diff --git a/.docker/frankenphp/Caddyfile b/.docker/frankenphp/Caddyfile new file mode 100644 index 00000000..83839304 --- /dev/null +++ b/.docker/frankenphp/Caddyfile @@ -0,0 +1,55 @@ +{ + {$CADDY_GLOBAL_OPTIONS} + + frankenphp { + {$FRANKENPHP_CONFIG} + } + + # https://caddyserver.com/docs/caddyfile/directives#sorting-algorithm + order mercure after encode + order vulcain after reverse_proxy + order php_server before file_server +} + +{$CADDY_EXTRA_CONFIG} + +{$SERVER_NAME:localhost} { + log { + # Redact the authorization query parameter that can be set by Mercure + format filter { + wrap console + fields { + uri query { + replace authorization REDACTED + } + } + } + } + + root * /app/public + encode zstd br gzip + + mercure { + # Transport to use (default to Bolt) + transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db} + # Publisher JWT key + publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG} + # Subscriber JWT key + subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG} + # Allow anonymous subscribers (double-check that it's what you want) + anonymous + # Enable the subscription API (double-check that it's what you want) + subscriptions + # Extra directives + {$MERCURE_EXTRA_DIRECTIVES} + } + + vulcain + + {$CADDY_SERVER_EXTRA_DIRECTIVES} + + # Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics + header ?Permissions-Policy "browsing-topics=()" + + php_server +} diff --git a/.docker/frankenphp/conf.d/app.dev.ini b/.docker/frankenphp/conf.d/app.dev.ini new file mode 100644 index 00000000..e50f43d0 --- /dev/null +++ b/.docker/frankenphp/conf.d/app.dev.ini @@ -0,0 +1,5 @@ +; See https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host +; See https://github.com/docker/for-linux/issues/264 +; The `client_host` below may optionally be replaced with `discover_client_host=yes` +; Add `start_with_request=yes` to start debug session on each request +xdebug.client_host = host.docker.internal diff --git a/.docker/frankenphp/conf.d/app.ini b/.docker/frankenphp/conf.d/app.ini new file mode 100644 index 00000000..10a062f2 --- /dev/null +++ b/.docker/frankenphp/conf.d/app.ini @@ -0,0 +1,18 @@ +expose_php = 0 +date.timezone = UTC +apc.enable_cli = 1 +session.use_strict_mode = 1 +zend.detect_unicode = 0 + +; https://symfony.com/doc/current/performance.html +realpath_cache_size = 4096K +realpath_cache_ttl = 600 +opcache.interned_strings_buffer = 16 +opcache.max_accelerated_files = 20000 +opcache.memory_consumption = 256 +opcache.enable_file_override = 1 + +memory_limit = 256M + +upload_max_filesize=256M +post_max_size=300M \ No newline at end of file diff --git a/.docker/frankenphp/conf.d/app.prod.ini b/.docker/frankenphp/conf.d/app.prod.ini new file mode 100644 index 00000000..3bcaa71e --- /dev/null +++ b/.docker/frankenphp/conf.d/app.prod.ini @@ -0,0 +1,2 @@ +opcache.preload_user = root +opcache.preload = /app/config/preload.php diff --git a/.docker/frankenphp/docker-entrypoint.sh b/.docker/frankenphp/docker-entrypoint.sh new file mode 100644 index 00000000..1655af5a --- /dev/null +++ b/.docker/frankenphp/docker-entrypoint.sh @@ -0,0 +1,60 @@ +#!/bin/sh +set -e + +if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then + # Install the project the first time PHP is started + # After the installation, the following block can be deleted + if [ ! -f composer.json ]; then + rm -Rf tmp/ + composer create-project "symfony/skeleton $SYMFONY_VERSION" tmp --stability="$STABILITY" --prefer-dist --no-progress --no-interaction --no-install + + cd tmp + cp -Rp . .. + cd - + rm -Rf tmp/ + + composer require "php:>=$PHP_VERSION" runtime/frankenphp-symfony + composer config --json extra.symfony.docker 'true' + + if grep -q ^DATABASE_URL= .env; then + echo "To finish the installation please press Ctrl+C to stop Docker Compose and run: docker compose up --build -d --wait" + sleep infinity + fi + fi + + if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then + composer install --prefer-dist --no-progress --no-interaction + fi + + if grep -q ^DATABASE_URL= .env; then + echo "Waiting for database to be ready..." + ATTEMPTS_LEFT_TO_REACH_DATABASE=60 + until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(php bin/console dbal:run-sql -q "SELECT 1" 2>&1); do + if [ $? -eq 255 ]; then + # If the Doctrine command exits with 255, an unrecoverable error occurred + ATTEMPTS_LEFT_TO_REACH_DATABASE=0 + break + fi + sleep 1 + ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE - 1)) + echo "Still waiting for database to be ready... Or maybe the database is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left." + done + + if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then + echo "The database is not up or not reachable:" + echo "$DATABASE_ERROR" + exit 1 + else + echo "The database is now ready and reachable" + fi + + if [ "$( find ./migrations -iname '*.php' -print -quit )" ]; then + php bin/console doctrine:migrations:migrate --no-interaction + fi + fi + + setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var + setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var +fi + +exec docker-php-entrypoint "$@" \ No newline at end of file diff --git a/.docker/frankenphp/worker.Caddyfile b/.docker/frankenphp/worker.Caddyfile new file mode 100644 index 00000000..d384ae4c --- /dev/null +++ b/.docker/frankenphp/worker.Caddyfile @@ -0,0 +1,4 @@ +worker { + file ./public/index.php + env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime +} diff --git a/.docker/partdb-entrypoint.sh b/.docker/partdb-entrypoint.sh index 3e06256a..ffd2b24a 100644 --- a/.docker/partdb-entrypoint.sh +++ b/.docker/partdb-entrypoint.sh @@ -39,8 +39,50 @@ if [ -d /var/www/html/var/db ]; then fi fi -# Start PHP-FPM -service php8.1-fpm start +# Start PHP-FPM (the PHP_VERSION is replaced by the configured version in the Dockerfile) +service phpPHP_VERSION-fpm start + + +# Run migrations if automigration is enabled via env variable DB_AUTOMIGRATE +if [ "$DB_AUTOMIGRATE" = "true" ]; then + echo "Waiting for database to be ready..." + ATTEMPTS_LEFT_TO_REACH_DATABASE=60 + until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(sudo -E -u www-data php bin/console dbal:run-sql -q "SELECT 1" 2>&1); do + if [ $? -eq 255 ]; then + # If the Doctrine command exits with 255, an unrecoverable error occurred + ATTEMPTS_LEFT_TO_REACH_DATABASE=0 + break + fi + sleep 1 + ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE - 1)) + echo "Still waiting for database to be ready... Or maybe the database is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left." + done + + if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then + echo "The database is not up or not reachable:" + echo "$DATABASE_ERROR" + exit 1 + else + echo "The database is now ready and reachable" + fi + + # Check if there are any available migrations to do, by executing doctrine:migrations:up-to-date + # and checking if the exit code is 0 (up to date) or 1 (not up to date) + if sudo -E -u www-data php bin/console doctrine:migrations:up-to-date --no-interaction; then + echo "Database is up to date, no migrations necessary." + else + echo "Migrations available..." + echo "Do backup of database..." + + sudo -E -u www-data mkdir -p /var/www/html/uploads/.automigration-backup/ + # Backup the database + sudo -E -u www-data php bin/console partdb:backup -n --database /var/www/html/uploads/.automigration-backup/backup-$(date +%Y-%m-%d_%H-%M-%S).zip + + # Check if there are any migration files + sudo -E -u www-data php bin/console doctrine:migrations:migrate --no-interaction + fi + +fi # first arg is `-f` or `--some-option` (taken from https://github.com/docker-library/php/blob/master/8.2/bullseye/apache/docker-php-entrypoint) if [ "${1#-}" != "$1" ]; then diff --git a/.docker/symfony.conf b/.docker/symfony.conf index 8866bcc3..b5229bf6 100644 --- a/.docker/symfony.conf +++ b/.docker/symfony.conf @@ -25,21 +25,28 @@ CustomLog ${APACHE_LOG_DIR}/access.log combined # Pass the configuration from the docker env to the PHP environment (here you should list all .env options) - PassEnv APP_ENV APP_DEBUG APP_SECRET + PassEnv APP_ENV APP_DEBUG APP_SECRET REDIRECT_TO_HTTPS DISABLE_YEAR2038_BUG_CHECK PassEnv TRUSTED_PROXIES TRUSTED_HOSTS LOCK_DSN - PassEnv DATABASE_URL ENFORCE_CHANGE_COMMENTS_FOR - PassEnv DEFAULT_LANG DEFAULT_TIMEZONE BASE_CURRENCY INSTANCE_NAME ALLOW_ATTACHMENT_DOWNLOADS USE_GRAVATAR MAX_ATTACHMENT_FILE_SIZE DEFAULT_URI + PassEnv DATABASE_URL ENFORCE_CHANGE_COMMENTS_FOR DATABASE_MYSQL_USE_SSL_CA DATABASE_MYSQL_SSL_VERIFY_CERT + PassEnv DEFAULT_LANG DEFAULT_TIMEZONE BASE_CURRENCY INSTANCE_NAME ALLOW_ATTACHMENT_DOWNLOADS USE_GRAVATAR MAX_ATTACHMENT_FILE_SIZE DEFAULT_URI CHECK_FOR_UPDATES ATTACHMENT_DOWNLOAD_BY_DEFAULT PassEnv MAILER_DSN ALLOW_EMAIL_PW_RESET EMAIL_SENDER_EMAIL EMAIL_SENDER_NAME PassEnv HISTORY_SAVE_CHANGED_FIELDS HISTORY_SAVE_CHANGED_DATA HISTORY_SAVE_REMOVED_DATA HISTORY_SAVE_NEW_DATA PassEnv ERROR_PAGE_ADMIN_EMAIL ERROR_PAGE_SHOW_HELP PassEnv DEMO_MODE NO_URL_REWRITE_AVAILABLE FIXER_API_KEY BANNER - PassEnv SAML_ENABLED SAML_ROLE_MAPPING SAML_UPDATE_GROUP_ON_LOGIN SAML_IDP_ENTITY_ID SAML_IDP_SINGLE_SIGN_ON_SERVICE SAML_IDP_SINGLE_LOGOUT_SERVICE SAML_IDP_X509_CERT SAML_SP_ENTITY_ID SAML_SP_X509_CERT SAMLP_SP_PRIVATE_KEY - PassEnv TABLE_DEFAULT_PAGE_SIZE + # In old version the SAML sp private key env, was wrongly named SAMLP_SP_PRIVATE_KEY, keep it for backward compatibility + PassEnv SAML_ENABLED SAML_BEHIND_PROXY SAML_ROLE_MAPPING SAML_UPDATE_GROUP_ON_LOGIN SAML_IDP_ENTITY_ID SAML_IDP_SINGLE_SIGN_ON_SERVICE SAML_IDP_SINGLE_LOGOUT_SERVICE SAML_IDP_X509_CERT SAML_SP_ENTITY_ID SAML_SP_X509_CERT SAML_SP_PRIVATE_KEY SAMLP_SP_PRIVATE_KEY + PassEnv TABLE_DEFAULT_PAGE_SIZE TABLE_PARTS_DEFAULT_COLUMNS PassEnv PROVIDER_DIGIKEY_CLIENT_ID PROVIDER_DIGIKEY_SECRET PROVIDER_DIGIKEY_CURRENCY PROVIDER_DIGIKEY_LANGUAGE PROVIDER_DIGIKEY_COUNTRY PassEnv PROVIDER_ELEMENT14_KEY PROVIDER_ELEMENT14_STORE_ID PassEnv PROVIDER_TME_KEY PROVIDER_TME_SECRET PROVIDER_TME_CURRENCY PROVIDER_TME_LANGUAGE PROVIDER_TME_COUNTRY PROVIDER_TME_GET_GROSS_PRICES PassEnv PROVIDER_OCTOPART_CLIENT_ID PROVIDER_OCTOPART_SECRET PROVIDER_OCTOPART_CURRENCY PROVIDER_OCTOPART_COUNTRY PROVIDER_OCTOPART_SEARCH_LIMIT PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS + PassEnv PROVIDER_MOUSER_KEY PROVIDER_MOUSER_SEARCH_OPTION PROVIDER_MOUSER_SEARCH_LIMIT PROVIDER_MOUSER_SEARCH_WITH_SIGNUP_LANGUAGE + PassEnv PROVIDER_LCSC_ENABLED PROVIDER_LCSC_CURRENCY + PassEnv PROVIDER_OEMSECRETS_KEY PROVIDER_OEMSECRETS_COUNTRY_CODE PROVIDER_OEMSECRETS_CURRENCY PROVIDER_OEMSECRETS_ZERO_PRICE PROVIDER_OEMSECRETS_SET_PARAM PROVIDER_OEMSECRETS_SORT_CRITERIA + PassEnv PROVIDER_REICHELT_ENABLED PROVIDER_REICHELT_CURRENCY PROVIDER_REICHELT_COUNTRY PROVIDER_REICHELT_LANGUAGE PROVIDER_REICHELT_INCLUDE_VAT + PassEnv PROVIDER_POLLIN_ENABLED + PassEnv EDA_KICAD_CATEGORY_DEPTH # For most configuration files from conf-available/, which are # enabled or disabled at a global level, it is possible to diff --git a/.dockerignore b/.dockerignore index 8929729c..472b1bb3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,6 +5,8 @@ tests/ docs/ .git +/public/media/* + ###> symfony/framework-bundle ### /.env.local /.env.local.php @@ -42,3 +44,39 @@ yarn-error.log /phpunit.xml .phpunit.result.cache ###< phpunit/phpunit ### + + +### From frankenphp + +**/*.log +**/*.php~ +**/*.dist.php +**/*.dist +**/*.cache +**/._* +**/.dockerignore +**/.DS_Store +**/.git/ +**/.gitattributes +**/.gitignore +**/.gitmodules +**/compose.*.yaml +**/compose.*.yml +**/compose.yaml +**/compose.yml +**/docker-compose.*.yaml +**/docker-compose.*.yml +**/docker-compose.yaml +**/docker-compose.yml +**/Dockerfile +**/Thumbs.db +.github/ +public/bundles/ +var/ +vendor/ +.editorconfig +.env.*.local +.env.local +.env.local.php +.env.test + diff --git a/.env b/.env index cb57a3bb..1806e9c6 100644 --- a/.env +++ b/.env @@ -14,6 +14,19 @@ DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db" # Uncomment this line (and comment the line above to use a MySQL database #DATABASE_URL=mysql://root:@127.0.0.1:3306/part-db?serverVersion=5.7 +# Set this value to 1, if you want to use SSL to connect to the MySQL server. It will be tried to use the CA certificate +# otherwise a CA bundle shipped with PHP will be used. +# Leave it at 0, if you do not want to use SSL or if your server does not support it +DATABASE_MYSQL_USE_SSL_CA=0 + +# Set this value to 0, if you don't want to verify the CA certificate of the MySQL server +# Only do this, if you know what you are doing! +DATABASE_MYSQL_SSL_VERIFY_CERT=1 + +# Emulate natural sorting of strings even on databases that do not support it (like SQLite, MySQL or MariaDB < 10.7) +# This can be slow on big databases and might have some problems and quirks, so use it with caution +DATABASE_EMULATE_NATURAL_SORT=0 + ################################################################################### # General settings ################################################################################### @@ -29,13 +42,15 @@ INSTANCE_NAME="Part-DB" # Allow users to download attachments to the server by providing an URL # This could be a potential security issue, as the user can retrieve any file the server has access to (via internet) ALLOW_ATTACHMENT_DOWNLOADS=0 +# Set this to 1, if the "download external files" checkbox should be checked by default for new attachments +ATTACHMENT_DOWNLOAD_BY_DEFAULT=0 # Use gravatars for user avatars, when user has no own avatar defined USE_GRAVATAR=0 # The maximum allowed size for attachment files in bytes (you can use M for megabytes and G for gigabytes) # Please note that the php.ini setting upload_max_filesize also limits the maximum size of uploaded files MAX_ATTACHMENT_FILE_SIZE="100M" -# The public reachable URL of this Part-DB installation. This is used for generating links to the website in emails and so on +# The public reachable URL of this Part-DB installation. This is used for generating links in SAML and email templates # This must end with a slash! DEFAULT_URI="https://partdb.changeme.invalid/" @@ -44,6 +59,9 @@ DEFAULT_URI="https://partdb.changeme.invalid/" # Leave this empty, to make all change reasons optional ENFORCE_CHANGE_COMMENTS_FOR="" +# Disable that if you do not want that Part-DB connects to GitHub to check for available updates, or if your server can not connect to the internet +CHECK_FOR_UPDATES=1 + ################################################################################### # Email settings ################################################################################### @@ -90,6 +108,9 @@ ERROR_PAGE_SHOW_HELP=1 # The default page size for the part table (set to -1 to show all parts on one page) TABLE_DEFAULT_PAGE_SIZE=50 +# Configure which columns will be visible by default in the parts table (and in which order). +# This is a comma separated list of column names. See documentation for available values. +TABLE_PARTS_DEFAULT_COLUMNS=name,description,category,footprint,manufacturer,storage_location,amount ################################################################################## # Info provider settings @@ -122,7 +143,8 @@ PROVIDER_TME_CURRENCY=EUR PROVIDER_TME_LANGUAGE=en # The country to get results for PROVIDER_TME_COUNTRY=DE -# Set this to 1 to get gross prices (including VAT) instead of net prices +# [DEPRECATED] Set this to 1 to get gross prices (including VAT) instead of net prices +# With private API keys, this option cannot be used anymore is ignored by Part-DB. The VAT inclusion depends on your TME account settings. PROVIDER_TME_GET_GROSS_PRICES=1 # Octopart / Nexar Provider: @@ -139,13 +161,101 @@ PROVIDER_OCTOPART_SEARCH_LIMIT=10 # Set to false to include non authorized offers in the results PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS=1 +# Mouser Provider API V2: +# You can get your API key from https://www.mouser.it/api-hub/ +PROVIDER_MOUSER_KEY= +# Filter search results by RoHS compliance and stock availability: +# Available options: None | Rohs | InStock | RohsAndInStock +PROVIDER_MOUSER_SEARCH_OPTION='None' +# The number of results to get from Mouser while searching (please note that this value is max 50) +PROVIDER_MOUSER_SEARCH_LIMIT=50 +# It is recommended to leave this set to 'true'. The option is not really good doumented by Mouser: +# Used when searching for keywords in the language specified when you signed up for Search API. +PROVIDER_MOUSER_SEARCH_WITH_SIGNUP_LANGUAGE='true' + +# LCSC Provider: +# LCSC does not provide an offical API, so this used the API LCSC uses to render their webshop. +# LCSC did not intended the use of this API and it could break any time, so use it at your own risk. + +# We dont require an API key for LCSC, just set this to 1 to enable LCSC support +PROVIDER_LCSC_ENABLED=0 +# The currency to get prices in (e.g. EUR, USD, etc.) +PROVIDER_LCSC_CURRENCY=EUR + +# Oemsecrets Provider API 3.0.1: +# You can get your API key from https://www.oemsecrets.com/api +PROVIDER_OEMSECRETS_KEY= +# The country you want the output for +PROVIDER_OEMSECRETS_COUNTRY_CODE=DE +# Available country code are: +# AD, AE, AQ, AR, AT, AU, BE, BO, BR, BV, BY, CA, CH, CL, CN, CO, CZ, DE, DK, EC, EE, EH, +# ES, FI, FK, FO, FR, GB, GE, GF, GG, GI, GL, GR, GS, GY, HK, HM, HR, HU, IE, IM, IN, IS, +# IT, JM, JP, KP, KR, KZ, LI, LK, LT, LU, MC, MD, ME, MK, MT, NL, NO, NZ, PE, PH, PL, PT, +# PY, RO, RS, RU, SB, SD, SE, SG, SI, SJ, SK, SM, SO, SR, SY, SZ, TC, TF, TG, TH, TJ, TK, +# TM, TN, TO, TR, TT, TV, TW, TZ, UA, UG, UM, US, UY, UZ, VA, VE, VG, VI, VN, VU, WF, YE, +# ZA, ZM, ZW +# +# The currency you want the prices to be displayed in +PROVIDER_OEMSECRETS_CURRENCY=EUR +# Available currency are:AUD, CAD, CHF, CNY, DKK, EUR, GBP, HKD, ILS, INR, JPY, KRW, NOK, +# NZD, RUB, SEK, SGD, TWD, USD +# +# If PROVIDER_OEMSECRETS_ZERO_PRICE is set to 0, distributors with zero prices +# will be discarded from the creation of a new part (set to 1 otherwise) +PROVIDER_OEMSECRETS_ZERO_PRICE=0 +# +# When PROVIDER_OEMSECRETS_SET_PARAM is set to 1 the parameters for the part are generated +# from the description transforming unstructured descriptions into structured parameters; +# each parameter in description should have the form: "...;name1:value1;name2:value2" +PROVIDER_OEMSECRETS_SET_PARAM=1 +# +# This environment variable determines the sorting criteria for product results. +# The sorting process first arranges items based on the provided keyword. +# Then, if set to 'C', it further sorts by completeness (prioritizing items with the most +# detailed information). If set to 'M', it further sorts by manufacturer name. +#If unset or set to any other value, no sorting is performed. +PROVIDER_OEMSECRETS_SORT_CRITERIA=C + + +# Reichelt provider: +# Reichelt.com offers no official API, so this info provider webscrapes the website to extract info +# It could break at any time, use it at your own risk +# We dont require an API key for Reichelt, just set this to 1 to enable Reichelt support +PROVIDER_REICHELT_ENABLED=0 +# The country to get prices for +PROVIDER_REICHELT_COUNTRY=DE +# The language to get results in (en, de, fr, nl, pl, it, es) +PROVIDER_REICHELT_LANGUAGE=en +# Include VAT in prices (set to 1 to include VAT, 0 to exclude VAT) +PROVIDER_REICHELT_INCLUDE_VAT=1 +# The currency to get prices in (only for countries with countries other than EUR) +PROVIDER_REICHELT_CURRENCY=EUR + +# Pollin provider: +# Pollin.de offers no official API, so this info provider webscrapes the website to extract info +# It could break at any time, use it at your own risk +# We dont require an API key for Pollin, just set this to 1 to enable Pollin support +PROVIDER_POLLIN_ENABLED=0 + +################################################################################## +# EDA integration related settings +################################################################################## + +# This value determines the depth of the category tree, that is visible inside KiCad +# 0 means that only the top level categories are visible. Set to a value > 0 to show more levels. +# Set to -1, to show all parts of Part-DB inside a single category in KiCad +EDA_KICAD_CATEGORY_DEPTH=0 ################################################################################### # SAML Single sign on-settings ################################################################################### # Set this to 1 to enable SAML single sign on +# Be also sure to set the correct values for DEFAULT_URI SAML_ENABLED=0 +# Set to 1, if your Part-DB installation is behind a reverse proxy and you want to use SAML +SAML_BEHIND_PROXY=0 + # A JSON encoded array of role mappings in the form { "saml_role": PARTDB_GROUP_ID, "*": PARTDB_GROUP_ID } # The first match is used, so the order is important! Put the group mapping with the most privileges first. # Please not to only use single quotes to enclose the JSON string @@ -172,7 +282,7 @@ SAML_SP_ENTITY_ID="https://partdb.changeme.invalid/sp" # The public certificate of the SAML SP SAML_SP_X509_CERT="MIIC..." # The private key of the SAML SP -SAMLP_SP_PRIVATE_KEY="MIIE..." +SAML_SP_PRIVATE_KEY="MIIE..." ###################################################################################### @@ -185,6 +295,9 @@ DEMO_MODE=0 # In that case all URL contains the index.php front controller in URL NO_URL_REWRITE_AVAILABLE=0 +# Set to 1, if Part-DB should redirect all HTTP requests to HTTPS. You dont need to configure this, if your webserver already does this. +REDIRECT_TO_HTTPS=0 + # If you want to use fixer.io for currency conversion, you have to set this to your API key FIXER_API_KEY=CHANGEME @@ -195,9 +308,11 @@ BANNER="" APP_ENV=prod APP_SECRET=a03498528f5a5fc089273ec9ae5b2849 +# Set this to zero, if you want to disable the year 2038 bug check on 32-bit systems (it will cause errors with current 32-bit PHP versions) +DISABLE_YEAR2038_BUG_CHECK=0 # Set the trusted IPs here, when using an reverse proxy -#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 +#TRUSTED_PROXIES=127.0.0.0/8,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 #TRUSTED_HOSTS='^(localhost|example\.com)$' @@ -206,3 +321,7 @@ APP_SECRET=a03498528f5a5fc089273ec9ae5b2849 # postgresql+advisory://db_user:db_password@localhost/db_name LOCK_DSN=flock ###< symfony/lock ### + +###> nelmio/cors-bundle ### +CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' +###< nelmio/cors-bundle ### diff --git a/.env.dev b/.env.dev new file mode 100644 index 00000000..e69de29b diff --git a/.env.test b/.env.test index a9b0cccf..3dbece81 100644 --- a/.env.test +++ b/.env.test @@ -5,5 +5,9 @@ SYMFONY_DEPRECATIONS_HELPER=999999 PANTHER_APP_ENV=panther PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots +DATABASE_URL="sqlite:///%kernel.project_dir%/var/app_test.db" # Doctrine automatically adds an _test suffix to database name in test env -DATABASE_URL=mysql://root:@127.0.0.1:3306/part-db \ No newline at end of file +#DATABASE_URL=mysql://root:@127.0.0.1:3306/part-db + +# Disable update checks, as tests would fail, when github is not reachable +CHECK_FOR_UPDATES=0 \ No newline at end of file diff --git a/.github/workflows/assets_artifact_build.yml b/.github/workflows/assets_artifact_build.yml index 0c3c1568..0bbfe432 100644 --- a/.github/workflows/assets_artifact_build.yml +++ b/.github/workflows/assets_artifact_build.yml @@ -19,14 +19,22 @@ jobs: APP_ENV: prod steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + ini-values: xdebug.max_nesting_level=1000 + extensions: mbstring, intl, gd, xsl, gmp, bcmath, :php-psr - name: Get Composer Cache Directory id: composer-cache run: | echo "::set-output name=dir::$(composer config cache-files-dir)" - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -40,7 +48,7 @@ jobs: id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} @@ -49,7 +57,7 @@ jobs: ${{ runner.os }}-yarn- - name: Setup node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '18' @@ -69,13 +77,13 @@ jobs: run: zip -r /tmp/partdb_assets.zip public/build/ vendor/ - name: Upload assets artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Only dependencies and built assets path: /tmp/partdb_assets.zip - name: Upload full artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Full Part-DB including dependencies and built assets path: /tmp/partdb_with_assets.zip diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 79d01893..64287d83 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -17,11 +17,11 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Docker meta id: docker_meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: # list of Docker images to use as base name for tags images: | @@ -49,23 +49,23 @@ jobs: - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 with: platforms: 'arm64,arm' - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64,linux/arm64,linux/arm/v7 diff --git a/.github/workflows/docker_frankenphp.yml b/.github/workflows/docker_frankenphp.yml new file mode 100644 index 00000000..d8cd0695 --- /dev/null +++ b/.github/workflows/docker_frankenphp.yml @@ -0,0 +1,77 @@ +name: Docker Image Build (FrankenPHP) + +on: + #schedule: + # - cron: '0 10 * * *' # everyday at 10am + push: + branches: + - '**' + - '!l10n_**' + tags: + - 'v*.*.*' + - 'v*.*.*-**' + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v4 + - + name: Docker meta + id: docker_meta + uses: docker/metadata-action@v5 + with: + # list of Docker images to use as base name for tags + images: | + partdborg/part-db + # Mark the image build from master as latest (as we dont have really releases yet) + tags: | + type=edge,branch=master + type=ref,event=branch, + type=ref,event=tag, + type=schedule + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=ref,event=branch + type=ref,event=pr + labels: | + org.opencontainers.image.source=${{ github.event.repository.clone_url }} + org.opencontainers.image.revision=${{ github.sha }} + org.opencontainers.image.title=Part-DB + org.opencontainers.image.description=Part-DB is a web application for managing electronic components and your inventory. + org.opencontainers.image.url=https://github.com/Part-DB/Part-DB-server + org.opencontainers.image.source=https://github.com/Part-DB/Part-DB-server + org.opencontainers.image.authors=Jan Böhmer + org.opencontainers.licenses=AGPL-3.0-or-later + + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: 'arm64,arm' + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - + name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile-frankenphp + platforms: linux/amd64,linux/arm64,linux/arm/v7 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.docker_meta.outputs.tags }} + labels: ${{ steps.docker_meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max \ No newline at end of file diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 41ff1a56..20150b28 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -16,14 +16,22 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + ini-values: xdebug.max_nesting_level=1000 + extensions: mbstring, intl, gd, xsl, gmp, bcmath, :php-psr - name: Get Composer Cache Directory id: composer-cache run: | echo "::set-output name=dir::$(composer config cache-files-dir)" - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -48,9 +56,10 @@ jobs: - name: Check doctrine mapping run: ./bin/console doctrine:schema:validate --skip-sync -vvv --no-interaction - + + # Use the -d option to raise the max nesting level - name: Generate dev container - run: ./bin/console cache:clear --env dev + run: php -d xdebug.max_nesting_level=1000 ./bin/console cache:clear --env dev - name: Run PHPstan run: composer phpstan diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 99955059..8e6ea54c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,13 +13,13 @@ on: jobs: phpunit: name: PHPUnit and coverage Test (PHP ${{ matrix.php-versions }}, ${{ matrix.db-type }}) - # Ubuntu 20.04 ships MySQL 8.0 which causes problems with login, so we just use ubuntu 18.04 for now... runs-on: ubuntu-22.04 strategy: + fail-fast: false matrix: - php-versions: [ '8.1', '8.2' ] - db-type: [ 'mysql', 'sqlite' ] + php-versions: [ '8.1', '8.2', '8.3', '8.4' ] + db-type: [ 'mysql', 'sqlite', 'postgres' ] env: # Note that we set DATABASE URL later based on our db-type matrix value @@ -27,30 +27,45 @@ jobs: SYMFONY_DEPRECATIONS_HELPER: disabled PHP_VERSION: ${{ matrix.php-versions }} DB_TYPE: ${{ matrix.db-type }} + CHECK_FOR_UPDATES: false # Disable update checks for tests steps: - name: Set Database env for MySQL - run: echo "DATABASE_URL=mysql://root:root@127.0.0.1:3306/test" >> $GITHUB_ENV + run: echo "DATABASE_URL=mysql://root:root@127.0.0.1:3306/partdb?serverVersion=8.0.35" >> $GITHUB_ENV if: matrix.db-type == 'mysql' - name: Set Database env for SQLite run: echo "DATABASE_URL="sqlite:///%kernel.project_dir%/var/app_test.db"" >> $GITHUB_ENV if: matrix.db-type == 'sqlite' + - name: Set Database env for PostgreSQL + run: echo "DATABASE_URL=postgresql://postgres:postgres @127.0.0.1:5432/partdb?serverVersion=14&charset=utf8" >> $GITHUB_ENV + if: matrix.db-type == 'postgres' + - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-versions }} coverage: pcov - extensions: mbstring, intl, gd, xsl, gmp, bcmath + ini-values: xdebug.max_nesting_level=1000 + extensions: mbstring, intl, gd, xsl, gmp, bcmath, :php-psr - name: Start MySQL run: sudo systemctl start mysql.service + if: matrix.db-type == 'mysql' - #- name: Setup MySQL + # Replace the scram-sha-256 with trust for host connections, to avoid password authentication + - name: Start PostgreSQL + run: | + sudo sed -i 's/^\(host.*all.*all.*\)scram-sha-256/\1trust/' /etc/postgresql/14/main/pg_hba.conf + sudo systemctl start postgresql.service + sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'postgres';" + if: matrix.db-type == 'postgres' + + #- name: Setup MySQL # uses: mirromutth/mysql-action@v1.1 # with: # mysql version: 5.7 @@ -63,7 +78,7 @@ jobs: id: composer-cache run: | echo "::set-output name=dir::$(composer config cache-files-dir)" - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -74,7 +89,7 @@ jobs: id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - - uses: actions/cache@v3 + - uses: actions/cache@v4 id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} @@ -86,7 +101,7 @@ jobs: run: composer install --prefer-dist --no-progress - name: Setup node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: '18' @@ -98,26 +113,24 @@ jobs: - name: Create DB run: php bin/console --env test doctrine:database:create --if-not-exists -n - if: matrix.db-type == 'mysql' - - # Checkinf for existance is not supported for sqlite, so do it without it - - name: Create DB - run: php bin/console --env test doctrine:database:create -n - if: matrix.db-type == 'sqlite' + if: matrix.db-type == 'mysql' || matrix.db-type == 'postgres' - name: Do migrations run: php bin/console --env test doctrine:migrations:migrate -n - + + # Use our own custom fixtures loading command to circumvent some problems with reset the autoincrement values - name: Load fixtures - run: php bin/console --env test doctrine:fixtures:load -n + run: php bin/console --env test partdb:fixtures:load -n - name: Run PHPunit and generate coverage run: ./bin/phpunit --coverage-clover=coverage.xml - name: Upload coverage - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v5 with: env_vars: PHP_VERSION,DB_TYPE + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true - name: Test app:clean-attachments run: php bin/console partdb:attachments:clean-unused -n @@ -131,11 +144,11 @@ jobs: - name: Test check-requirements command run: php bin/console partdb:check-requirements -n + - name: Test partdb:backup command + run: php bin/console partdb:backup -n --full /tmp/test_backup.zip + - name: Test legacy Part-DB import run: bash .github/assets/legacy_import/test_legacy_import.sh if: matrix.db-type == 'mysql' && matrix.php-versions == '8.2' env: DATABASE_URL: mysql://root:root@localhost:3306/legacy_db - - - diff --git a/.gitignore b/.gitignore index 1d28a771..b726f64c 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,7 @@ yarn-error.log /phpunit.xml .phpunit.result.cache ###< phpunit/phpunit ### + +###> phpstan/phpstan ### +phpstan.neon +###< phpstan/phpstan ### diff --git a/Dockerfile b/Dockerfile index 4a9048ba..0f909f16 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,64 @@ -FROM debian:bullseye-slim +ARG BASE_IMAGE=debian:bookworm-slim +ARG PHP_VERSION=8.3 + +FROM ${BASE_IMAGE} AS base +ARG PHP_VERSION # Install needed dependencies for PHP build #RUN apt-get update && apt-get install -y pkg-config curl libcurl4-openssl-dev libicu-dev \ # libpng-dev libjpeg-dev libfreetype6-dev gnupg zip libzip-dev libjpeg62-turbo-dev libonig-dev libxslt-dev libwebp-dev vim \ # && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/* -RUN apt-get update && apt-get -y install apt-transport-https lsb-release ca-certificates curl zip \ +RUN apt-get update && apt-get -y install \ + apt-transport-https \ + lsb-release \ + ca-certificates \ + curl \ + zip \ + mariadb-client \ + postgresql-client \ && curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg \ && sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list' \ && apt-get update && apt-get upgrade -y \ - && apt-get install -y apache2 php8.1 php8.1-fpm php8.1-opcache php8.1-curl php8.1-gd php8.1-mbstring php8.1-xml php8.1-bcmath php8.1-intl php8.1-zip php8.1-xsl php8.1-sqlite3 php8.1-mysql gpg \ - && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/*; - -ENV APACHE_CONFDIR /etc/apache2 -ENV APACHE_ENVVARS $APACHE_CONFDIR/envvars - + && apt-get install -y \ + apache2 \ + php${PHP_VERSION} \ + php${PHP_VERSION}-fpm \ + php${PHP_VERSION}-opcache \ + php${PHP_VERSION}-curl \ + php${PHP_VERSION}-gd \ + php${PHP_VERSION}-mbstring \ + php${PHP_VERSION}-xml \ + php${PHP_VERSION}-bcmath \ + php${PHP_VERSION}-intl \ + php${PHP_VERSION}-zip \ + php${PHP_VERSION}-xsl \ + php${PHP_VERSION}-sqlite3 \ + php${PHP_VERSION}-mysql \ + php${PHP_VERSION}-pgsql \ + gpg \ + sudo \ + && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/* \ # Create workdir and set permissions if directory does not exists -RUN mkdir -p /var/www/html && chown -R www-data:www-data /var/www/html + && mkdir -p /var/www/html \ + && chown -R www-data:www-data /var/www/html \ +# delete the "index.html" that installing Apache drops in here + && rm -rvf /var/www/html/* + +# Install node and yarn +RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ + echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ + curl -sL https://deb.nodesource.com/setup_20.x | bash - && \ + apt-get update && apt-get install -y \ + nodejs \ + yarn \ + && apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/* + +# Install composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +ENV APACHE_CONFDIR=/etc/apache2 +ENV APACHE_ENVVARS=$APACHE_CONFDIR/envvars # Configure apache 2 (taken from https://github.com/docker-library/php/blob/master/8.2/bullseye/apache/Dockerfile) # generically convert lines like @@ -27,8 +69,6 @@ RUN mkdir -p /var/www/html && chown -R www-data:www-data /var/www/html # so that they can be overridden at runtime ("-e APACHE_RUN_USER=...") RUN sed -ri 's/^export ([^=]+)=(.*)$/: ${\1:=\2}\nexport \1/' "$APACHE_ENVVARS"; \ set -eux; . "$APACHE_ENVVARS"; \ - # delete the "index.html" that installing Apache drops in here - rm -rvf /var/www/html/*; \ \ # logs should go to stdout / stderr ln -sfT /dev/stderr "$APACHE_LOG_DIR/error.log"; \ @@ -36,82 +76,87 @@ RUN sed -ri 's/^export ([^=]+)=(.*)$/: ${\1:=\2}\nexport \1/' "$APACHE_ENVVARS" ln -sfT /dev/stdout "$APACHE_LOG_DIR/other_vhosts_access.log"; \ chown -R --no-dereference "$APACHE_RUN_USER:$APACHE_RUN_GROUP" "$APACHE_LOG_DIR"; -# Enable php-fpm -RUN a2enmod proxy_fcgi setenvif && a2enconf php8.1-fpm +# --- +FROM scratch AS apache-config +ARG PHP_VERSION # Configure php-fpm to log to stdout of the container (stdout of PID 1) # We have to use /proc/1/fd/1 because /dev/stdout or /proc/self/fd/1 does not point to the container stdout (because we use apache as entrypoint) # We also disable the clear_env option to allow the use of environment variables in php-fpm -RUN { \ - echo '[global]'; \ - echo 'error_log = /proc/1/fd/1'; \ - echo; \ - echo '[www]'; \ - echo 'access.log = /proc/1/fd/1'; \ - echo 'catch_workers_output = yes'; \ - echo 'decorate_workers_output = no'; \ - echo 'clear_env = no'; \ - } | tee "/etc/php/8.1/fpm/pool.d/zz-docker.conf" +COPY <'; \ - echo '\tSetHandler application/x-httpd-php'; \ - echo ''; \ - echo; \ - echo 'DirectoryIndex disabled'; \ - echo 'DirectoryIndex index.php index.html'; \ - echo; \ - echo ''; \ - echo '\tOptions -Indexes'; \ - echo '\tAllowOverride All'; \ - echo ''; \ - } | tee "$APACHE_CONFDIR/conf-available/docker-php.conf" \ - && a2enconf docker-php +COPY < + SetHandler application/x-httpd-php + + +DirectoryIndex disabled +DirectoryIndex index.php index.html + + + Options -Indexes + AllowOverride All + +EOF # Enable opcache and configure it recommended for symfony (see https://symfony.com/doc/current/performance.html) -RUN \ - { \ - echo 'opcache.memory_consumption=256'; \ - echo 'opcache.max_accelerated_files=20000'; \ - echo 'opcache.validate_timestamp=0'; \ - # Configure Realpath cache for performance - echo 'realpath_cache_size=4096K'; \ - echo 'realpath_cache_ttl=600'; \ - } > /etc/php/8.1/fpm/conf.d/symfony-recommended.ini +COPY < /etc/php/8.1/fpm/conf.d/partdb.ini +COPY < ## Features -* Inventory management of your electronic parts. Each part can be assigned to a category, footprint, manufacturer -and multiple store locations and price information. Parts can be grouped using tags. You can associate various files like datasheets or pictures with the parts. -* Multi-Language support (currently German, English, Russian, Japanese and French (experimental)) + +* Inventory management of your electronic parts. Each part can be assigned to a category, footprint, manufacturer, + and multiple store locations and price information. Parts can be grouped using tags. You can associate various files + like datasheets or pictures with the parts. +* Multi-language support (currently German, English, Russian, Japanese, French, Czech, Danish, and Chinese) * Barcodes/Labels generator for parts and storage locations, scan barcodes via webcam using the builtin barcode scanner -* User system with groups and detailed (fine granular) permissions. -Two-factor authentication is supported (Google Authenticator and Webauthn/U2F keys) and can be enforced for groups. Password reset via email can be setuped. -* Optional support for single sign-on (SSO) via SAML (using an intermediate service like [Keycloak](https://www.keycloak.org/) you can connect Part-DB to an existing LDAP or Active Directory server) -* Import/Export system for parts and datastructure. BOM import for projects from KiCAD is supported. -* Project management: Create projects and assign parts to the bill of material (BOM), to show how often you could build this project and directly withdraw all components needed from DB -* Event log: Track what changes happens to your inventory, track which user does what. Revert your parts to older versions. -* Responsive design: You can use Part-DB on your PC, your tablet and your smartphone using the same interface. -* MySQL and SQLite supported as database backends +* User system with groups and detailed (fine granular) permissions. + Two-factor authentication is supported (Google Authenticator and Webauthn/U2F keys) and can be enforced for groups. + Password reset via email can be set up. +* Optional support for single sign-on (SSO) via SAML (using an intermediate service + like [Keycloak](https://www.keycloak.org/) you can connect Part-DB to an existing LDAP or Active Directory server) +* Import/Export system for parts and data structure. BOM import for projects from KiCAD is supported. +* Project management: Create projects and assign parts to the bill of material (BOM), to show how often you could build + this project and directly withdraw all components needed from DB +* Event log: Track what changes happen to your inventory, track which user does what. Revert your parts to older + versions. +* Responsive design: You can use Part-DB on your PC, your tablet, and your smartphone using the same interface. +* MySQL, SQLite and PostgreSQL are supported as database backends * Support for rich text descriptions and comments in parts * Support for multiple currencies and automatic update of exchange rates supported * Powerful search and filter function, including parametric search (search for parts according to some specifications) * Automatic thumbnail generation for pictures -* Use cloud providers (like Octopart, Digikey, farnell or TME) to automatically get part information, datasheets and prices for parts +* Use cloud providers (like Octopart, Digikey, Farnell, LCSC or TME) to automatically get part information, datasheets, and + prices for parts +* API to access Part-DB from other applications/scripts +* [Integration with KiCad](https://docs.part-db.de/usage/eda_integration.html): Use Part-DB as the central datasource for your + KiCad and see available parts from Part-DB directly inside KiCad. - -With these features Part-DB is useful to hobbyists, who want to keep track of their private electronic parts inventory, -or makerspaces, where many users have should have (controlled) access to the shared inventory. +With these features, Part-DB is useful to hobbyists, who want to keep track of their private electronic parts inventory, +or maker spaces, where many users should have (controlled) access to the shared inventory. Part-DB is also used by small companies and universities for managing their inventory. ## Requirements - * A **web server** (like Apache2 or nginx) that is capable of running [Symfony 5](https://symfony.com/doc/current/reference/requirements.html), - this includes a minimum PHP version of **PHP 8.1** - * A **MySQL** (at least 5.7) /**MariaDB** (at least 10.2.2) database server if you do not want to use SQLite. - * Shell access to your server is highly suggested! - * For building the client side assets **yarn** and **nodejs** (>= 18.0) is needed. - + +* A **web server** (like Apache2 or nginx) that is capable of + running [Symfony 6](https://symfony.com/doc/current/reference/requirements.html), + this includes a minimum PHP version of **PHP 8.1** +* A **MySQL** (at least 5.7) /**MariaDB** (at least 10.4) database server, or **PostgreSQL** 10+ if you do not want to use SQLite. +* Shell access to your server is highly recommended! +* For building the client-side assets **yarn** and **nodejs** (>= 18.0) is needed. + ## Installation -If you want to upgrade your legacy (< 1.0.0) version of Part-DB to this version, please read [this](https://docs.part-db.de/upgrade_legacy.html) first. -*Hint:* A docker image is available under [jbtronics/part-db1](https://hub.docker.com/r/jbtronics/part-db1). How to set up Part-DB via docker is described [here](https://docs.part-db.de/installation/installation_docker.html). +If you want to upgrade your legacy (< 1.0.0) version of Part-DB to this version, please +read [this](https://docs.part-db.de/upgrade_legacy.html) first. -**Below you find some very rough outline of the installation process, see [here](https://docs.part-db.de/installation/) for a detailed guide how to install Part-DB.** +*Hint:* A docker image is available under [jbtronics/part-db1](https://hub.docker.com/r/jbtronics/part-db1). How to set +up Part-DB via docker is described [here](https://docs.part-db.de/installation/installation_docker.html). + +**Below you find a very rough outline of the installation process, see [here](https://docs.part-db.de/installation/) +for a detailed guide on how to install Part-DB.** 1. Copy or clone this repository into a folder on your server. -2. Configure your webserver to serve from the `public/` folder. See [here](https://symfony.com/doc/current/setup/web_server_configuration.html) -for additional information. +2. Configure your webserver to serve from the `public/` folder. + See [here](https://symfony.com/doc/current/setup/web_server_configuration.html) + for additional information. 3. Copy the global config file `cp .env .env.local` and edit `.env.local`: * Change the line `APP_ENV=dev` to `APP_ENV=prod` - * If you do not want to use SQLite, change the value of `DATABASE_URL=` to your needs (see [here](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url)) for the format. - In bigger instances with concurrent accesses, MySQL is more performant. This can not be changed easily later, so choose wisely. + * If you do not want to use SQLite, change the value of `DATABASE_URL=` to your needs ( + see [here](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url)) + for the format. + In bigger instances with concurrent accesses, MySQL is more performant. This can not be changed easily later, so + choose wisely. 4. Install composer dependencies and generate autoload files: `composer install -o --no-dev` -5. If you have put Part-DB into a sub-directory on your server (like `part-db/`), you have to edit the file -`webpack.config.js` and uncomment the lines (remove the `//` before the lines) `.setPublicPath('/part-db/build')` (line 43) and - `.setManifestKeyPrefix('build/')` (line 44). You have to replace `/part-db` with your own path on line 44. -6. Install client side dependencies and build it: `yarn install` and `yarn build` -7. _Optional_ (speeds up first load): Warmup cache: `php bin/console cache:warmup` -8. Upgrade database to new scheme (or create it, when it was empty): `php bin/console doctrine:migrations:migrate` and follow the instructions given. During the process the password for the admin is user is shown. Copy it. **Caution**: This steps tamper with your database and could potentially destroy it. So make sure to make a backup of your database. -9. You can configure Part-DB via `config/parameters.yaml`. You should check if settings match your expectations, after you installed/upgraded Part-DB. Check if `partdb.default_currency` matches your mainly used currency (this can not be changed after creating price informations). - Run `php bin/console cache:clear` when you changed something. -10. Access Part-DB in your browser (under the URL you put it) and login with user *admin*. Password is the one outputted during DB setup. - If you can not remember the password, set a new one with `php bin/console app:set-password admin`. You can create new users with the admin user and start using Part-DB. +5. Install client side dependencies and build it: `yarn install` and `yarn build` +6. _Optional_ (speeds up first load): Warmup cache: `php bin/console cache:warmup` +7. Upgrade database to new scheme (or create it, when it was empty): `php bin/console doctrine:migrations:migrate` and + follow the instructions given. During the process the password for the admin is user is shown. Copy it. **Caution**: + These steps tamper with your database and could potentially destroy it. So make sure to make a backup of your + database. +8. You can configure Part-DB via `config/parameters.yaml`. You should check if settings match your expectations after + you installed/upgraded Part-DB. Check if `partdb.default_currency` matches your mainly used currency (this can not be + changed after creating price information). + Run `php bin/console cache:clear` when you change something. +9. Access Part-DB in your browser (under the URL you put it) and log in with user *admin*. Password is the one outputted + during DB setup. + If you can not remember the password, set a new one with `php bin/console app:set-password admin`. You can create + new users with the admin user and start using Part-DB. When you want to upgrade to a newer version, then just copy the new files into the folder and repeat the steps 4. to 7. -Normally a random password is generated when the admin user is created during inital database creation, -however you can set the inital admin password, by setting the `INITIAL_ADMIN_PW` env var. +Normally a random password is generated when the admin user is created during initial database creation, +however, you can set the initial admin password, by setting the `INITIAL_ADMIN_PW` env var. -You can configure Part-DB to your needs by changing environment variables in the `.env.local` file. +You can configure Part-DB to your needs by changing environment variables in the `.env.local` file. See [here](https://docs.part-db.de/configuration.html) for more information. ### Reverse proxy -If you are using a reverse proxy, you have to ensure that the proxies sets the `X-Forwarded-*` headers correctly, or you will get HTTP/HTTPS mixup and wrong hostnames. -If the reverse proxy is on a different server (or it cannot access Part-DB via localhost) you have to set the `TRUSTED_PROXIES` env variable to match your reverse proxies IP-address (or IP block). You can do this in your `.env.local` or (when using docker) in your `docker-compose.yml` file. + +If you are using a reverse proxy, you have to ensure that the proxies set the `X-Forwarded-*` headers correctly, or you +will get HTTP/HTTPS mixup and wrong hostnames. +If the reverse proxy is on a different server (or it cannot access Part-DB via localhost) you have to set +the `TRUSTED_PROXIES` env variable to match your reverse proxy's IP address (or IP block). You can do this in +your `.env.local` or (when using docker) in your `docker-compose.yml` file. ## Donate for development + If you want to donate to the Part-DB developer, see the sponsor button in the top bar (next to the repo name). -There you will find various methods to support development on a monthly or a one time base. +There you will find various methods to support development on a monthly or a one-time base. ## Built with + * [Symfony 5](https://symfony.com/): The main framework used for the serverside PHP * [Bootstrap 5](https://getbootstrap.com/) and [Bootswatch](https://bootswatch.com/): Used as website theme * [Fontawesome](https://fontawesome.com/): Used as icon set -* [Hotwire Stimulus](https://stimulus.hotwired.dev/) and [Hotwire Turbo](https://turbo.hotwired.dev/): Frontend Javascript +* [Hotwire Stimulus](https://stimulus.hotwired.dev/) and [Hotwire Turbo](https://turbo.hotwired.dev/): Frontend + Javascript ## Authors -* **Jan Böhmer** - *Inital work* - [Github](https://github.com/jbtronics/) -See also the list of [contributors](https://github.com/Part-DB/Part-DB-server/graphs/contributors) who participated in this project. +* **Jan Böhmer** - *Initial work* - [GitHub](https://github.com/jbtronics/) + +See also the list of [contributors](https://github.com/Part-DB/Part-DB-server/graphs/contributors) who participated in +this project. Based on the original Part-DB by Christoph Lechner and K. Jacobs ## License + Part-DB is licensed under the GNU Affero General Public License v3.0 (or at your opinion any later). This mostly means that you can use Part-DB for whatever you want (even use it commercially) as long as you publish the source code for every change you make under the AGPL, too. diff --git a/VERSION b/VERSION index dc1e644a..511a76e6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.0 +1.17.1 diff --git a/assets/ckeditor/plugins/PartDBLabel/PartDBLabelUI.js b/assets/ckeditor/plugins/PartDBLabel/PartDBLabelUI.js index 03737dae..37e1dcbe 100644 --- a/assets/ckeditor/plugins/PartDBLabel/PartDBLabelUI.js +++ b/assets/ckeditor/plugins/PartDBLabel/PartDBLabelUI.js @@ -85,6 +85,9 @@ const PLACEHOLDERS = [ ['[[COMMENT_T]]', 'Comment (plain text)'], ['[[LAST_MODIFIED]]', 'Last modified datetime'], ['[[CREATION_DATE]]', 'Creation datetime'], + ['[[IPN_BARCODE_QR]]', 'IPN as QR code'], + ['[[IPN_BARCODE_C128]]', 'IPN as Code 128 barcode'], + ['[[IPN_BARCODE_C39]]', 'IPN as Code 39 barcode'], ] }, { @@ -125,6 +128,8 @@ const PLACEHOLDERS = [ ['[[BARCODE_QR]]', 'QR code linking to this element'], ['[[BARCODE_C128]]', 'Code 128 barcode linking to this element'], ['[[BARCODE_C39]]', 'Code 39 barcode linking to this element'], + ['[[BARCODE_C93]]', 'Code 93 barcode linking to this element'], + ['[[BARCODE_DATAMATRIX]]', 'Datamatrix code linking to this element'], ] }, { diff --git a/assets/ckeditor/plugins/PartDBLabel/lang/de.js b/assets/ckeditor/plugins/PartDBLabel/lang/de.js index 53007a0a..748b1607 100644 --- a/assets/ckeditor/plugins/PartDBLabel/lang/de.js +++ b/assets/ckeditor/plugins/PartDBLabel/lang/de.js @@ -48,6 +48,9 @@ Object.assign( window.CKEDITOR_TRANSLATIONS[ 'de' ].dictionary, { 'Comment (plain text)': 'Kommentar (Nur-Text)', 'Last modified datetime': 'Zuletzt geändert', 'Creation datetime': 'Erstellt', + 'IPN as QR code': 'IPN als QR Code', + 'IPN as Code 128 barcode': 'IPN als Code 128 Barcode', + 'IPN as Code 39 barcode': 'IPN als Code 39 Barcode', 'Lot ID': 'Lot ID', 'Lot name': 'Lot Name', @@ -66,6 +69,8 @@ Object.assign( window.CKEDITOR_TRANSLATIONS[ 'de' ].dictionary, { 'QR code linking to this element': 'QR Code verknüpft mit diesem Element', 'Code 128 barcode linking to this element': 'Code 128 Barcode verknüpft mit diesem Element', 'Code 39 barcode linking to this element': 'Code 39 Barcode verknüpft mit diesem Element', + 'Code 93 barcode linking to this element': 'Code 93 Barcode verknüpft mit diesem Element', + 'Datamatrix code linking to this element': 'Datamatrix Code verknüpft mit diesem Element', 'Location ID': 'Lagerort ID', 'Name': 'Name', diff --git a/assets/controllers/common/hide_sidebar_controller.js b/assets/controllers/common/hide_sidebar_controller.js index d4c1b5e2..4be304ff 100644 --- a/assets/controllers/common/hide_sidebar_controller.js +++ b/assets/controllers/common/hide_sidebar_controller.js @@ -88,5 +88,8 @@ export default class extends Controller { } else { this.hideSidebar(); } + + //Hide the tootip on the button + this._toggle_button.blur(); } } \ No newline at end of file diff --git a/assets/controllers/common/markdown_controller.js b/assets/controllers/common/markdown_controller.js index 91aaef66..b6ef0034 100644 --- a/assets/controllers/common/markdown_controller.js +++ b/assets/controllers/common/markdown_controller.js @@ -20,18 +20,26 @@ 'use strict'; import { Controller } from '@hotwired/stimulus'; -import { marked } from "marked"; +import { Marked } from "marked"; import { mangle } from "marked-mangle"; import { gfmHeadingId } from "marked-gfm-heading-id"; import DOMPurify from 'dompurify'; import "../../css/app/markdown.css"; -export default class extends Controller { +export default class MarkdownController extends Controller { + + static _marked = new Marked([ + { + gfm: true, + }, + gfmHeadingId(), + mangle(), + ]) + ; connect() { - this.configureMarked(); this.render(); //Dispatch an event that we are now finished @@ -45,7 +53,7 @@ export default class extends Controller { let raw = this.element.dataset['markdown']; //Apply purified parsed markdown - this.element.innerHTML = DOMPurify.sanitize(marked(this.unescapeHTML(raw))); + this.element.innerHTML = DOMPurify.sanitize(MarkdownController._marked.parse(this.unescapeHTML(raw))); for(let a of this.element.querySelectorAll('a')) { //Mark all links as external @@ -81,8 +89,17 @@ export default class extends Controller { /** * Configure the marked parser */ - configureMarked() + /*static newMarked() { + const marked = new Marked([ + { + gfm: true, + }, + gfmHeadingId(), + mangle(), + ]) + ; + marked.use(mangle()); marked.use(gfmHeadingId({ })); @@ -90,5 +107,5 @@ export default class extends Controller { marked.setOptions({ gfm: true, }); - } + }*/ } \ No newline at end of file diff --git a/assets/controllers/elements/attachment_autocomplete_controller.js b/assets/controllers/elements/attachment_autocomplete_controller.js index fe44baee..f8bc301e 100644 --- a/assets/controllers/elements/attachment_autocomplete_controller.js +++ b/assets/controllers/elements/attachment_autocomplete_controller.js @@ -23,6 +23,12 @@ import "tom-select/dist/css/tom-select.bootstrap5.css"; import '../../css/components/tom-select_extensions.css'; import TomSelect from "tom-select"; +import TomSelect_click_to_edit from '../../tomselect/click_to_edit/click_to_edit' +import TomSelect_autoselect_typed from '../../tomselect/autoselect_typed/autoselect_typed' + +TomSelect.define('click_to_edit', TomSelect_click_to_edit) +TomSelect.define('autoselect_typed', TomSelect_autoselect_typed) + export default class extends Controller { _tomSelect; @@ -46,6 +52,12 @@ export default class extends Controller { } return '
' + escape(data.label) + '
'; } + }, + plugins: { + 'autoselect_typed': {}, + 'click_to_edit': {}, + 'clear_button': {}, + "restore_on_backspace": {} } }; diff --git a/assets/controllers/elements/ckeditor_controller.js b/assets/controllers/elements/ckeditor_controller.js index 4de536fe..079ee2ad 100644 --- a/assets/controllers/elements/ckeditor_controller.js +++ b/assets/controllers/elements/ckeditor_controller.js @@ -53,6 +53,7 @@ export default class extends Controller { const config = { language: language, + licenseKey: "GPL", } const watchdog = new EditorWatchdog(); @@ -70,7 +71,9 @@ export default class extends Controller { editor_div.classList.add(...new_classes.split(",")); } - console.log(editor); + //This return is important! Otherwise we get mysterious errors in the console + //See: https://github.com/ckeditor/ckeditor5/issues/5897#issuecomment-628471302 + return editor; }) .catch(error => { console.error(error); diff --git a/assets/controllers/elements/collection_type_controller.js b/assets/controllers/elements/collection_type_controller.js index 0b961cb0..8b816f30 100644 --- a/assets/controllers/elements/collection_type_controller.js +++ b/assets/controllers/elements/collection_type_controller.js @@ -75,13 +75,49 @@ export default class extends Controller { //Insert new html after the last child element //If the table has a tbody, insert it there + //Afterwards return the newly created row if(targetTable.tBodies[0]) { targetTable.tBodies[0].insertAdjacentHTML('beforeend', newElementStr); + return targetTable.tBodies[0].lastElementChild; } else { //Otherwise just insert it targetTable.insertAdjacentHTML('beforeend', newElementStr); + return targetTable.lastElementChild; } } + /** + * This action opens a file dialog to select multiple files and then creates a new element for each file, where + * the file is assigned to the input field. + * This should only be used for attachments collection types + * @param event + */ + uploadMultipleFiles(event) { + //Open a file dialog to select multiple files + const input = document.createElement('input'); + input.type = 'file'; + input.multiple = true; + input.click(); + + input.addEventListener('change', (event) => { + //Create a element for each file + + for (let i = 0; i < input.files.length; i++) { + const file = input.files[i]; + + const newElement = this.createElement(event); + const rowInput = newElement.querySelector("input[type='file']"); + + //We can not directly assign the file to the input, so we have to create a new DataTransfer object + const dataTransfer = new DataTransfer(); + dataTransfer.items.add(file); + + rowInput.files = dataTransfer.files; + } + + }); + + } + /** * Similar to createEvent Pricedetails need some special handling to fill min amount * @param event diff --git a/assets/controllers/elements/datatables/datatables_controller.js b/assets/controllers/elements/datatables/datatables_controller.js index df0dbbfc..5a50623d 100644 --- a/assets/controllers/elements/datatables/datatables_controller.js +++ b/assets/controllers/elements/datatables/datatables_controller.js @@ -24,18 +24,25 @@ import 'datatables.net-bs5/css/dataTables.bootstrap5.css' import 'datatables.net-buttons-bs5/css/buttons.bootstrap5.css' import 'datatables.net-fixedheader-bs5/css/fixedHeader.bootstrap5.css' import 'datatables.net-responsive-bs5/css/responsive.bootstrap5.css'; -import 'datatables.net-select-bs5/css/select.bootstrap5.css'; + +//Use our own styles for the select extension which fit the bootstrap theme better +//import 'datatables.net-select-bs5/css/select.bootstrap5.css'; +import '../../../css/components/datatables_select_bs5.css'; //JS import 'datatables.net-bs5'; import 'datatables.net-buttons-bs5'; import 'datatables.net-buttons/js/buttons.colVis.js'; import 'datatables.net-fixedheader-bs5'; -import 'datatables.net-select-bs5'; import 'datatables.net-colreorder-bs5'; import 'datatables.net-responsive-bs5'; import '../../../js/lib/datatables'; +//import 'datatables.net-select-bs5'; +//Use the local version containing the fix for the select extension +import '../../../js/lib/dataTables.select.mjs'; + + const EVENT_DT_LOADED = 'dt:loaded'; export default class extends Controller { @@ -65,8 +72,13 @@ export default class extends Controller { localStorage.setItem( this.getStateSaveKey(), JSON.stringify(data) ); } - stateLoadCallback(settings) { - const data = JSON.parse( localStorage.getItem(this.getStateSaveKey()) ); + stateLoadCallback() { + const json = localStorage.getItem(this.getStateSaveKey()); + if(json === null || json === undefined) { + return null; + } + + const data = JSON.parse(json); if (data) { //Do not save the start value (current page), as we want to always start at the first page on a page reload @@ -90,6 +102,19 @@ export default class extends Controller { //Add url info, as the one available in the history is not enough, as Turbo may have not changed it yet settings.url = this.element.dataset.dtUrl; + //Add initial_order info to the settings, so that the order on the initial page load is the one saved in the state + const saved_state = this.stateLoadCallback(); + if (saved_state !== null) { + const raw_order = saved_state.order; + + settings.initial_order = raw_order.map((order) => { + return { + column: order[0], + dir: order[1] + } + }); + } + let options = { colReorder: true, responsive: true, @@ -114,7 +139,7 @@ export default class extends Controller { if(this.isSelectable()) { options.select = { style: 'multi+shift', - selector: 'td.select-checkbox' + selector: 'td.dt-select', }; } @@ -127,6 +152,12 @@ export default class extends Controller { //Fix height of the length selector promise.then((dt) => { + + //Draw the rows to make sure the correct status text is displayed ("No matching records found" instead of "Loading...") + if (dt.data().length === 0) { + dt.rows().draw() + } + //Find all length selectors (select with name dt_length), which are inside a label const lengthSelectors = document.querySelectorAll('label select[name="dt_length"]'); //And remove the surrounding label, while keeping the select with all event handlers @@ -162,27 +193,6 @@ export default class extends Controller { dt.fixedHeader.headerOffset($("#navbar").outerHeight()); }); - //Register event handler to selectAllRows checkbox if available - if (this.isSelectable()) { - promise.then((dt) => { - const selectAllCheckbox = this.element.querySelector('thead th.select-checkbox'); - selectAllCheckbox.addEventListener('click', () => { - if(selectAllCheckbox.parentElement.classList.contains('selected')) { - dt.rows().deselect(); - selectAllCheckbox.parentElement.classList.remove('selected'); - } else { - dt.rows().select(); - selectAllCheckbox.parentElement.classList.add('selected'); - } - }); - - //When any row is deselected, also deselect the selectAll checkbox - dt.on('deselect.dt', () => { - selectAllCheckbox.parentElement.classList.remove('selected'); - }); - }); - } - //Allow to further configure the datatable promise.then(this._afterLoaded.bind(this)); @@ -221,4 +231,16 @@ export default class extends Controller { return this.element.dataset.select ?? false; } + invertSelection() { + //Do nothing if the datatable is not selectable + if(!this.isSelectable()) { + return; + } + + //Invert the selected rows on the datatable + const selected_rows = this._dt.rows({selected: true}); + this._dt.rows().select(); + selected_rows.deselect(); + } + } diff --git a/assets/controllers/elements/delete_btn_controller.js b/assets/controllers/elements/delete_btn_controller.js index 1b28de13..9ab15f7d 100644 --- a/assets/controllers/elements/delete_btn_controller.js +++ b/assets/controllers/elements/delete_btn_controller.js @@ -43,7 +43,8 @@ export default class extends Controller const message = this.element.dataset.deleteMessage; const title = this.element.dataset.deleteTitle; - const form = this.element; + //Use event target, to find the form, where the submit button was clicked + const form = event.target; const submitter = event.submitter; const that = this; diff --git a/assets/controllers/elements/localStorage_checkbox_controller.js b/assets/controllers/elements/localStorage_checkbox_controller.js new file mode 100644 index 00000000..70ef877d --- /dev/null +++ b/assets/controllers/elements/localStorage_checkbox_controller.js @@ -0,0 +1,67 @@ +/* + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {Controller} from "@hotwired/stimulus"; + +export default class extends Controller +{ + static values = { + id: String + } + + connect() { + this.loadState() + this.element.addEventListener('change', () => { + this.saveState() + }); + } + + loadState() { + let storageKey = this.getStorageKey(); + let value = localStorage.getItem(storageKey); + if (value === null) { + return; + } + + if (value === 'true') { + this.element.checked = true + } + if (value === 'false') { + this.element.checked = false + } + } + + saveState() { + let storageKey = this.getStorageKey(); + + if (this.element.checked) { + localStorage.setItem(storageKey, 'true'); + } else { + localStorage.setItem(storageKey, 'false'); + } + } + + getStorageKey() { + if (this.hasIdValue) { + return 'persistent_checkbox_' + this.idValue + } + + return 'persistent_checkbox_' + this.element.id; + } +} diff --git a/assets/controllers/elements/part_search_controller.js b/assets/controllers/elements/part_search_controller.js new file mode 100644 index 00000000..c33cece0 --- /dev/null +++ b/assets/controllers/elements/part_search_controller.js @@ -0,0 +1,200 @@ +/* + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { Controller } from "@hotwired/stimulus"; +import { autocomplete } from '@algolia/autocomplete-js'; +//import "@algolia/autocomplete-theme-classic/dist/theme.css"; +import "../../css/components/autocomplete_bootstrap_theme.css"; +import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches'; +import {marked} from "marked"; + +import { + trans, + SEARCH_PLACEHOLDER, + SEARCH_SUBMIT, + STATISTICS_PARTS +} from '../../translator'; + + +/** + * This controller is responsible for the search fields in the navbar and the homepage. + * It uses the Algolia Autocomplete library to provide a fast and responsive search. + */ +export default class extends Controller { + + static targets = ["input"]; + + _autocomplete; + + // Highlight the search query in the results + _highlight = (text, query) => { + if (!text) return text; + if (!query) return text; + + const HIGHLIGHT_PRE_TAG = '__aa-highlight__' + const HIGHLIGHT_POST_TAG = '__/aa-highlight__' + + const escaped = query.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); + const regex = new RegExp(escaped, 'gi'); + + return text.replace(regex, (match) => `${HIGHLIGHT_PRE_TAG}${match}${HIGHLIGHT_POST_TAG}`); + } + + initialize() { + // The endpoint for searching parts + const base_url = this.element.dataset.autocomplete; + // The URL template for the part detail pages + const part_detail_uri_template = this.element.dataset.detailUrl; + + //The URL of the placeholder picture + const placeholder_image = this.element.dataset.placeholderImage; + + //If the element is in navbar mode, or not + const navbar_mode = this.element.dataset.navbarMode === "true"; + + const that = this; + + const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({ + key: 'RECENT_SEARCH', + limit: 5, + }); + + this._autocomplete = autocomplete({ + container: this.element, + //Place the panel in the navbar, if the element is in navbar mode + panelContainer: navbar_mode ? document.getElementById("navbar-search-form") : document.body, + panelPlacement: this.element.dataset.panelPlacement, + plugins: [recentSearchesPlugin], + openOnFocus: true, + placeholder: trans(SEARCH_PLACEHOLDER), + translations: { + submitButtonTitle: trans(SEARCH_SUBMIT) + }, + + // Use a navigator compatible with turbo: + navigator: { + navigate({ itemUrl }) { + window.Turbo.visit(itemUrl, { action: "advance" }); + }, + navigateNewTab({ itemUrl }) { + const windowReference = window.open(itemUrl, '_blank', 'noopener'); + + if (windowReference) { + windowReference.focus(); + } + }, + navigateNewWindow({ itemUrl }) { + window.open(itemUrl, '_blank', 'noopener'); + }, + }, + + // If the form is submitted, forward the term to the form + onSubmit({state, event, ...setters}) { + //Put the current text into each target input field + const input = that.inputTarget; + + if (!input) { + return; + } + + //Do not submit the form, if the input is empty + if (state.query === "") { + return; + } + + input.value = state.query; + input.form.requestSubmit(); + }, + + + getSources({ query }) { + return [ + // The parts source + { + sourceId: 'parts', + getItems() { + const url = base_url.replace('__QUERY__', encodeURIComponent(query)); + + const data = fetch(url) + .then((response) => response.json()) + ; + + //Iterate over all fields besides the id and highlight them + const fields = ["name", "description", "category", "footprint"]; + + data.then((items) => { + items.forEach((item) => { + for (const field of fields) { + item[field] = that._highlight(item[field], query); + } + }); + }); + + return data; + }, + getItemUrl({ item }) { + return part_detail_uri_template.replace('__ID__', item.id); + }, + templates: { + header({ html }) { + return html`${trans(STATISTICS_PARTS)} +
`; + }, + item({item, components, html}) { + const details_url = part_detail_uri_template.replace('__ID__', item.id); + + return html` + +
+
+ ${item.name} +
+
+
+ + ${components.Highlight({hit: item, attribute: 'name'})} + +
+
+ ${components.Highlight({hit: item, attribute: 'description'})} + ${item.category ? html`

${components.Highlight({hit: item, attribute: 'category'})}

` : ""} + ${item.footprint ? html`

${components.Highlight({hit: item, attribute: 'footprint'})}

` : ""} +
+
+
+
+ `; + }, + }, + }, + ]; + }, + }); + + //Try to find the input field and register a defocus handler. This is necessarry, as by default the autocomplete + //lib has problems when multiple inputs are present on the page. (see https://github.com/algolia/autocomplete/issues/1216) + const inputs = this.element.getElementsByClassName('aa-Input'); + for (const input of inputs) { + input.addEventListener('blur', () => { + this._autocomplete.setIsOpen(false); + }); + } + + } +} \ No newline at end of file diff --git a/assets/controllers/elements/part_select_controller.js b/assets/controllers/elements/part_select_controller.js index c7507636..5abd5ba3 100644 --- a/assets/controllers/elements/part_select_controller.js +++ b/assets/controllers/elements/part_select_controller.js @@ -27,7 +27,7 @@ export default class extends Controller { } let tmp = '
' + - "
" + + "
" + (data.image ? "" : "") + "
" + "
" + diff --git a/assets/controllers/elements/static_file_autocomplete_controller.js b/assets/controllers/elements/static_file_autocomplete_controller.js new file mode 100644 index 00000000..31ca0314 --- /dev/null +++ b/assets/controllers/elements/static_file_autocomplete_controller.js @@ -0,0 +1,106 @@ +/* + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {Controller} from "@hotwired/stimulus"; + +import "tom-select/dist/css/tom-select.bootstrap5.css"; +import '../../css/components/tom-select_extensions.css'; +import TomSelect from "tom-select"; + +import TomSelect_click_to_edit from '../../tomselect/click_to_edit/click_to_edit' +import TomSelect_autoselect_typed from '../../tomselect/autoselect_typed/autoselect_typed' + +TomSelect.define('click_to_edit', TomSelect_click_to_edit) +TomSelect.define('autoselect_typed', TomSelect_autoselect_typed) + +/** + * This is the frontend controller for StaticFileAutocompleteType form element. + * Basically it loads a text file from the given url (via data-url) and uses it as a source for the autocomplete. + * The file is just a list of strings, one per line, which will be used as the autocomplete options. + * Lines starting with # will be ignored. + */ +export default class extends Controller { + _tomSelect; + + connect() { + + let settings = { + persistent: false, + create: true, + maxItems: 1, + maxOptions: 100, + createOnBlur: true, + selectOnTab: true, + valueField: 'text', + searchField: 'text', + orderField: 'text', + + //This a an ugly solution to disable the delimiter parsing of the TomSelect plugin + delimiter: 'VERY_L0NG_D€LIMITER_WHICH_WILL_NEVER_BE_ENCOUNTERED_IN_A_STRING', + plugins: { + 'autoselect_typed': {}, + 'click_to_edit': {}, + 'clear_button': {}, + 'restore_on_backspace': {} + } + }; + + if (this.element.dataset.url) { + const url = this.element.dataset.url; + settings.load = (query, callback) => { + const self = this; + if (self.loading > 1) { + callback(); + return; + } + + fetch(url) + .then(response => response.text()) + .then(text => { + // Convert the text file to array + let lines = text.split("\n"); + //Remove all lines beginning with # + lines = lines.filter(x => !x.startsWith("#")); + + //Convert the array to an object, where each line is in the text field + lines = lines.map(x => { + return {text: x}; + }); + + + //Unset the load function to prevent endless recursion + self._tomSelect.settings.load = null; + + callback(lines); + }).catch(() => { + callback(); + }); + }; + } + + this._tomSelect = new TomSelect(this.element, settings); + } + + disconnect() { + super.disconnect(); + //Destroy the TomSelect instance + this._tomSelect.destroy(); + } + +} diff --git a/assets/controllers/elements/structural_entity_select_controller.js b/assets/controllers/elements/structural_entity_select_controller.js index e775af8a..a1114a97 100644 --- a/assets/controllers/elements/structural_entity_select_controller.js +++ b/assets/controllers/elements/structural_entity_select_controller.js @@ -24,6 +24,8 @@ import {Controller} from "@hotwired/stimulus"; import {trans, ENTITY_SELECT_GROUP_NEW_NOT_ADDED_TO_DB} from '../../translator.js' +import TomSelect_autoselect_typed from '../../tomselect/autoselect_typed/autoselect_typed' +TomSelect.define('autoselect_typed', TomSelect_autoselect_typed) export default class extends Controller { _tomSelect; @@ -38,12 +40,20 @@ export default class extends Controller { const allowAdd = this.element.getAttribute("data-allow-add") === "true"; const addHint = this.element.getAttribute("data-add-hint") ?? ""; + + + let settings = { allowEmptyOption: true, selectOnTab: true, maxOptions: null, create: allowAdd ? this.createItem.bind(this) : false, - createFilter: /\D/, //Must contain a non-digit character, otherwise they would be recognized as DB ID + createFilter: this.createFilter.bind(this), + + // This three options allow us to paste element names with commas: (see issue #538) + maxItems: 1, + delimiter: "$$VERY_LONG_DELIMITER_THAT_SHOULD_NEVER_APPEAR$$", + splitOn: null, searchField: [ {field: "text", weight : 2}, @@ -54,7 +64,21 @@ export default class extends Controller { render: { item: this.renderItem.bind(this), option: this.renderOption.bind(this), - option_create: function(data, escape) { + option_create: (data, escape) => { + //If the input starts with "->", we prepend the current selected value, for easier extension of existing values + //This here handles the display part, while the createItem function handles the actual creation + if (data.input.startsWith("->")) { + //Get current selected value + const current = this._tomSelect.getItem(this._tomSelect.getValue()).textContent.replaceAll("→", "->").trim(); + //Prepend it to the input + if (current) { + data.input = current + " " + data.input; + } else { + //If there is no current value, we remove the "->" + data.input = data.input.substring(2); + } + } + return '
 ' + escape(data.input) + '… ' + '(' + addHint +')' + '
'; @@ -64,20 +88,72 @@ export default class extends Controller { //Add callbacks to update validity onInitialize: this.updateValidity.bind(this), onChange: this.updateValidity.bind(this), + + plugins: { + "autoselect_typed": {}, + } }; + //Add clear button plugin, if an empty option is present + if (this.element.querySelector("option[value='']") !== null) { + settings.plugins["clear_button"] = {}; + } + this._tomSelect = new TomSelect(this.element, settings); - this._tomSelect.sync(); + //Do not do a sync here as this breaks the initial rendering of the empty option + //this._tomSelect.sync(); } createItem(input, callback) { + + //If the input starts with "->", we prepend the current selected value, for easier extension of existing values + if (input.startsWith("->")) { + //Get current selected value + let current = this._tomSelect.getItem(this._tomSelect.getValue()).textContent.replaceAll("→", "->").trim(); + //Replace no break spaces with normal spaces + current = current.replaceAll("\u00A0", " "); + //Prepend it to the input + if (current) { + input = current + " " + input; + } else { + //If there is no current value, we remove the "->" + input = input.substring(2); + } + } + callback({ - value: input, + //$%$ is a special value prefix, that is used to identify items, that are not yet in the DB + value: '$%$' + input, text: input, not_in_db_yet: true, }); } + createFilter(input) { + + //Normalize the input (replace spacing around arrows) + if (input.includes("->")) { + const inputs = input.split("->"); + inputs.forEach((value, index) => { + inputs[index] = value.trim(); + }); + input = inputs.join("->"); + } else { + input = input.trim(); + } + + const options = this._tomSelect.options; + //Iterate over all options and check if the input is already present + for (let index in options) { + const option = options[index]; + if (option.path === input) { + return false; + } + } + + return true; + } + updateValidity() { //Mark this input as invalid, if the selected option is disabled diff --git a/assets/controllers/elements/tagsinput_controller.js b/assets/controllers/elements/tagsinput_controller.js index acfcd0fa..1f10c457 100644 --- a/assets/controllers/elements/tagsinput_controller.js +++ b/assets/controllers/elements/tagsinput_controller.js @@ -23,14 +23,21 @@ import "tom-select/dist/css/tom-select.bootstrap5.css"; import '../../css/components/tom-select_extensions.css'; import TomSelect from "tom-select"; +import TomSelect_click_to_edit from '../../tomselect/click_to_edit/click_to_edit' +import TomSelect_autoselect_typed from '../../tomselect/autoselect_typed/autoselect_typed' + +TomSelect.define('click_to_edit', TomSelect_click_to_edit) +TomSelect.define('autoselect_typed', TomSelect_autoselect_typed) + export default class extends Controller { _tomSelect; connect() { let settings = { plugins: { - remove_button:{ - } + remove_button:{}, + 'autoselect_typed': {}, + 'click_to_edit': {}, }, persistent: false, selectOnTab: true, diff --git a/assets/controllers/elements/tree_controller.js b/assets/controllers/elements/tree_controller.js index d2f21a8e..bb64839c 100644 --- a/assets/controllers/elements/tree_controller.js +++ b/assets/controllers/elements/tree_controller.js @@ -94,13 +94,15 @@ export default class extends Controller { showTags: this._showTags, data: data, showIcon: true, + preventUnselect: true, + allowReselect: true, onNodeSelected: (event) => { const node = event.detail.node; if (node.href) { window.Turbo.visit(node.href, {action: "advance"}); + this._registerURLWatcher(node); } }, - //onNodeContextmenu: contextmenu_handler, }, [BS5Theme, BS53Theme, FAIconTheme]); this.treeTarget.addEventListener(EVENT_INITIALIZED, (event) => { @@ -108,12 +110,42 @@ export default class extends Controller { const treeView = event.detail.treeView; treeView.revealNode(treeView.getSelected()); + //Add the url watcher to all selected nodes + for (const node of treeView.getSelected()) { + this._registerURLWatcher(node); + } + //Add contextmenu event listener to the tree, which allows us to open the links in a new tab with a right click treeView.getTreeElement().addEventListener("contextmenu", this._onContextMenu.bind(this)); }); } + _registerURLWatcher(node) + { + //Register a watcher for a location change, which will unselect the node, if the location changes + const desired_url = node.href; + + //Ensure that the node is unselected, if the location changes + const unselectNode = () => { + //Parse url so we can properly compare them + const desired = new URL(node.href, window.location.origin); + + //We only compare the pathname, because the hash and parameters should not matter + if(window.location.pathname !== desired.pathname) { + //The ignore parameter is important here, otherwise the node will not be unselected + node.setSelected(false, {silent: true, ignorePreventUnselect: true}); + + //Unregister the watcher + document.removeEventListener('turbo:load', unselectNode); + } + }; + + //Register the watcher via hotwire turbo + //We must just load to have the new url in window.location + document.addEventListener('turbo:load', unselectNode); + } + _onContextMenu(event) { //Find the node that was clicked and open link in new tab diff --git a/assets/controllers/pages/association_edit_type_select_controller.js b/assets/controllers/pages/association_edit_type_select_controller.js new file mode 100644 index 00000000..10badf9c --- /dev/null +++ b/assets/controllers/pages/association_edit_type_select_controller.js @@ -0,0 +1,44 @@ +/* + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {Controller} from "@hotwired/stimulus"; + +export default class extends Controller { + + static targets = [ "display", "select" ] + + connect() + { + this.update(); + this.selectTarget.addEventListener('change', this.update.bind(this)); + } + + update() + { + //If the select value is 0, then we show the input field + if( this.selectTarget.value === '0') + { + this.displayTarget.classList.remove('d-none'); + } + else + { + this.displayTarget.classList.add('d-none'); + } + } +} \ No newline at end of file diff --git a/assets/controllers/pages/barcode_scan_controller.js b/assets/controllers/pages/barcode_scan_controller.js index 5f82a39e..368fef43 100644 --- a/assets/controllers/pages/barcode_scan_controller.js +++ b/assets/controllers/pages/barcode_scan_controller.js @@ -20,7 +20,7 @@ import {Controller} from "@hotwired/stimulus"; //import * as ZXing from "@zxing/library"; -import {Html5QrcodeScanner, Html5Qrcode} from "html5-qrcode"; +import {Html5QrcodeScanner, Html5Qrcode} from "@part-db/html5-qrcode"; /* stimulusFetch: 'lazy' */ export default class extends Controller { @@ -50,7 +50,7 @@ export default class extends Controller { }); this._scanner = new Html5QrcodeScanner(this.element.id, { - fps: 2, + fps: 10, qrbox: qrboxFunction, experimentalFeatures: { //This option improves reading quality on android chrome @@ -61,6 +61,11 @@ export default class extends Controller { this._scanner.render(this.onScanSuccess.bind(this)); } + disconnect() { + this._scanner.pause(); + this._scanner.clear(); + } + onScanSuccess(decodedText, decodedResult) { //Put our decoded Text into the input box document.getElementById('scan_dialog_input').value = decodedText; diff --git a/assets/controllers/pages/dont_check_quantity_checkbox_controller.js b/assets/controllers/pages/dont_check_quantity_checkbox_controller.js new file mode 100644 index 00000000..2abd3d77 --- /dev/null +++ b/assets/controllers/pages/dont_check_quantity_checkbox_controller.js @@ -0,0 +1,65 @@ +/* + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {Controller} from "@hotwired/stimulus"; + +/** + * This controller is used on a checkbox, which toggles the max value of all number input fields + */ +export default class extends Controller { + + _checkbox; + + getCheckbox() { + if (this._checkbox) { + return this._checkbox; + } + + //Find the checkbox inside the controller element + this._checkbox = this.element.querySelector('input[type="checkbox"]'); + return this._checkbox; + } + + connect() { + //Add event listener to the checkbox + this.getCheckbox().addEventListener('change', this.toggleInputLimits.bind(this)); + } + + toggleInputLimits() { + //Find all input fields with the data-toggle-input-limits-target="max" + const inputFields = document.querySelectorAll("input[type='number']"); + + inputFields.forEach((inputField) => { + //Ensure that the input field has either a max or a data-max attribute + if (!inputField.hasAttribute('max') && !inputField.hasAttribute('data-max')) { + return; + } + + //If the checkbox is checked, rename the max attribute to data-max + if (this.getCheckbox().checked) { + inputField.setAttribute('data-max', inputField.getAttribute('max')); + inputField.removeAttribute('max'); + } else { + //If the checkbox is not checked, rename the data-max attribute back to max + inputField.setAttribute('max', inputField.getAttribute('data-max')); + inputField.removeAttribute('data-max'); + } + }); + } +} \ No newline at end of file diff --git a/assets/controllers/pages/latex_preview_controller.js b/assets/controllers/pages/latex_preview_controller.js index c836faa6..6113393a 100644 --- a/assets/controllers/pages/latex_preview_controller.js +++ b/assets/controllers/pages/latex_preview_controller.js @@ -25,9 +25,20 @@ import "katex/dist/katex.css"; export default class extends Controller { static targets = ["input", "preview"]; + static values = { + unit: {type: Boolean, default: false} //Render as upstanding (non-italic) text, useful for units + } + updatePreview() { - katex.render(this.inputTarget.value, this.previewTarget, { + let value = ""; + if (this.unitValue) { + value = "\\mathrm{" + this.inputTarget.value + "}"; + } else { + value = this.inputTarget.value; + } + + katex.render(value, this.previewTarget, { throwOnError: false, }); } diff --git a/assets/controllers/pages/parameters_autocomplete_controller.js b/assets/controllers/pages/parameters_autocomplete_controller.js index f6504990..cd82875a 100644 --- a/assets/controllers/pages/parameters_autocomplete_controller.js +++ b/assets/controllers/pages/parameters_autocomplete_controller.js @@ -22,6 +22,13 @@ import TomSelect from "tom-select"; import katex from "katex"; import "katex/dist/katex.css"; + +import TomSelect_click_to_edit from '../../tomselect/click_to_edit/click_to_edit' +import TomSelect_autoselect_typed from '../../tomselect/autoselect_typed/autoselect_typed' + +TomSelect.define('click_to_edit', TomSelect_click_to_edit) +TomSelect.define('autoselect_typed', TomSelect_autoselect_typed) + /* stimulusFetch: 'lazy' */ export default class extends Controller { @@ -53,7 +60,10 @@ export default class extends Controller connect() { const settings = { plugins: { - clear_button:{} + 'autoselect_typed': {}, + 'click_to_edit': {}, + 'clear_button': {}, + 'restore_on_backspace': {} }, persistent: false, maxItems: 1, diff --git a/assets/controllers/pages/part_merge_modal_controller.js b/assets/controllers/pages/part_merge_modal_controller.js new file mode 100644 index 00000000..e9e41302 --- /dev/null +++ b/assets/controllers/pages/part_merge_modal_controller.js @@ -0,0 +1,68 @@ +/* + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import {Controller} from "@hotwired/stimulus"; + +export default class extends Controller +{ + static targets = ['link', 'mode', 'otherSelect']; + static values = { + targetId: Number, + }; + + connect() { + } + + update() { + const link = this.linkTarget; + const other_select = this.otherSelectTarget; + + //Extract the mode using the mode radio buttons (we filter the array to get the checked one) + const mode = (this.modeTargets.filter((e)=>e.checked))[0].value; + + if (other_select.value === '') { + link.classList.add('disabled'); + return; + } + + //Extract href template from data attribute on link target + let href = link.getAttribute('data-href-template'); + + let target, other; + if (mode === '1') { + target = this.targetIdValue; + other = other_select.value; + } else if (mode === '2') { + target = other_select.value; + other = this.targetIdValue; + } else { + throw 'Invalid mode'; + } + + //Replace placeholder with actual target id + href = href.replace('__target__', target); + //Replace placeholder with selected value of the select (the event sender) + href = href.replace('__other__', other); + + //Assign new href to link + link.setAttribute('href', href); + //Make link clickable + link.classList.remove('disabled'); + } +} \ No newline at end of file diff --git a/assets/css/app/helpers.css b/assets/css/app/helpers.css index 2741d667..8e7b6fa3 100644 --- a/assets/css/app/helpers.css +++ b/assets/css/app/helpers.css @@ -111,4 +111,11 @@ ul.structural_link li a:hover { .permission-checkbox:checked { background-color: var(--bs-success); border-color: var(--bs-success); +} + +/*********************************************** + * Katex rendering with same height as text + ***********************************************/ +.katex-same-height-as-text .katex { + font-size: 1.0em; } \ No newline at end of file diff --git a/assets/css/app/images.css b/assets/css/app/images.css index 9168484d..214776e7 100644 --- a/assets/css/app/images.css +++ b/assets/css/app/images.css @@ -51,7 +51,6 @@ .part-table-image { max-height: 40px; object-fit: contain; - width: 100%; } .part-info-image { @@ -61,4 +60,4 @@ .object-fit-cover { object-fit: cover; -} \ No newline at end of file +} diff --git a/assets/css/app/layout.css b/assets/css/app/layout.css index e00c823c..4be123a7 100644 --- a/assets/css/app/layout.css +++ b/assets/css/app/layout.css @@ -108,8 +108,8 @@ body { .back-to-top { cursor: pointer; position: fixed; - bottom: 20px; - right: 20px; + bottom: 60px; + right: 40px; display:none; z-index: 1030; } diff --git a/assets/css/app/tables.css b/assets/css/app/tables.css index 276272b7..ae892f50 100644 --- a/assets/css/app/tables.css +++ b/assets/css/app/tables.css @@ -63,10 +63,6 @@ table.dataTable > tbody > tr.selected > td > a { margin-block-end: 0; } -.card-footer-table { - padding-top: 0; -} - table.dataTable { margin-top: 0 !important; } @@ -84,14 +80,24 @@ th.select-checkbox { * Datatables definitions/overrides ********************************************************************/ -.dataTables_length { +.dt-length { display: inline-flex; } /** Fix datatables select-checkbox position */ table.dataTable tr.selected td.select-checkbox:after { - margin-top: -25px !important; + margin-top: -20px !important; +} + +/** Show pagination right aligned */ +.dt-paging .pagination { + justify-content: flex-end; +} + +/** Fix table row coloring */ +table.table.dataTable > :not(caption) > * > * { + background-color: var(--bs-table-bg); } @@ -103,53 +109,4 @@ Classes for Datatables export #export-messageTop, .export-helper{ display: none; -} - -/****************************************************** - * Styling for the select all checkbox in the parts table - * Should match the styling of the select checkbox - ******************************************************/ -table.dataTable > thead > tr > th.select-checkbox { - position: relative; -} -table.dataTable > thead > tr > th.select-checkbox:before, -table.dataTable > thead > tr > th.select-checkbox:after { - display: block; - position: absolute; - top: 0.9em; - left: 50%; - width: 1em !important; - height: 1em !important; - box-sizing: border-box; -} -table.dataTable > thead > tr > th.select-checkbox:before { - content: " "; - margin-top: -5px; - margin-left: -6px; - border: 2px solid var(--bs-tertiary-color); - border-radius: 3px; -} - -table.dataTable > tbody > tr > td.select-checkbox:before, table.dataTable > tbody > tr > th.select-checkbox:before { - border: 2px solid var(--bs-tertiary-color) !important; -} - -table.dataTable > tbody > tr > td.select-checkbox:before, table.dataTable > tbody > tr > td.select-checkbox:after, table.dataTable > tbody > tr > th.select-checkbox:before, table.dataTable > tbody > tr > th.select-checkbox:after { - width: 1em !important; - height: 1em !important; -} - -table.dataTable > thead > tr.selected > th.select-checkbox:after { - content: "✓"; - font-size: 20px; - margin-top: -20px; - margin-left: -6px; - text-align: center; - /*text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9; */ -} -table.dataTable.compact > thead > tr > th.select-checkbox:before { - margin-top: -12px; -} -table.dataTable.compact > thead > tr.selected > th.select-checkbox:after { - margin-top: -16px; -} +} \ No newline at end of file diff --git a/assets/css/components/autocomplete_bootstrap_theme.css b/assets/css/components/autocomplete_bootstrap_theme.css new file mode 100644 index 00000000..d86232e5 --- /dev/null +++ b/assets/css/components/autocomplete_bootstrap_theme.css @@ -0,0 +1,1120 @@ +/* + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/*** + * This file is based on the autocomplete-theme-classic from Algolia and modifies it to fit better into the bootstrap 5 + * theme of Part-DB. + */ + +/*! @algolia/autocomplete-theme-classic 1.17.0 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */ +/* ----------------*/ +/* 1. CSS Variables*/ +/* 2. Dark Mode*/ +/* 3. Autocomplete*/ +/* 4. Panel*/ +/* 5. Sources*/ +/* 6. Hit Layout*/ +/* 7. Panel Header*/ +/* 8. Panel Footer*/ +/* 9. Detached Mode*/ +/* 10. Gradients*/ +/* 11. Utilities*/ +/* ----------------*/ +/* Note:*/ +/* This theme reflects the markup structure of autocomplete with SCSS indentation.*/ +/* We use the SASS `@at-root` function to keep specificity low.*/ +/* ----------------*/ +/* 1. CSS Variables*/ +/* ----------------*/ +:root { + /* Input*/ + --aa-search-input-height: 44px; + --aa-input-icon-size: 20px; + /* Size and spacing*/ + --aa-base-unit: 16; + --aa-spacing-factor: 1; + --aa-spacing: calc(var(--aa-base-unit) * var(--aa-spacing-factor) * 1px); + --aa-spacing-half: calc(var(--aa-spacing) / 2); + --aa-panel-max-height: 650px; + /* Z-index*/ + --aa-base-z-index: 9999; + /* Font*/ + --aa-font-size: calc(var(--aa-base-unit) * 1px); + --aa-font-family: inherit; + --aa-font-weight-medium: 500; + --aa-font-weight-semibold: 600; + --aa-font-weight-bold: 700; + /* Icons*/ + --aa-icon-size: 20px; + --aa-icon-stroke-width: 1.6; + --aa-icon-color-rgb: 119, 119, 163; + --aa-icon-color-alpha: 1; + --aa-action-icon-size: 20px; + /* Text colors*/ + --aa-text-color-rgb: 38, 38, 39; + --aa-text-color-alpha: 1; + --aa-primary-color-rgb: 62, 52, 211; + --aa-primary-color-alpha: 0.2; + --aa-muted-color-rgb: 128, 126, 163; + --aa-muted-color-alpha: 0.6; + /* Border colors*/ + --aa-panel-border-color-rgb: 128, 126, 163; + --aa-panel-border-color-alpha: 0.3; + --aa-input-border-color-rgb: 128, 126, 163; + --aa-input-border-color-alpha: 0.8; + /* Background colors*/ + --aa-background-color-rgb: 255, 255, 255; + --aa-background-color-alpha: 1; + --aa-input-background-color-rgb: 255, 255, 255; + --aa-input-background-color-alpha: 1; + --aa-selected-color-rgb: 179, 173, 214; + --aa-selected-color-alpha: 0.205; + --aa-description-highlight-background-color-rgb: 245, 223, 77; + --aa-description-highlight-background-color-alpha: 0.5; + /* Detached mode*/ + --aa-detached-media-query: (max-width: 680px); + --aa-detached-modal-media-query: (min-width: 680px); + --aa-detached-modal-max-width: 680px; + --aa-detached-modal-max-height: 500px; + --aa-overlay-color-rgb: 115, 114, 129; + --aa-overlay-color-alpha: 0.4; + /* Shadows*/ + --aa-panel-shadow: 0 0 0 1px rgba(35, 38, 59, .1), + 0 6px 16px -4px rgba(35, 38, 59, .15); + /* Scrollbar*/ + --aa-scrollbar-width: 13px; + --aa-scrollbar-track-background-color-rgb: 234, 234, 234; + --aa-scrollbar-track-background-color-alpha: 1; + --aa-scrollbar-thumb-background-color-rgb: var(--aa-background-color-rgb); + --aa-scrollbar-thumb-background-color-alpha: 1; + /* Touch screens*/ +} +@media (hover: none) and (pointer: coarse) { + :root { + --aa-spacing-factor: 1.2; + --aa-action-icon-size: 22px; + } +} + +/* ----------------*/ +/* 2. Dark Mode*/ +/* ----------------*/ +body { + /* stylelint-disable selector-no-qualifying-type, selector-class-pattern */ + /* stylelint-enable selector-no-qualifying-type, selector-class-pattern */ +} + +/* Reset for `@extend`*/ +.aa-Panel *, .aa-Autocomplete *, +.aa-DetachedFormContainer * { + box-sizing: border-box; +} + +/* Init for `@extend`*/ +.aa-Panel, .aa-Autocomplete, +.aa-DetachedFormContainer { + color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha)); + color: var(--bs-body-color); + font-family: inherit; + font-weight: normal; + line-height: 1em; + margin: 0; + padding: 0; + text-align: left; +} + +/* ----------------*/ +/* 3. Autocomplete*/ +/* ----------------*/ +.aa-Autocomplete, +.aa-DetachedFormContainer { + /* Search box*/ +} +.aa-Form { + align-items: center; + background-color: var(--bs-body-bg); + border: var(--bs-border-width) solid var(--bs-border-color); + border-radius: var(--bs-border-radius); + color: var(--bs-body-color); + transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; + display: flex; + line-height: 1em; + margin: 0; + position: relative; + width: 100%; +} +.aa-Form:focus-within { + background-color: var(--bs-body-bg); + border-color: #86b7fe; + box-shadow: 0 0 0 0.25rem rgba(13,110,253,.25); + color: var(--bs-body-color); + outline: 0; +} +.aa-InputWrapperPrefix { + align-items: center; + display: flex; + flex-shrink: 0; + height: 44px; + height: var(--aa-search-input-height); + order: 1; + /* Container for search and loading icons*/ +} +.aa-Label, +.aa-LoadingIndicator { + cursor: auto; + cursor: initial; + flex-shrink: 0; + height: 100%; + padding: 0; + text-align: left; +} +.aa-Label svg, +.aa-LoadingIndicator svg { + color: rgba(var(--bs-primary-rgb), 1.0); + height: auto; + max-height: 20px; + max-height: var(--aa-input-icon-size); + stroke-width: 1.6; + stroke-width: var(--aa-icon-stroke-width); + width: 20px; + width: var(--aa-input-icon-size); +} + +.aa-SubmitButton, +.aa-LoadingIndicator { + height: 100%; + padding-left: calc((16 * 1 * 1px) * 0.75 - 1px); + padding-left: calc(calc(16 * 1 * 1px) * 0.75 - 1px); + padding-left: calc(var(--aa-spacing) * 0.75 - 1px); + padding-right: calc((16 * 1 * 1px) / 2); + padding-right: calc(calc(16 * 1 * 1px) / 2); + padding-right: var(--aa-spacing-half); + width: calc((16 * 1 * 1px) * 1.75 + 20px - 1px); + width: calc(calc(16 * 1 * 1px) * 1.75 + 20px - 1px); + width: calc(var(--aa-spacing) * 1.75 + var(--aa-icon-size) - 1px); +} +@media (hover: none) and (pointer: coarse) { + .aa-SubmitButton, + .aa-LoadingIndicator { + padding-left: calc(((16 * 1 * 1px) / 2) / 2 - 1px); + padding-left: calc(calc(calc(16 * 1 * 1px) / 2) / 2 - 1px); + padding-left: calc(var(--aa-spacing-half) / 2 - 1px); + width: calc(20px + (16 * 1 * 1px) * 1.25 - 1px); + width: calc(20px + calc(16 * 1 * 1px) * 1.25 - 1px); + width: calc(var(--aa-icon-size) + var(--aa-spacing) * 1.25 - 1px); + } +} + +.aa-SubmitButton { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: none; + border: 0; + margin: 0; +} + +.aa-LoadingIndicator { + align-items: center; + display: flex; + justify-content: center; +} +.aa-LoadingIndicator[hidden] { + display: none; +} + +.aa-InputWrapper { + order: 3; + position: relative; + width: 100%; + /* Search box input (with placeholder and query)*/ +} +.aa-Input { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: none; + border: 0; + color: var(--bs-body-color); + font: inherit; + height: 44px; + height: var(--aa-search-input-height); + padding: 0; + width: 100%; + /* Focus is set and styled on the parent, it isn't necessary here*/ + /* Remove native appearance*/ +} +.aa-Input::-moz-placeholder { + color: var(--bs-secondary-color); + opacity: 1; +} +.aa-Input::placeholder { + color: var(--bs-secondary-color); + opacity: 1; +} +.aa-Input:focus { + box-shadow: none; + outline: none; +} +.aa-Input::-webkit-search-decoration, .aa-Input::-webkit-search-cancel-button, .aa-Input::-webkit-search-results-button, .aa-Input::-webkit-search-results-decoration { + -webkit-appearance: none; + appearance: none; +} + +.aa-InputWrapperSuffix { + align-items: center; + display: flex; + height: 44px; + height: var(--aa-search-input-height); + order: 4; + /* Accelerator to clear the query*/ +} +.aa-ClearButton { + align-items: center; + background: none; + border: 0; + color: var(--bs-secondary-color); + cursor: pointer; + display: flex; + height: 100%; + margin: 0; + padding: 0 calc((16 * 1 * 1px) * 0.8333333333 - 0.5px); + padding: 0 calc(calc(16 * 1 * 1px) * 0.8333333333 - 0.5px); + padding: 0 calc(var(--aa-spacing) * 0.8333333333 - 0.5px); +} +@media (hover: none) and (pointer: coarse) { + .aa-ClearButton { + padding: 0 calc((16 * 1 * 1px) * 0.6666666667 - 0.5px); + padding: 0 calc(calc(16 * 1 * 1px) * 0.6666666667 - 0.5px); + padding: 0 calc(var(--aa-spacing) * 0.6666666667 - 0.5px); + } +} +.aa-ClearButton:hover, .aa-ClearButton:focus { + color: var(--bs-body-color); +} +.aa-ClearButton[hidden] { + display: none; +} +.aa-ClearButton svg { + stroke-width: 1.6; + stroke-width: var(--aa-icon-stroke-width); + width: 20px; + width: var(--aa-icon-size); +} + +/* ----------------*/ +/* 4. Panel*/ +/* ----------------*/ +.aa-Panel { + --bs-dropdown-header-padding-x: 1rem; + --bs-dropdown-header-padding-y: 0.5rem; + --bs-dropdown-font-size: 1rem; + --bs-dropdown-color: var(--bs-body-color); + --bs-dropdown-bg: var(--bs-body-bg); + --bs-dropdown-border-color: var(--bs-border-color-translucent); + --bs-dropdown-border-radius: var(--bs-border-radius); + --bs-dropdown-border-width: var(--bs-border-width); + + z-index: 1000; + + box-shadow: 0 0 0 1px rgba(35, 38, 59, 0.1); + overflow: hidden; + position: absolute; + transition: opacity 200ms ease-in, filter 200ms ease-in; + /* When a request isn't resolved yet*/ + + padding: var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x); + margin: 0; + font-size: var(--bs-dropdown-font-size); + color: var(--bs-dropdown-color); + background-color: var(--bs-dropdown-bg); + background-clip: padding-box; + border: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color); + border-radius: var(--bs-dropdown-border-radius); +} +@media screen and (prefers-reduced-motion) { + .aa-Panel { + transition: none; + } +} +.aa-Panel button { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: none; + border: 0; + margin: 0; + padding: 0; +} +.aa-PanelLayout { + height: 100%; + margin: 0; + max-height: 650px; + max-height: var(--aa-panel-max-height); + overflow-y: auto; + padding: 0; + position: relative; + text-align: left; +} +.aa-PanelLayoutColumns--twoGolden { + display: grid; + grid-template-columns: 39.2% auto; + overflow: hidden; + padding: 0; +} + +.aa-PanelLayoutColumns--two { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + overflow: hidden; + padding: 0; +} + +.aa-PanelLayoutColumns--three { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + overflow: hidden; + padding: 0; +} + +.aa-Panel--stalled .aa-Source { + filter: grayscale(1); + opacity: 0.8; +} + +.aa-Panel--scrollable { + margin: 0; + max-height: 650px; + max-height: var(--aa-panel-max-height); + overflow-x: hidden; + overflow-y: auto; + padding: calc((16 * 1 * 1px) / 2); + padding: calc(calc(16 * 1 * 1px) / 2); + padding: var(--aa-spacing-half); + scrollbar-color: rgba(255, 255, 255, 1) rgba(234, 234, 234, 1); + scrollbar-color: rgba(var(--aa-scrollbar-thumb-background-color-rgb), var(--aa-scrollbar-thumb-background-color-alpha)) rgba(var(--aa-scrollbar-track-background-color-rgb), var(--aa-scrollbar-track-background-color-alpha)); + scrollbar-width: thin; +} +.aa-Panel--scrollable::-webkit-scrollbar { + width: 13px; + width: var(--aa-scrollbar-width); +} +.aa-Panel--scrollable::-webkit-scrollbar-track { + background-color: rgba(234, 234, 234, 1); + background-color: rgba(var(--aa-scrollbar-track-background-color-rgb), var(--aa-scrollbar-track-background-color-alpha)); +} +.aa-Panel--scrollable::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 1); + background-color: rgba(var(--aa-scrollbar-thumb-background-color-rgb), var(--aa-scrollbar-thumb-background-color-alpha)); + border-color: rgba(234, 234, 234, 1); + border-color: rgba(var(--aa-scrollbar-track-background-color-rgb), var(--aa-scrollbar-track-background-color-alpha)); + border-radius: 9999px; + border-style: solid; + border-width: 3px 2px 3px 3px; +} + +/* ----------------*/ +/* 5. Sources*/ +/* Each source can be styled independently*/ +/* ----------------*/ +.aa-Source { + margin: 0; + padding: 0; + position: relative; + width: 100%; + /* List of results inside the source*/ + /* Source title*/ + /* See all button*/ +} +.aa-Source:empty { + /* Hide empty section*/ + display: none; +} +.aa-SourceNoResults { + font-size: 1em; + margin: 0; + padding: calc(16 * 1 * 1px); + padding: var(--aa-spacing); +} + +.aa-List { + list-style: none; + margin: 0; + padding: 0; + position: relative; +} + +.aa-SourceHeader { + margin: calc((16 * 1 * 1px) / 2) 0.5em calc((16 * 1 * 1px) / 2) 0; + margin: calc(calc(16 * 1 * 1px) / 2) 0.5em calc(calc(16 * 1 * 1px) / 2) 0; + margin: var(--aa-spacing-half) 0.5em var(--aa-spacing-half) 0; + padding: 0; + position: relative; + /* Hide empty header*/ + /* Title typography*/ + /* Line separator*/ +} +.aa-SourceHeader:empty { + display: none; +} +.aa-SourceHeaderTitle { + background: var(--bs-body-bg); + color: rgba(var(--bs-primary-rgb), 1.0); + display: inline-block; + font-size: 0.8em; + font-weight: 600; + font-weight: var(--aa-font-weight-semibold); + margin: 0; + padding: 0 calc((16 * 1 * 1px) / 2) 0 0; + padding: 0 calc(calc(16 * 1 * 1px) / 2) 0 0; + padding: 0 var(--aa-spacing-half) 0 0; + position: relative; + z-index: 9999; + z-index: var(--aa-base-z-index); +} + +.aa-SourceHeaderLine { + border-bottom: solid 1px rgba(var(--bs-primary-rgb), 1.0); + display: block; + height: 2px; + left: 0; + margin: 0; + opacity: 0.3; + padding: 0; + position: absolute; + right: 0; + top: calc((16 * 1 * 1px) / 2); + top: calc(calc(16 * 1 * 1px) / 2); + top: var(--aa-spacing-half); + z-index: calc(9999 - 1); + z-index: calc(var(--aa-base-z-index) - 1); +} + +.aa-SourceFooterSeeAll { + background: linear-gradient(180deg, var(--bs-body-bg), rgba(128, 126, 163, 0.14)); + border: 1px solid var(--bs-secondary-color); + border-radius: 5px; + box-shadow: inset 0 0 2px #fff, 0 2px 2px -1px rgba(76, 69, 88, 0.15); + color: inherit; + font-size: 0.95em; + font-weight: 500; + padding: 0.475em 1em 0.6em; + -webkit-text-decoration: none; + text-decoration: none; +} +.aa-SourceFooterSeeAll:focus, .aa-SourceFooterSeeAll:hover { + border: 1px solid rgba(62, 52, 211, 1); + border: 1px solid rgba(var(--bs-primary-rgb), 1); + color: rgba(62, 52, 211, 1); + color: rgba(var(--bs-primary-rgb), 1); +} + +/* ----------------*/ +/* 6. Hit Layout*/ +/* ----------------*/ +.aa-Item { + align-items: center; + border-radius: 3px; + cursor: pointer; + display: grid; + min-height: calc((16 * 1 * 1px) * 2.5); + min-height: calc(calc(16 * 1 * 1px) * 2.5); + min-height: calc(var(--aa-spacing) * 2.5); + padding: calc(((16 * 1 * 1px) / 2) / 2); + padding: calc(calc(calc(16 * 1 * 1px) / 2) / 2); + padding: calc(var(--aa-spacing-half) / 2); + /* When the result is active*/ + /* The result type icon inlined SVG or image*/ + /* wrap hit with url but we don't need to see it*/ + /* Secondary click actions*/ +} +.aa-Item[aria-selected=true] { + background-color: var(--bs-tertiary-bg); +} +.aa-Item[aria-selected=true] .aa-ItemActionButton, +.aa-Item[aria-selected=true] .aa-ActiveOnly { + visibility: visible; +} +.aa-ItemIcon { + align-items: center; + background: var(--bs-body-bg); + border-radius: 3px; + box-shadow: inset 0 0 0 1px rgba(128, 126, 163, 0.3); + box-shadow: inset 0 0 0 1px rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha)); + color: rgba(119, 119, 163, 1); + color: rgba(var(--aa-icon-color-rgb), var(--aa-icon-color-alpha)); + display: flex; + flex-shrink: 0; + font-size: 0.7em; + height: calc(20px + ((16 * 1 * 1px) / 2)); + height: calc(20px + calc(calc(16 * 1 * 1px) / 2)); + height: calc(var(--aa-icon-size) + var(--aa-spacing-half)); + justify-content: center; + overflow: hidden; + stroke-width: 1.6; + stroke-width: var(--aa-icon-stroke-width); + text-align: center; + width: calc(20px + ((16 * 1 * 1px) / 2)); + width: calc(20px + calc(calc(16 * 1 * 1px) / 2)); + width: calc(var(--aa-icon-size) + var(--aa-spacing-half)); +} +.aa-ItemIcon img { + height: auto; + max-height: calc(20px + ((16 * 1 * 1px) / 2) - 8px); + max-height: calc(20px + calc(calc(16 * 1 * 1px) / 2) - 8px); + max-height: calc(var(--aa-icon-size) + var(--aa-spacing-half) - 8px); + max-width: calc(20px + ((16 * 1 * 1px) / 2) - 8px); + max-width: calc(20px + calc(calc(16 * 1 * 1px) / 2) - 8px); + max-width: calc(var(--aa-icon-size) + var(--aa-spacing-half) - 8px); + width: auto; +} +.aa-ItemIcon svg { + height: 20px; + height: var(--aa-icon-size); + width: 20px; + width: var(--aa-icon-size); +} +.aa-ItemIcon--alignTop { + align-self: flex-start; +} + +.aa-ItemIcon--noBorder { + background: none; + box-shadow: none; +} + +.aa-ItemIcon--picture { + height: 96px; + width: 96px; +} +.aa-ItemIcon--picture img { + max-height: 100%; + max-width: 100%; + padding: calc((16 * 1 * 1px) / 2); + padding: calc(calc(16 * 1 * 1px) / 2); + padding: var(--aa-spacing-half); +} + +.aa-ItemContent { + align-items: center; + cursor: pointer; + display: grid; + gap: calc((16 * 1 * 1px) / 2); + gap: calc(calc(16 * 1 * 1px) / 2); + grid-gap: calc((16 * 1 * 1px) / 2); + grid-gap: calc(calc(16 * 1 * 1px) / 2); + grid-gap: var(--aa-spacing-half); + gap: var(--aa-spacing-half); + grid-auto-flow: column; + line-height: 1.25em; + overflow: hidden; +} +.aa-ItemContent:empty { + display: none; +} +.aa-ItemContent mark { + background: var(--bs-highlight-bg); + color: var(--bs-body-color); + font-style: normal; + padding: 0; + font-weight: 700; + font-weight: var(--aa-font-weight-bold); +} +.aa-ItemContent--dual { + display: flex; + flex-direction: column; + justify-content: space-between; + text-align: left; +} +.aa-ItemContent--dual .aa-ItemContentTitle, +.aa-ItemContent--dual .aa-ItemContentSubtitle { + display: block; +} + +.aa-ItemContent--indented { + padding-left: calc(20px + (16 * 1 * 1px)); + padding-left: calc(20px + calc(16 * 1 * 1px)); + padding-left: calc(var(--aa-icon-size) + var(--aa-spacing)); +} + +.aa-ItemContentBody { + display: grid; + gap: calc(((16 * 1 * 1px) / 2) / 2); + gap: calc(calc(calc(16 * 1 * 1px) / 2) / 2); + grid-gap: calc(((16 * 1 * 1px) / 2) / 2); + grid-gap: calc(calc(calc(16 * 1 * 1px) / 2) / 2); + grid-gap: calc(var(--aa-spacing-half) / 2); + gap: calc(var(--aa-spacing-half) / 2); +} + +.aa-ItemContentTitle { + display: inline-block; + margin: 0 0.5em 0 0; + max-width: 100%; + overflow: hidden; + padding: 0; + text-overflow: ellipsis; + white-space: nowrap; +} + +.aa-ItemContentSubtitle { + font-size: 0.92em; +} +.aa-ItemContentSubtitleIcon::before { + border-color: var(--bs-tertiary-color); + border-style: solid; + content: ""; + display: inline-block; + left: 1px; + position: relative; + top: -3px; +} + +.aa-ItemContentSubtitle--inline .aa-ItemContentSubtitleIcon::before { + border-width: 0 0 1.5px; + margin-left: calc((16 * 1 * 1px) / 2); + margin-left: calc(calc(16 * 1 * 1px) / 2); + margin-left: var(--aa-spacing-half); + margin-right: calc(((16 * 1 * 1px) / 2) / 2); + margin-right: calc(calc(calc(16 * 1 * 1px) / 2) / 2); + margin-right: calc(var(--aa-spacing-half) / 2); + width: calc(((16 * 1 * 1px) / 2) + 2px); + width: calc(calc(calc(16 * 1 * 1px) / 2) + 2px); + width: calc(var(--aa-spacing-half) + 2px); +} + +.aa-ItemContentSubtitle--standalone { + align-items: center; + color: var(--bs-body-color); + display: grid; + gap: calc((16 * 1 * 1px) / 2); + gap: calc(calc(16 * 1 * 1px) / 2); + grid-gap: calc((16 * 1 * 1px) / 2); + grid-gap: calc(calc(16 * 1 * 1px) / 2); + grid-gap: var(--aa-spacing-half); + gap: var(--aa-spacing-half); + grid-auto-flow: column; + justify-content: start; +} +.aa-ItemContentSubtitle--standalone .aa-ItemContentSubtitleIcon::before { + border-radius: 0 0 0 3px; + border-width: 0 0 1.5px 1.5px; + height: calc((16 * 1 * 1px) / 2); + height: calc(calc(16 * 1 * 1px) / 2); + height: var(--aa-spacing-half); + width: calc((16 * 1 * 1px) / 2); + width: calc(calc(16 * 1 * 1px) / 2); + width: var(--aa-spacing-half); +} + +.aa-ItemContentSubtitleCategory { + color: var(--bs-secondary-color); + font-weight: 500; +} + +.aa-ItemContentDescription { + color: var(--bs-body-color); + font-size: 0.85em; + max-width: 100%; + overflow-x: hidden; + text-overflow: ellipsis; +} +.aa-ItemContentDescription:empty { + display: none; +} +.aa-ItemContentDescription mark { + background: rgba(245, 223, 77, 0.5); + background: rgba(var(--aa-description-highlight-background-color-rgb), var(--aa-description-highlight-background-color-alpha)); + color: rgba(38, 38, 39, 1); + color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha)); + font-style: normal; + font-weight: 500; + font-weight: var(--aa-font-weight-medium); +} + +.aa-ItemContentDash { + color: var(--bs-secondary-color); + display: none; + opacity: 0.4; +} + +.aa-ItemContentTag { + color: rgba(var(--bs-primary-rgb), 1.0);; + border-radius: 3px; + margin: 0 0.4em 0 0; + padding: 0.08em 0.3em; +} + +.aa-ItemWrapper, +.aa-ItemLink { + align-items: center; + color: inherit; + display: grid; + gap: calc(((16 * 1 * 1px) / 2) / 2); + gap: calc(calc(calc(16 * 1 * 1px) / 2) / 2); + grid-gap: calc(((16 * 1 * 1px) / 2) / 2); + grid-gap: calc(calc(calc(16 * 1 * 1px) / 2) / 2); + grid-gap: calc(var(--aa-spacing-half) / 2); + gap: calc(var(--aa-spacing-half) / 2); + grid-auto-flow: column; + justify-content: space-between; + width: 100%; +} + +.aa-ItemLink { + color: inherit; + -webkit-text-decoration: none; + text-decoration: none; +} + +.aa-ItemActions { + display: grid; + grid-auto-flow: column; + height: 100%; + justify-self: end; + margin: 0 calc((16 * 1 * 1px) / -3); + margin: 0 calc(calc(16 * 1 * 1px) / -3); + margin: 0 calc(var(--aa-spacing) / -3); + padding: 0 2px 0 0; +} + +.aa-ItemActionButton { + align-items: center; + background: none; + border: 0; + color: var(--bs-secondary-color); + cursor: pointer; + display: flex; + flex-shrink: 0; + padding: 0; +} +.aa-ItemActionButton:hover svg, .aa-ItemActionButton:focus svg { + color: var(--bs-body-color); +} +@media (hover: none) and (pointer: coarse) { + .aa-ItemActionButton:hover svg, .aa-ItemActionButton:focus svg { + color: inherit; + } +} +.aa-ItemActionButton svg { + color: var(--bs-secondary-color); + margin: 0; + margin: calc(calc(16 * 1 * 1px) / 3); + margin: calc(var(--aa-spacing) / 3); + stroke-width: 1.6; + stroke-width: var(--aa-icon-stroke-width); + width: 20px; + width: var(--aa-action-icon-size); +} + +.aa-ActiveOnly { + visibility: hidden; +} + +/*----------------*/ +/* 7. Panel Header*/ +/*----------------*/ +.aa-PanelHeader { + align-items: center; + background: var(--bs-primary-bg-subtle); + color: #fff; + display: grid; + height: var(--aa-modal-header-height); + margin: 0; + padding: calc((16 * 1 * 1px) / 2) calc(16 * 1 * 1px); + padding: calc(calc(16 * 1 * 1px) / 2) calc(16 * 1 * 1px); + padding: var(--aa-spacing-half) var(--aa-spacing); + position: relative; +} +.aa-PanelHeader::after { + background-image: linear-gradient(rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); + background-image: linear-gradient(rgba(var(--aa-background-color-rgb), 1), rgba(var(--aa-background-color-rgb), 0)); + bottom: calc(((16 * 1 * 1px) / 2) * -1); + bottom: calc(calc(calc(16 * 1 * 1px) / 2) * -1); + bottom: calc(var(--aa-spacing-half) * -1); + content: ""; + height: calc((16 * 1 * 1px) / 2); + height: calc(calc(16 * 1 * 1px) / 2); + height: var(--aa-spacing-half); + left: 0; + pointer-events: none; + position: absolute; + right: 0; + z-index: 9999; + z-index: var(--aa-base-z-index); +} + +/*----------------*/ +/* 8. Panel Footer*/ +/*----------------*/ +.aa-PanelFooter { + background-color: var(--bs-body-bg); + box-shadow: inset 0 1px 0 var(--bs-dropdown-border-color); + display: flex; + justify-content: space-between; + margin: 0; + padding: calc(16 * 1 * 1px); + padding: var(--aa-spacing); + position: relative; + z-index: 9999; + z-index: var(--aa-base-z-index); +} +.aa-PanelFooter::after { + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(128, 126, 163, 0.6)); + background-image: linear-gradient(rgba(var(--aa-background-color-rgb), 0), rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha))); + content: ""; + height: calc(16 * 1 * 1px); + height: var(--aa-spacing); + left: 0; + opacity: 0.12; + pointer-events: none; + position: absolute; + right: 0; + top: calc((16 * 1 * 1px) * -1); + top: calc(calc(16 * 1 * 1px) * -1); + top: calc(var(--aa-spacing) * -1); + z-index: calc(9999 - 1); + z-index: calc(var(--aa-base-z-index) - 1); +} + +/*----------------*/ +/* 9. Detached Mode*/ +/*----------------*/ +.aa-DetachedContainer { + background: var(--bs-body-bg); + bottom: 0; + box-shadow: 0 0 0 1px rgba(35, 38, 59, 0.1), + 0 6px 16px -4px rgba(35, 38, 59, 0.15); + box-shadow: var(--aa-panel-shadow); + display: flex; + flex-direction: column; + left: 0; + margin: 0; + overflow: hidden; + padding: 0; + position: fixed; + right: 0; + top: 0; + z-index: 9999; + z-index: var(--aa-base-z-index); +} +.aa-DetachedContainer::after { + height: 32px; +} +.aa-DetachedContainer .aa-SourceHeader { + margin: calc((16 * 1 * 1px) / 2) 0 calc((16 * 1 * 1px) / 2) 2px; + margin: calc(calc(16 * 1 * 1px) / 2) 0 calc(calc(16 * 1 * 1px) / 2) 2px; + margin: var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px; +} +.aa-DetachedContainer .aa-Panel { + background-color: var(--bs-body-bg); + border-radius: 0; + box-shadow: none; + flex-grow: 1; + margin: 0; + padding: 0; + position: relative; +} +.aa-DetachedContainer .aa-PanelLayout { + bottom: 0; + box-shadow: none; + left: 0; + margin: 0; + max-height: none; + overflow-y: auto; + position: absolute; + right: 0; + top: 0; + width: 100%; +} +.aa-DetachedFormContainer { + border-bottom: solid 1px rgba(128, 126, 163, 0.3); + border-bottom: solid 1px rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha)); + display: flex; + flex-direction: row; + justify-content: space-between; + margin: 0; + padding: calc((16 * 1 * 1px) / 2); + padding: calc(calc(16 * 1 * 1px) / 2); + padding: var(--aa-spacing-half); +} +.aa-DetachedCancelButton { + background: none; + border: 0; + border-radius: 3px; + color: var(--bs-body-color); + cursor: pointer; + font: inherit; + margin: 0 0 0 calc((16 * 1 * 1px) / 2); + margin: 0 0 0 calc(calc(16 * 1 * 1px) / 2); + margin: 0 0 0 var(--aa-spacing-half); + padding: 0 calc((16 * 1 * 1px) / 2); + padding: 0 calc(calc(16 * 1 * 1px) / 2); + padding: 0 var(--aa-spacing-half); +} +.aa-DetachedCancelButton:hover, .aa-DetachedCancelButton:focus { + box-shadow: inset 0 0 0 1px rgba(128, 126, 163, 0.3); + box-shadow: inset 0 0 0 1px rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha)); +} + +.aa-DetachedContainer--modal { + border-radius: 6px; + bottom: inherit; + height: auto; + margin: 0 auto; + max-width: 680px; + max-width: var(--aa-detached-modal-max-width); + position: absolute; + top: 3%; +} +.aa-DetachedContainer--modal .aa-PanelLayout { + max-height: 500px; + max-height: var(--aa-detached-modal-max-height); + padding-bottom: calc((16 * 1 * 1px) / 2); + padding-bottom: calc(calc(16 * 1 * 1px) / 2); + padding-bottom: var(--aa-spacing-half); + position: static; +} +.aa-DetachedContainer--modal .aa-PanelLayout:empty { + display: none; +} + +/* Search Button*/ +.aa-DetachedSearchButton { + align-items: center; + background-color: var(--bs-body-bg); + border: 1px solid var(--bs-secondary-border-subtle); + border-radius: 3px; + color: var(--bs-secondary-color); + cursor: pointer; + display: flex; + font: inherit; + font-family: inherit; + font-family: var(--aa-font-family); + font-size: calc(16 * 1px); + font-size: var(--aa-font-size); + height: 44px; + height: var(--aa-search-input-height); + margin: 0; + padding: 0 calc(44px / 8); + padding: 0 calc(var(--aa-search-input-height) / 8); + position: relative; + text-align: left; + width: 100%; +} +.aa-DetachedSearchButton:focus { + border-color: var(--bs-primary-border-subtle); + box-shadow: rgba(62, 52, 211, 0.2) 0 0 0 3px, inset rgba(62, 52, 211, 0.2) 0 0 0 2px; + box-shadow: var(--bs-primary-border-subtle) 0 0 0 3px, inset var(--bs-primary-border-subtle) 0 0 0 2px; + outline: currentColor none medium; +} +.aa-DetachedSearchButtonIcon { + align-items: center; + color: rgba(var(--bs-primary-rgb), 1.0); + cursor: auto; + cursor: initial; + display: flex; + flex-shrink: 0; + height: 100%; + justify-content: center; + width: calc(20px + (16 * 1 * 1px)); + width: calc(20px + calc(16 * 1 * 1px)); + width: calc(var(--aa-icon-size) + var(--aa-spacing)); +} + +.aa-DetachedSearchButtonQuery { + color: var(--bs-body-color); + line-height: 1.25em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.aa-DetachedSearchButtonPlaceholder[hidden] { + display: none; +} + +/* Remove scroll on `body`*/ +.aa-Detached { + height: 100vh; + overflow: hidden; +} + +.aa-DetachedOverlay { + background-color: rgba(115, 114, 129, 0.4); + background-color: rgba(var(--aa-overlay-color-rgb), var(--aa-overlay-color-alpha)); + height: 100vh; + left: 0; + margin: 0; + padding: 0; + position: fixed; + right: 0; + top: 0; + z-index: calc(9999 - 1); + z-index: calc(var(--aa-base-z-index) - 1); +} + +/*----------------*/ +/* 10. Gradients*/ +/*----------------*/ +.aa-GradientTop, +.aa-GradientBottom { + height: calc((16 * 1 * 1px) / 2); + height: calc(calc(16 * 1 * 1px) / 2); + height: var(--aa-spacing-half); + left: 0; + pointer-events: none; + position: absolute; + right: 0; + z-index: 9999; + z-index: var(--aa-base-z-index); +} + +.aa-GradientTop { + background-image: linear-gradient(rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); + background-image: linear-gradient(rgba(var(--aa-background-color-rgb), 1), rgba(var(--aa-background-color-rgb), 0)); + top: 0; +} + +.aa-GradientBottom { + background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 1)); + background-image: linear-gradient(rgba(var(--aa-background-color-rgb), 0), rgba(var(--aa-background-color-rgb), 1)); + border-bottom-left-radius: calc((16 * 1 * 1px) / 4); + border-bottom-left-radius: calc(calc(16 * 1 * 1px) / 4); + border-bottom-left-radius: calc(var(--aa-spacing) / 4); + border-bottom-right-radius: calc((16 * 1 * 1px) / 4); + border-bottom-right-radius: calc(calc(16 * 1 * 1px) / 4); + border-bottom-right-radius: calc(var(--aa-spacing) / 4); + bottom: 0; +} + +/*----------------*/ +/* 11. Utilities*/ +/*----------------*/ +@media (hover: none) and (pointer: coarse) { + .aa-DesktopOnly { + display: none; + } +} + +@media (hover: hover) { + .aa-TouchOnly { + display: none; + } +} \ No newline at end of file diff --git a/assets/css/components/ckeditor.css b/assets/css/components/ckeditor.css index f8a682a2..d6b3def4 100644 --- a/assets/css/components/ckeditor.css +++ b/assets/css/components/ckeditor.css @@ -24,9 +24,8 @@ /** Should be the same settings, as in label_style.css */ .ck-html-label .ck-content { font-family: "DejaVu Sans Mono", monospace; - font-size: 12px; + font-size: 12pt; line-height: 1.0; - font-size-adjust: 1.5; } .ck-html-label .ck-content p { diff --git a/assets/css/components/datatables_select_bs5.css b/assets/css/components/datatables_select_bs5.css new file mode 100644 index 00000000..7c717bf4 --- /dev/null +++ b/assets/css/components/datatables_select_bs5.css @@ -0,0 +1,69 @@ +/****************************************************************************************** +* This styles the checkboxes of the select extension exactly like the ones in bootstrap 5 +******************************************************************************************/ + +table.dataTable > tbody > tr > .selected { + background-color: var(--bs-primary-bg-subtle) !important; + color: white; +} +table.dataTable > tbody > tr > .dt-select { + text-align: center; + vertical-align: middle; +} +table.dataTable > thead > tr > .dt-select { + text-align: center; +} +table.dataTable input.dt-select-checkbox { + --bs-form-check-bg: var(--bs-body-bg); + flex-shrink: 0; + width: 1em; + height: 1em; + margin-top: 0.25em; + vertical-align: top; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: var(--bs-form-check-bg); + background-image: var(--bs-form-check-bg-image); + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: var(--bs-border-width) solid var(--bs-border-color); + -webkit-print-color-adjust: exact; + color-adjust: exact; + print-color-adjust: exact; + border-radius: 0.25em; +} + +table.dataTable input.dt-select-checkbox:checked { + background-color: rgb(var(--bs-secondary-rgb)); + border-color: rgb(var(--bs-secondary-rgb)); + --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e"); +} + +table.dataTable input.dt-select-checkbox:indeterminate { + background-color: rgb(var(--bs-secondary-rgb)); + border-color: rgb(var(--bs-secondary-rgb)); + --bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e"); +} + + + + +div.dt-container span.select-info, +div.dt-container span.select-item { + margin-left: 0.5em; +} + + +@media screen and (max-width: 640px) { + div.dt-container span.select-info, + div.dt-container span.select-item { + margin-left: 0; + display: block; + } +} +table.dataTable.table-sm tbody td.select-checkbox::before { + margin-top: -9px; +} + diff --git a/assets/css/email/foundation-emails.css b/assets/css/email/foundation-emails.css index 723728d3..2b62bc09 100644 --- a/assets/css/email/foundation-emails.css +++ b/assets/css/email/foundation-emails.css @@ -1,594 +1,708 @@ -/* - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). +/** + * Copyright (c) 2017 ZURB, inc. * - * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) + * MIT License * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ .wrapper { - width: 100%; } + width: 100%; +} #outlook a { - padding: 0; } + padding: 0; +} body { - width: 100% !important; - min-width: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; - margin: 0; - Margin: 0; - padding: 0; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; } + width: 100% !important; + min-width: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + margin: 0; + Margin: 0; + padding: 0; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} .ExternalClass { - width: 100%; } - .ExternalClass, - .ExternalClass p, - .ExternalClass span, - .ExternalClass font, - .ExternalClass td, - .ExternalClass div { - line-height: 100%; } + width: 100%; +} + +.ExternalClass, +.ExternalClass p, +.ExternalClass span, +.ExternalClass font, +.ExternalClass td, +.ExternalClass div { + line-height: 100%; +} #backgroundTable { - margin: 0; - Margin: 0; - padding: 0; - width: 100% !important; - line-height: 100% !important; } + margin: 0; + Margin: 0; + padding: 0; + width: 100% !important; + line-height: 100% !important; +} img { - outline: none; - text-decoration: none; - -ms-interpolation-mode: bicubic; - width: auto; - max-width: 100%; - clear: both; - display: block; } + outline: none; + text-decoration: none; + -ms-interpolation-mode: bicubic; + width: auto; + max-width: 100%; + clear: both; + display: block; +} center { - width: 100%; - min-width: 580px; } + width: 100%; + min-width: 580px; +} a img { - border: none; } + border: none; +} p { - margin: 0 0 0 10px; - Margin: 0 0 0 10px; } + margin: 0 0 0 10px; + Margin: 0 0 0 10px; +} table { - border-spacing: 0; - border-collapse: collapse; } + border-spacing: 0; + border-collapse: collapse; +} td { - word-wrap: break-word; - -webkit-hyphens: auto; - -moz-hyphens: auto; - hyphens: auto; - border-collapse: collapse !important; } + word-wrap: break-word; + -webkit-hyphens: auto; + -moz-hyphens: auto; + hyphens: auto; + border-collapse: collapse !important; +} table, tr, td { - padding: 0; - vertical-align: top; - text-align: left; } + padding: 0; + vertical-align: top; + text-align: left; +} @media only screen { - html { - min-height: 100%; - background: #f3f3f3; } } + html { + min-height: 100%; + background: #f3f3f3; + } +} table.body { - background: #f3f3f3; - height: 100%; - width: 100%; } + background: #f3f3f3; + height: 100%; + width: 100%; +} table.container { - background: #fefefe; - width: 580px; - margin: 0 auto; - Margin: 0 auto; - text-align: inherit; } + background: #fefefe; + width: 580px; + margin: 0 auto; + Margin: 0 auto; + text-align: inherit; +} table.row { - padding: 0; - width: 100%; - position: relative; } + padding: 0; + width: 100%; + position: relative; +} table.spacer { - width: 100%; } - table.spacer td { - mso-line-height-rule: exactly; } + width: 100%; +} + +table.spacer td { + mso-line-height-rule: exactly; +} table.container table.row { - display: table; } + display: table; +} td.columns, td.column, th.columns, th.column { - margin: 0 auto; - Margin: 0 auto; - padding-left: 16px; - padding-bottom: 16px; } - td.columns .column, - td.columns .columns, - td.column .column, - td.column .columns, - th.columns .column, - th.columns .columns, - th.column .column, - th.column .columns { + margin: 0 auto; + Margin: 0 auto; + padding-left: 16px; + padding-bottom: 16px; +} + +td.columns .column, +td.columns .columns, +td.column .column, +td.column .columns, +th.columns .column, +th.columns .columns, +th.column .column, +th.column .columns { padding-left: 0 !important; - padding-right: 0 !important; } - td.columns .column center, - td.columns .columns center, - td.column .column center, - td.column .columns center, - th.columns .column center, - th.columns .columns center, - th.column .column center, - th.column .columns center { - min-width: none !important; } + padding-right: 0 !important; +} + +td.columns .column center, +td.columns .columns center, +td.column .column center, +td.column .columns center, +th.columns .column center, +th.columns .columns center, +th.column .column center, +th.column .columns center { + min-width: none !important; +} td.columns.last, td.column.last, th.columns.last, th.column.last { - padding-right: 16px; } + padding-right: 16px; +} td.columns table:not(.button), td.column table:not(.button), th.columns table:not(.button), th.column table:not(.button) { - width: 100%; } + width: 100%; +} td.large-1, th.large-1 { - width: 32.33333px; - padding-left: 8px; - padding-right: 8px; } + width: 32.33333px; + padding-left: 8px; + padding-right: 8px; +} td.large-1.first, th.large-1.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-1.last, th.large-1.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-1, .collapse > tbody > tr > th.large-1 { - padding-right: 0; - padding-left: 0; - width: 48.33333px; } + padding-right: 0; + padding-left: 0; + width: 48.33333px; +} .collapse td.large-1.first, .collapse th.large-1.first, .collapse td.large-1.last, .collapse th.large-1.last { - width: 56.33333px; } + width: 56.33333px; +} td.large-1 center, th.large-1 center { - min-width: 0.33333px; } + min-width: 0.33333px; +} .body .columns td.large-1, .body .column td.large-1, .body .columns th.large-1, .body .column th.large-1 { - width: 8.33333%; } + width: 8.33333%; +} td.large-2, th.large-2 { - width: 80.66667px; - padding-left: 8px; - padding-right: 8px; } + width: 80.66667px; + padding-left: 8px; + padding-right: 8px; +} td.large-2.first, th.large-2.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-2.last, th.large-2.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-2, .collapse > tbody > tr > th.large-2 { - padding-right: 0; - padding-left: 0; - width: 96.66667px; } + padding-right: 0; + padding-left: 0; + width: 96.66667px; +} .collapse td.large-2.first, .collapse th.large-2.first, .collapse td.large-2.last, .collapse th.large-2.last { - width: 104.66667px; } + width: 104.66667px; +} td.large-2 center, th.large-2 center { - min-width: 48.66667px; } + min-width: 48.66667px; +} .body .columns td.large-2, .body .column td.large-2, .body .columns th.large-2, .body .column th.large-2 { - width: 16.66667%; } + width: 16.66667%; +} td.large-3, th.large-3 { - width: 129px; - padding-left: 8px; - padding-right: 8px; } + width: 129px; + padding-left: 8px; + padding-right: 8px; +} td.large-3.first, th.large-3.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-3.last, th.large-3.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-3, .collapse > tbody > tr > th.large-3 { - padding-right: 0; - padding-left: 0; - width: 145px; } + padding-right: 0; + padding-left: 0; + width: 145px; +} .collapse td.large-3.first, .collapse th.large-3.first, .collapse td.large-3.last, .collapse th.large-3.last { - width: 153px; } + width: 153px; +} td.large-3 center, th.large-3 center { - min-width: 97px; } + min-width: 97px; +} .body .columns td.large-3, .body .column td.large-3, .body .columns th.large-3, .body .column th.large-3 { - width: 25%; } + width: 25%; +} td.large-4, th.large-4 { - width: 177.33333px; - padding-left: 8px; - padding-right: 8px; } + width: 177.33333px; + padding-left: 8px; + padding-right: 8px; +} td.large-4.first, th.large-4.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-4.last, th.large-4.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-4, .collapse > tbody > tr > th.large-4 { - padding-right: 0; - padding-left: 0; - width: 193.33333px; } + padding-right: 0; + padding-left: 0; + width: 193.33333px; +} .collapse td.large-4.first, .collapse th.large-4.first, .collapse td.large-4.last, .collapse th.large-4.last { - width: 201.33333px; } + width: 201.33333px; +} td.large-4 center, th.large-4 center { - min-width: 145.33333px; } + min-width: 145.33333px; +} .body .columns td.large-4, .body .column td.large-4, .body .columns th.large-4, .body .column th.large-4 { - width: 33.33333%; } + width: 33.33333%; +} td.large-5, th.large-5 { - width: 225.66667px; - padding-left: 8px; - padding-right: 8px; } + width: 225.66667px; + padding-left: 8px; + padding-right: 8px; +} td.large-5.first, th.large-5.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-5.last, th.large-5.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-5, .collapse > tbody > tr > th.large-5 { - padding-right: 0; - padding-left: 0; - width: 241.66667px; } + padding-right: 0; + padding-left: 0; + width: 241.66667px; +} .collapse td.large-5.first, .collapse th.large-5.first, .collapse td.large-5.last, .collapse th.large-5.last { - width: 249.66667px; } + width: 249.66667px; +} td.large-5 center, th.large-5 center { - min-width: 193.66667px; } + min-width: 193.66667px; +} .body .columns td.large-5, .body .column td.large-5, .body .columns th.large-5, .body .column th.large-5 { - width: 41.66667%; } + width: 41.66667%; +} td.large-6, th.large-6 { - width: 274px; - padding-left: 8px; - padding-right: 8px; } + width: 274px; + padding-left: 8px; + padding-right: 8px; +} td.large-6.first, th.large-6.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-6.last, th.large-6.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-6, .collapse > tbody > tr > th.large-6 { - padding-right: 0; - padding-left: 0; - width: 290px; } + padding-right: 0; + padding-left: 0; + width: 290px; +} .collapse td.large-6.first, .collapse th.large-6.first, .collapse td.large-6.last, .collapse th.large-6.last { - width: 298px; } + width: 298px; +} td.large-6 center, th.large-6 center { - min-width: 242px; } + min-width: 242px; +} .body .columns td.large-6, .body .column td.large-6, .body .columns th.large-6, .body .column th.large-6 { - width: 50%; } + width: 50%; +} td.large-7, th.large-7 { - width: 322.33333px; - padding-left: 8px; - padding-right: 8px; } + width: 322.33333px; + padding-left: 8px; + padding-right: 8px; +} td.large-7.first, th.large-7.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-7.last, th.large-7.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-7, .collapse > tbody > tr > th.large-7 { - padding-right: 0; - padding-left: 0; - width: 338.33333px; } + padding-right: 0; + padding-left: 0; + width: 338.33333px; +} .collapse td.large-7.first, .collapse th.large-7.first, .collapse td.large-7.last, .collapse th.large-7.last { - width: 346.33333px; } + width: 346.33333px; +} td.large-7 center, th.large-7 center { - min-width: 290.33333px; } + min-width: 290.33333px; +} .body .columns td.large-7, .body .column td.large-7, .body .columns th.large-7, .body .column th.large-7 { - width: 58.33333%; } + width: 58.33333%; +} td.large-8, th.large-8 { - width: 370.66667px; - padding-left: 8px; - padding-right: 8px; } + width: 370.66667px; + padding-left: 8px; + padding-right: 8px; +} td.large-8.first, th.large-8.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-8.last, th.large-8.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-8, .collapse > tbody > tr > th.large-8 { - padding-right: 0; - padding-left: 0; - width: 386.66667px; } + padding-right: 0; + padding-left: 0; + width: 386.66667px; +} .collapse td.large-8.first, .collapse th.large-8.first, .collapse td.large-8.last, .collapse th.large-8.last { - width: 394.66667px; } + width: 394.66667px; +} td.large-8 center, th.large-8 center { - min-width: 338.66667px; } + min-width: 338.66667px; +} .body .columns td.large-8, .body .column td.large-8, .body .columns th.large-8, .body .column th.large-8 { - width: 66.66667%; } + width: 66.66667%; +} td.large-9, th.large-9 { - width: 419px; - padding-left: 8px; - padding-right: 8px; } + width: 419px; + padding-left: 8px; + padding-right: 8px; +} td.large-9.first, th.large-9.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-9.last, th.large-9.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-9, .collapse > tbody > tr > th.large-9 { - padding-right: 0; - padding-left: 0; - width: 435px; } + padding-right: 0; + padding-left: 0; + width: 435px; +} .collapse td.large-9.first, .collapse th.large-9.first, .collapse td.large-9.last, .collapse th.large-9.last { - width: 443px; } + width: 443px; +} td.large-9 center, th.large-9 center { - min-width: 387px; } + min-width: 387px; +} .body .columns td.large-9, .body .column td.large-9, .body .columns th.large-9, .body .column th.large-9 { - width: 75%; } + width: 75%; +} td.large-10, th.large-10 { - width: 467.33333px; - padding-left: 8px; - padding-right: 8px; } + width: 467.33333px; + padding-left: 8px; + padding-right: 8px; +} td.large-10.first, th.large-10.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-10.last, th.large-10.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-10, .collapse > tbody > tr > th.large-10 { - padding-right: 0; - padding-left: 0; - width: 483.33333px; } + padding-right: 0; + padding-left: 0; + width: 483.33333px; +} .collapse td.large-10.first, .collapse th.large-10.first, .collapse td.large-10.last, .collapse th.large-10.last { - width: 491.33333px; } + width: 491.33333px; +} td.large-10 center, th.large-10 center { - min-width: 435.33333px; } + min-width: 435.33333px; +} .body .columns td.large-10, .body .column td.large-10, .body .columns th.large-10, .body .column th.large-10 { - width: 83.33333%; } + width: 83.33333%; +} td.large-11, th.large-11 { - width: 515.66667px; - padding-left: 8px; - padding-right: 8px; } + width: 515.66667px; + padding-left: 8px; + padding-right: 8px; +} td.large-11.first, th.large-11.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-11.last, th.large-11.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-11, .collapse > tbody > tr > th.large-11 { - padding-right: 0; - padding-left: 0; - width: 531.66667px; } + padding-right: 0; + padding-left: 0; + width: 531.66667px; +} .collapse td.large-11.first, .collapse th.large-11.first, .collapse td.large-11.last, .collapse th.large-11.last { - width: 539.66667px; } + width: 539.66667px; +} td.large-11 center, th.large-11 center { - min-width: 483.66667px; } + min-width: 483.66667px; +} .body .columns td.large-11, .body .column td.large-11, .body .columns th.large-11, .body .column th.large-11 { - width: 91.66667%; } + width: 91.66667%; +} td.large-12, th.large-12 { - width: 564px; - padding-left: 8px; - padding-right: 8px; } + width: 564px; + padding-left: 8px; + padding-right: 8px; +} td.large-12.first, th.large-12.first { - padding-left: 16px; } + padding-left: 16px; +} td.large-12.last, th.large-12.last { - padding-right: 16px; } + padding-right: 16px; +} .collapse > tbody > tr > td.large-12, .collapse > tbody > tr > th.large-12 { - padding-right: 0; - padding-left: 0; - width: 580px; } + padding-right: 0; + padding-left: 0; + width: 580px; +} .collapse td.large-12.first, .collapse th.large-12.first, .collapse td.large-12.last, .collapse th.large-12.last { - width: 588px; } + width: 588px; +} td.large-12 center, th.large-12 center { - min-width: 532px; } + min-width: 532px; +} .body .columns td.large-12, .body .column td.large-12, .body .columns th.large-12, .body .column th.large-12 { - width: 100%; } + width: 100%; +} td.large-offset-1, td.large-offset-1.first, @@ -596,7 +710,8 @@ td.large-offset-1.last, th.large-offset-1, th.large-offset-1.first, th.large-offset-1.last { - padding-left: 64.33333px; } + padding-left: 64.33333px; +} td.large-offset-2, td.large-offset-2.first, @@ -604,7 +719,8 @@ td.large-offset-2.last, th.large-offset-2, th.large-offset-2.first, th.large-offset-2.last { - padding-left: 112.66667px; } + padding-left: 112.66667px; +} td.large-offset-3, td.large-offset-3.first, @@ -612,7 +728,8 @@ td.large-offset-3.last, th.large-offset-3, th.large-offset-3.first, th.large-offset-3.last { - padding-left: 161px; } + padding-left: 161px; +} td.large-offset-4, td.large-offset-4.first, @@ -620,7 +737,8 @@ td.large-offset-4.last, th.large-offset-4, th.large-offset-4.first, th.large-offset-4.last { - padding-left: 209.33333px; } + padding-left: 209.33333px; +} td.large-offset-5, td.large-offset-5.first, @@ -628,7 +746,8 @@ td.large-offset-5.last, th.large-offset-5, th.large-offset-5.first, th.large-offset-5.last { - padding-left: 257.66667px; } + padding-left: 257.66667px; +} td.large-offset-6, td.large-offset-6.first, @@ -636,7 +755,8 @@ td.large-offset-6.last, th.large-offset-6, th.large-offset-6.first, th.large-offset-6.last { - padding-left: 306px; } + padding-left: 306px; +} td.large-offset-7, td.large-offset-7.first, @@ -644,7 +764,8 @@ td.large-offset-7.last, th.large-offset-7, th.large-offset-7.first, th.large-offset-7.last { - padding-left: 354.33333px; } + padding-left: 354.33333px; +} td.large-offset-8, td.large-offset-8.first, @@ -652,7 +773,8 @@ td.large-offset-8.last, th.large-offset-8, th.large-offset-8.first, th.large-offset-8.last { - padding-left: 402.66667px; } + padding-left: 402.66667px; +} td.large-offset-9, td.large-offset-9.first, @@ -660,7 +782,8 @@ td.large-offset-9.last, th.large-offset-9, th.large-offset-9.first, th.large-offset-9.last { - padding-left: 451px; } + padding-left: 451px; +} td.large-offset-10, td.large-offset-10.first, @@ -668,7 +791,8 @@ td.large-offset-10.last, th.large-offset-10, th.large-offset-10.first, th.large-offset-10.last { - padding-left: 499.33333px; } + padding-left: 499.33333px; +} td.large-offset-11, td.large-offset-11.first, @@ -676,45 +800,58 @@ td.large-offset-11.last, th.large-offset-11, th.large-offset-11.first, th.large-offset-11.last { - padding-left: 547.66667px; } + padding-left: 547.66667px; +} td.expander, th.expander { - visibility: hidden; - width: 0; - padding: 0 !important; } + visibility: hidden; + width: 0; + padding: 0 !important; +} table.container.radius { - border-radius: 0; - border-collapse: separate; } + border-radius: 0; + border-collapse: separate; +} .block-grid { - width: 100%; - max-width: 580px; } - .block-grid td { + width: 100%; + max-width: 580px; +} + +.block-grid td { display: inline-block; - padding: 8px; } + padding: 8px; +} .up-2 td { - width: 274px !important; } + width: 274px !important; +} .up-3 td { - width: 177px !important; } + width: 177px !important; +} .up-4 td { - width: 129px !important; } + width: 129px !important; +} .up-5 td { - width: 100px !important; } + width: 100px !important; +} .up-6 td { - width: 80px !important; } + width: 80px !important; +} .up-7 td { - width: 66px !important; } + width: 66px !important; +} .up-8 td { - width: 56px !important; } + width: 56px !important; +} table.text-center, th.text-center, @@ -727,7 +864,8 @@ h5.text-center, h6.text-center, p.text-center, span.text-center { - text-align: center; } + text-align: center; +} table.text-left, th.text-left, @@ -740,7 +878,8 @@ h5.text-left, h6.text-left, p.text-left, span.text-left { - text-align: left; } + text-align: left; +} table.text-right, th.text-right, @@ -753,85 +892,110 @@ h5.text-right, h6.text-right, p.text-right, span.text-right { - text-align: right; } + text-align: right; +} span.text-center { - display: block; - width: 100%; - text-align: center; } + display: block; + width: 100%; + text-align: center; +} @media only screen and (max-width: 596px) { - .small-float-center { - margin: 0 auto !important; - float: none !important; - text-align: center !important; } - .small-text-center { - text-align: center !important; } - .small-text-left { - text-align: left !important; } - .small-text-right { - text-align: right !important; } } + .small-float-center { + margin: 0 auto !important; + float: none !important; + text-align: center !important; + } + + .small-text-center { + text-align: center !important; + } + + .small-text-left { + text-align: left !important; + } + + .small-text-right { + text-align: right !important; + } +} img.float-left { - float: left; - text-align: left; } + float: left; + text-align: left; +} img.float-right { - float: right; - text-align: right; } + float: right; + text-align: right; +} img.float-center, img.text-center { - margin: 0 auto; - Margin: 0 auto; - float: none; - text-align: center; } + margin: 0 auto; + Margin: 0 auto; + float: none; + text-align: center; +} table.float-center, td.float-center, th.float-center { - margin: 0 auto; - Margin: 0 auto; - float: none; - text-align: center; } + margin: 0 auto; + Margin: 0 auto; + float: none; + text-align: center; +} .hide-for-large { - display: none !important; - mso-hide: all; - overflow: hidden; - max-height: 0; - font-size: 0; - width: 0; - line-height: 0; } - @media only screen and (max-width: 596px) { + display: none !important; + mso-hide: all; + overflow: hidden; + max-height: 0; + font-size: 0; + width: 0; + line-height: 0; +} + +@media only screen and (max-width: 596px) { .hide-for-large { - display: block !important; - width: auto !important; - overflow: visible !important; - max-height: none !important; - font-size: inherit !important; - line-height: inherit !important; } } + display: block !important; + width: auto !important; + overflow: visible !important; + max-height: none !important; + font-size: inherit !important; + line-height: inherit !important; + } +} table.body table.container .hide-for-large * { - mso-hide: all; } - -@media only screen and (max-width: 596px) { - table.body table.container .hide-for-large, - table.body table.container .row.hide-for-large { - display: table !important; - width: 100% !important; } } - -@media only screen and (max-width: 596px) { - table.body table.container .callout-inner.hide-for-large { - display: table-cell !important; - width: 100% !important; } } - -@media only screen and (max-width: 596px) { - table.body table.container .show-for-large { - display: none !important; - width: 0; mso-hide: all; - overflow: hidden; } } +} + +@media only screen and (max-width: 596px) { + table.body table.container .hide-for-large, + table.body table.container .row.hide-for-large { + display: table !important; + width: 100% !important; + } +} + +@media only screen and (max-width: 596px) { + table.body table.container .callout-inner.hide-for-large { + display: table-cell !important; + width: 100% !important; + } +} + +@media only screen and (max-width: 596px) { + table.body table.container .show-for-large { + display: none !important; + width: 0; + mso-hide: all; + overflow: hidden; + } +} body, table.body, @@ -845,14 +1009,15 @@ p, td, th, a { - color: #0a0a0a; - font-family: Helvetica, Arial, sans-serif; - font-weight: normal; - padding: 0; - margin: 0; - Margin: 0; - text-align: left; - line-height: 1.3; } + color: #0a0a0a; + font-family: Helvetica, Arial, sans-serif; + font-weight: normal; + padding: 0; + margin: 0; + Margin: 0; + text-align: left; + line-height: 1.3; +} h1, h2, @@ -860,67 +1025,88 @@ h3, h4, h5, h6 { - color: inherit; - word-wrap: normal; - font-family: Helvetica, Arial, sans-serif; - font-weight: normal; - margin-bottom: 10px; - Margin-bottom: 10px; } + color: inherit; + word-wrap: normal; + font-family: Helvetica, Arial, sans-serif; + font-weight: normal; + margin-bottom: 10px; + Margin-bottom: 10px; +} h1 { - font-size: 34px; } + font-size: 34px; +} h2 { - font-size: 30px; } + font-size: 30px; +} h3 { - font-size: 28px; } + font-size: 28px; +} h4 { - font-size: 24px; } + font-size: 24px; +} h5 { - font-size: 20px; } + font-size: 20px; +} h6 { - font-size: 18px; } + font-size: 18px; +} body, table.body, p, td, th { - font-size: 16px; - line-height: 1.3; } + font-size: 16px; + line-height: 1.3; +} p { - margin-bottom: 10px; - Margin-bottom: 10px; } - p.lead { + margin-bottom: 10px; + Margin-bottom: 10px; +} + +p.lead { font-size: 20px; - line-height: 1.6; } - p.subheader { + line-height: 1.6; +} + +p.subheader { margin-top: 4px; margin-bottom: 8px; Margin-top: 4px; Margin-bottom: 8px; font-weight: normal; line-height: 1.4; - color: #8a8a8a; } + color: #8a8a8a; +} small { - font-size: 80%; - color: #cacaca; } + font-size: 80%; + color: #cacaca; +} a { - color: #2199e8; - text-decoration: none; } - a:hover { - color: #147dc2; } - a:active { - color: #147dc2; } - a:visited { - color: #2199e8; } + color: #2199e8; + text-decoration: none; +} + +a:hover { + color: #147dc2; +} + +a:active { + color: #147dc2; +} + +a:visited { + color: #2199e8; +} h1 a, h1 a:visited, @@ -934,24 +1120,34 @@ h5 a, h5 a:visited, h6 a, h6 a:visited { - color: #2199e8; } + color: #2199e8; +} pre { - background: #f3f3f3; - margin: 30px 0; - Margin: 30px 0; } - pre code { - color: #cacaca; } - pre code span.callout { - color: #8a8a8a; - font-weight: bold; } - pre code span.callout-strong { - color: #ff6908; - font-weight: bold; } + background: #f3f3f3; + margin: 30px 0; + Margin: 30px 0; +} + +pre code { + color: #cacaca; +} + +pre code span.callout { + color: #8a8a8a; + font-weight: bold; +} + +pre code span.callout-strong { + color: #ff6908; + font-weight: bold; +} table.hr { - width: 100%; } - table.hr th { + width: 100%; +} + +table.hr th { height: 0; max-width: 580px; border-top: 0; @@ -960,52 +1156,66 @@ table.hr { border-left: 0; margin: 20px auto; Margin: 20px auto; - clear: both; } + clear: both; +} .stat { - font-size: 40px; - line-height: 1; } - p + .stat { + font-size: 40px; + line-height: 1; +} + +p + .stat { margin-top: -16px; - Margin-top: -16px; } + Margin-top: -16px; +} span.preheader { - display: none !important; - visibility: hidden; - mso-hide: all !important; - font-size: 1px; - color: #f3f3f3; - line-height: 1px; - max-height: 0px; - max-width: 0px; - opacity: 0; - overflow: hidden; } + display: none !important; + visibility: hidden; + mso-hide: all !important; + font-size: 1px; + color: #f3f3f3; + line-height: 1px; + max-height: 0px; + max-width: 0px; + opacity: 0; + overflow: hidden; +} table.button { - width: auto; - margin: 0 0 16px 0; - Margin: 0 0 16px 0; } - table.button table td { + width: auto; + margin: 0 0 16px 0; + Margin: 0 0 16px 0; +} + +table.button table td { text-align: left; color: #fefefe; background: #2199e8; - border: 2px solid #2199e8; } - table.button table td a { - font-family: Helvetica, Arial, sans-serif; - font-size: 16px; - font-weight: bold; - color: #fefefe; - text-decoration: none; - display: inline-block; - padding: 8px 16px 8px 16px; - border: 0 solid #2199e8; - border-radius: 3px; } - table.button.radius table td { + border: 2px solid #2199e8; +} + +table.button table td a { + font-family: Helvetica, Arial, sans-serif; + font-size: 16px; + font-weight: bold; + color: #fefefe; + text-decoration: none; + display: inline-block; + padding: 8px 16px 8px 16px; + border: 0 solid #2199e8; border-radius: 3px; - border: none; } - table.button.rounded table td { +} + +table.button.radius table td { + border-radius: 3px; + border: none; +} + +table.button.rounded table td { border-radius: 500px; - border: none; } + border: none; +} table.button:hover table tr td a, table.button:active table tr td a, @@ -1019,349 +1229,491 @@ table.button.small table tr td a:visited, table.button.large:hover table tr td a, table.button.large:active table tr td a, table.button.large table tr td a:visited { - color: #fefefe; } + color: #fefefe; +} table.button.tiny table td, table.button.tiny table a { - padding: 4px 8px 4px 8px; } + padding: 4px 8px 4px 8px; +} table.button.tiny table a { - font-size: 10px; - font-weight: normal; } + font-size: 10px; + font-weight: normal; +} table.button.small table td, table.button.small table a { - padding: 5px 10px 5px 10px; - font-size: 12px; } + padding: 5px 10px 5px 10px; + font-size: 12px; +} table.button.large table a { - padding: 10px 20px 10px 20px; - font-size: 20px; } + padding: 10px 20px 10px 20px; + font-size: 20px; +} table.button.expand, table.button.expanded { - width: 100% !important; } - table.button.expand table, - table.button.expanded table { - width: 100%; } - table.button.expand table a, - table.button.expanded table a { - text-align: center; - width: 100%; - padding-left: 0; - padding-right: 0; } - table.button.expand center, - table.button.expanded center { - min-width: 0; } + width: 100% !important; +} + +table.button.expand table, +table.button.expanded table { + width: 100%; +} + +table.button.expand table a, +table.button.expanded table a { + text-align: center; + width: 100%; + padding-left: 0; + padding-right: 0; +} + +table.button.expand center, +table.button.expanded center { + min-width: 0; +} table.button:hover table td, table.button:visited table td, table.button:active table td { - background: #147dc2; - color: #fefefe; } + background: #147dc2; + color: #fefefe; +} table.button:hover table a, table.button:visited table a, table.button:active table a { - border: 0 solid #147dc2; } + border: 0 solid #147dc2; +} table.button.secondary table td { - background: #777777; - color: #fefefe; - border: 0px solid #777777; } + background: #777777; + color: #fefefe; + border: 0px solid #777777; +} table.button.secondary table a { - color: #fefefe; - border: 0 solid #777777; } + color: #fefefe; + border: 0 solid #777777; +} table.button.secondary:hover table td { - background: #919191; - color: #fefefe; } + background: #919191; + color: #fefefe; +} table.button.secondary:hover table a { - border: 0 solid #919191; } + border: 0 solid #919191; +} table.button.secondary:hover table td a { - color: #fefefe; } + color: #fefefe; +} table.button.secondary:active table td a { - color: #fefefe; } + color: #fefefe; +} table.button.secondary table td a:visited { - color: #fefefe; } + color: #fefefe; +} table.button.success table td { - background: #3adb76; - border: 0px solid #3adb76; } + background: #3adb76; + border: 0px solid #3adb76; +} table.button.success table a { - border: 0 solid #3adb76; } + border: 0 solid #3adb76; +} table.button.success:hover table td { - background: #23bf5d; } + background: #23bf5d; +} table.button.success:hover table a { - border: 0 solid #23bf5d; } + border: 0 solid #23bf5d; +} table.button.alert table td { - background: #ec5840; - border: 0px solid #ec5840; } + background: #ec5840; + border: 0px solid #ec5840; +} table.button.alert table a { - border: 0 solid #ec5840; } + border: 0 solid #ec5840; +} table.button.alert:hover table td { - background: #e23317; } + background: #e23317; +} table.button.alert:hover table a { - border: 0 solid #e23317; } + border: 0 solid #e23317; +} table.button.warning table td { - background: #ffae00; - border: 0px solid #ffae00; } + background: #ffae00; + border: 0px solid #ffae00; +} table.button.warning table a { - border: 0px solid #ffae00; } + border: 0px solid #ffae00; +} table.button.warning:hover table td { - background: #cc8b00; } + background: #cc8b00; +} table.button.warning:hover table a { - border: 0px solid #cc8b00; } + border: 0px solid #cc8b00; +} table.callout { - margin-bottom: 16px; - Margin-bottom: 16px; } + margin-bottom: 16px; + Margin-bottom: 16px; +} th.callout-inner { - width: 100%; - border: 1px solid #cbcbcb; - padding: 10px; - background: #fefefe; } - th.callout-inner.primary { + width: 100%; + border: 1px solid #cbcbcb; + padding: 10px; + background: #fefefe; +} + +th.callout-inner.primary { background: #def0fc; border: 1px solid #444444; - color: #0a0a0a; } - th.callout-inner.secondary { + color: #0a0a0a; +} + +th.callout-inner.secondary { background: #ebebeb; border: 1px solid #444444; - color: #0a0a0a; } - th.callout-inner.success { + color: #0a0a0a; +} + +th.callout-inner.success { background: #e1faea; border: 1px solid #1b9448; - color: #fefefe; } - th.callout-inner.warning { + color: #fefefe; +} + +th.callout-inner.warning { background: #fff3d9; border: 1px solid #996800; - color: #fefefe; } - th.callout-inner.alert { + color: #fefefe; +} + +th.callout-inner.alert { background: #fce6e2; border: 1px solid #b42912; - color: #fefefe; } + color: #fefefe; +} .thumbnail { - border: solid 4px #fefefe; - box-shadow: 0 0 0 1px rgba(10, 10, 10, 0.2); - display: inline-block; - line-height: 0; - max-width: 100%; - transition: box-shadow 200ms ease-out; - border-radius: 3px; - margin-bottom: 16px; } - .thumbnail:hover, .thumbnail:focus { - box-shadow: 0 0 6px 1px rgba(33, 153, 232, 0.5); } + border: solid 4px #fefefe; + box-shadow: 0 0 0 1px rgba(10, 10, 10, 0.2); + display: inline-block; + line-height: 0; + max-width: 100%; + transition: box-shadow 200ms ease-out; + border-radius: 3px; + margin-bottom: 16px; +} + +.thumbnail:hover, .thumbnail:focus { + box-shadow: 0 0 6px 1px rgba(33, 153, 232, 0.5); +} table.menu { - width: 580px; } - table.menu td.menu-item, - table.menu th.menu-item { + width: 580px; +} + +table.menu td.menu-item, +table.menu th.menu-item { padding: 10px; - padding-right: 10px; } - table.menu td.menu-item a, - table.menu th.menu-item a { - color: #2199e8; } + padding-right: 10px; +} + +table.menu td.menu-item a, +table.menu th.menu-item a { + color: #2199e8; +} table.menu.vertical td.menu-item, table.menu.vertical th.menu-item { - padding: 10px; - padding-right: 0; - display: block; } - table.menu.vertical td.menu-item a, - table.menu.vertical th.menu-item a { - width: 100%; } + padding: 10px; + padding-right: 0; + display: block; +} + +table.menu.vertical td.menu-item a, +table.menu.vertical th.menu-item a { + width: 100%; +} table.menu.vertical td.menu-item table.menu.vertical td.menu-item, table.menu.vertical td.menu-item table.menu.vertical th.menu-item, table.menu.vertical th.menu-item table.menu.vertical td.menu-item, table.menu.vertical th.menu-item table.menu.vertical th.menu-item { - padding-left: 10px; } + padding-left: 10px; +} table.menu.text-center a { - text-align: center; } + text-align: center; +} .menu[align="center"] { - width: auto !important; } + width: auto !important; +} body.outlook p { - display: inline !important; } + display: inline !important; +} @media only screen and (max-width: 596px) { - table.body img { - width: auto; - height: auto; } - table.body center { - min-width: 0 !important; } - table.body .container { - width: 95% !important; } - table.body .columns, - table.body .column { - height: auto !important; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - padding-left: 16px !important; - padding-right: 16px !important; } + table.body img { + width: auto; + height: auto; + } + + table.body center { + min-width: 0 !important; + } + + table.body .container { + width: 95% !important; + } + + table.body .columns, + table.body .column { + height: auto !important; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding-left: 16px !important; + padding-right: 16px !important; + } + table.body .columns .column, table.body .columns .columns, table.body .column .column, table.body .column .columns { - padding-left: 0 !important; - padding-right: 0 !important; } - table.body .collapse .columns, - table.body .collapse .column { - padding-left: 0 !important; - padding-right: 0 !important; } - td.small-1, - th.small-1 { - display: inline-block !important; - width: 8.33333% !important; } - td.small-2, - th.small-2 { - display: inline-block !important; - width: 16.66667% !important; } - td.small-3, - th.small-3 { - display: inline-block !important; - width: 25% !important; } - td.small-4, - th.small-4 { - display: inline-block !important; - width: 33.33333% !important; } - td.small-5, - th.small-5 { - display: inline-block !important; - width: 41.66667% !important; } - td.small-6, - th.small-6 { - display: inline-block !important; - width: 50% !important; } - td.small-7, - th.small-7 { - display: inline-block !important; - width: 58.33333% !important; } - td.small-8, - th.small-8 { - display: inline-block !important; - width: 66.66667% !important; } - td.small-9, - th.small-9 { - display: inline-block !important; - width: 75% !important; } - td.small-10, - th.small-10 { - display: inline-block !important; - width: 83.33333% !important; } - td.small-11, - th.small-11 { - display: inline-block !important; - width: 91.66667% !important; } - td.small-12, - th.small-12 { - display: inline-block !important; - width: 100% !important; } - .columns td.small-12, - .column td.small-12, - .columns th.small-12, - .column th.small-12 { - display: block !important; - width: 100% !important; } - table.body td.small-offset-1, - table.body th.small-offset-1 { - margin-left: 8.33333% !important; - Margin-left: 8.33333% !important; } - table.body td.small-offset-2, - table.body th.small-offset-2 { - margin-left: 16.66667% !important; - Margin-left: 16.66667% !important; } - table.body td.small-offset-3, - table.body th.small-offset-3 { - margin-left: 25% !important; - Margin-left: 25% !important; } - table.body td.small-offset-4, - table.body th.small-offset-4 { - margin-left: 33.33333% !important; - Margin-left: 33.33333% !important; } - table.body td.small-offset-5, - table.body th.small-offset-5 { - margin-left: 41.66667% !important; - Margin-left: 41.66667% !important; } - table.body td.small-offset-6, - table.body th.small-offset-6 { - margin-left: 50% !important; - Margin-left: 50% !important; } - table.body td.small-offset-7, - table.body th.small-offset-7 { - margin-left: 58.33333% !important; - Margin-left: 58.33333% !important; } - table.body td.small-offset-8, - table.body th.small-offset-8 { - margin-left: 66.66667% !important; - Margin-left: 66.66667% !important; } - table.body td.small-offset-9, - table.body th.small-offset-9 { - margin-left: 75% !important; - Margin-left: 75% !important; } - table.body td.small-offset-10, - table.body th.small-offset-10 { - margin-left: 83.33333% !important; - Margin-left: 83.33333% !important; } - table.body td.small-offset-11, - table.body th.small-offset-11 { - margin-left: 91.66667% !important; - Margin-left: 91.66667% !important; } - table.body table.columns td.expander, - table.body table.columns th.expander { - display: none !important; } - table.body .right-text-pad, - table.body .text-pad-right { - padding-left: 10px !important; } - table.body .left-text-pad, - table.body .text-pad-left { - padding-right: 10px !important; } - table.menu { - width: 100% !important; } + padding-left: 0 !important; + padding-right: 0 !important; + } + + table.body .collapse .columns, + table.body .collapse .column { + padding-left: 0 !important; + padding-right: 0 !important; + } + + td.small-1, + th.small-1 { + display: inline-block !important; + width: 8.33333% !important; + } + + td.small-2, + th.small-2 { + display: inline-block !important; + width: 16.66667% !important; + } + + td.small-3, + th.small-3 { + display: inline-block !important; + width: 25% !important; + } + + td.small-4, + th.small-4 { + display: inline-block !important; + width: 33.33333% !important; + } + + td.small-5, + th.small-5 { + display: inline-block !important; + width: 41.66667% !important; + } + + td.small-6, + th.small-6 { + display: inline-block !important; + width: 50% !important; + } + + td.small-7, + th.small-7 { + display: inline-block !important; + width: 58.33333% !important; + } + + td.small-8, + th.small-8 { + display: inline-block !important; + width: 66.66667% !important; + } + + td.small-9, + th.small-9 { + display: inline-block !important; + width: 75% !important; + } + + td.small-10, + th.small-10 { + display: inline-block !important; + width: 83.33333% !important; + } + + td.small-11, + th.small-11 { + display: inline-block !important; + width: 91.66667% !important; + } + + td.small-12, + th.small-12 { + display: inline-block !important; + width: 100% !important; + } + + .columns td.small-12, + .column td.small-12, + .columns th.small-12, + .column th.small-12 { + display: block !important; + width: 100% !important; + } + + table.body td.small-offset-1, + table.body th.small-offset-1 { + margin-left: 8.33333% !important; + Margin-left: 8.33333% !important; + } + + table.body td.small-offset-2, + table.body th.small-offset-2 { + margin-left: 16.66667% !important; + Margin-left: 16.66667% !important; + } + + table.body td.small-offset-3, + table.body th.small-offset-3 { + margin-left: 25% !important; + Margin-left: 25% !important; + } + + table.body td.small-offset-4, + table.body th.small-offset-4 { + margin-left: 33.33333% !important; + Margin-left: 33.33333% !important; + } + + table.body td.small-offset-5, + table.body th.small-offset-5 { + margin-left: 41.66667% !important; + Margin-left: 41.66667% !important; + } + + table.body td.small-offset-6, + table.body th.small-offset-6 { + margin-left: 50% !important; + Margin-left: 50% !important; + } + + table.body td.small-offset-7, + table.body th.small-offset-7 { + margin-left: 58.33333% !important; + Margin-left: 58.33333% !important; + } + + table.body td.small-offset-8, + table.body th.small-offset-8 { + margin-left: 66.66667% !important; + Margin-left: 66.66667% !important; + } + + table.body td.small-offset-9, + table.body th.small-offset-9 { + margin-left: 75% !important; + Margin-left: 75% !important; + } + + table.body td.small-offset-10, + table.body th.small-offset-10 { + margin-left: 83.33333% !important; + Margin-left: 83.33333% !important; + } + + table.body td.small-offset-11, + table.body th.small-offset-11 { + margin-left: 91.66667% !important; + Margin-left: 91.66667% !important; + } + + table.body table.columns td.expander, + table.body table.columns th.expander { + display: none !important; + } + + table.body .right-text-pad, + table.body .text-pad-right { + padding-left: 10px !important; + } + + table.body .left-text-pad, + table.body .text-pad-left { + padding-right: 10px !important; + } + + table.menu { + width: 100% !important; + } + table.menu td, table.menu th { - width: auto !important; - display: inline-block !important; } + width: auto !important; + display: inline-block !important; + } + table.menu.vertical td, table.menu.vertical th, table.menu.small-vertical td, table.menu.small-vertical th { - display: block !important; } - table.menu[align="center"] { - width: auto !important; } - table.button.small-expand, - table.button.small-expanded { - width: 100% !important; } + display: block !important; + } + + table.menu[align="center"] { + width: auto !important; + } + + table.button.small-expand, + table.button.small-expanded { + width: 100% !important; + } + table.button.small-expand table, table.button.small-expanded table { - width: 100%; } - table.button.small-expand table a, - table.button.small-expanded table a { + width: 100%; + } + + table.button.small-expand table a, + table.button.small-expanded table a { text-align: center !important; width: 100% !important; padding-left: 0 !important; - padding-right: 0 !important; } + padding-right: 0 !important; + } + table.button.small-expand center, table.button.small-expanded center { - min-width: 0; } } + min-width: 0; + } +} diff --git a/assets/js/app.js b/assets/js/app.js index fd7db935..43acec5d 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -44,4 +44,18 @@ import "./register_events"; import "./tristate_checkboxes"; //Define jquery globally -window.$ = window.jQuery = require("jquery") \ No newline at end of file +window.$ = window.jQuery = require("jquery"); + +//Use the local WASM file for the ZXing library +import { + setZXingModuleOverrides, +} from "barcode-detector/pure"; +import wasmFile from "../../node_modules/zxing-wasm/dist/reader/zxing_reader.wasm"; +setZXingModuleOverrides({ + locateFile: (path, prefix) => { + if (path.endsWith(".wasm")) { + return wasmFile; + } + return prefix + path; + }, +}); \ No newline at end of file diff --git a/assets/js/lib/dataTables.select.mjs b/assets/js/lib/dataTables.select.mjs new file mode 100644 index 00000000..bba97692 --- /dev/null +++ b/assets/js/lib/dataTables.select.mjs @@ -0,0 +1,1538 @@ +/********************* + * This is the fixed version of the select extension for DataTables with the fix for the issue with the select extension + * (https://github.com/DataTables/Select/issues/51) + * We use this instead of the yarn version until the PR (https://github.com/DataTables/Select/pull/52) is merged and released + * /*******************/ + + +/*! Select for DataTables 2.0.0 + * © SpryMedia Ltd - datatables.net/license/mit + */ + +import jQuery from 'jquery'; +import DataTable from 'datatables.net'; + +// Allow reassignment of the $ variable +let $ = jQuery; + + +// Version information for debugger +DataTable.select = {}; + +DataTable.select.version = '2.0.0'; + +DataTable.select.init = function (dt) { + var ctx = dt.settings()[0]; + + if (!DataTable.versionCheck('2')) { + throw 'Warning: Select requires DataTables 2 or newer'; + } + + if (ctx._select) { + return; + } + + var savedSelected = dt.state.loaded(); + + var selectAndSave = function (e, settings, data) { + if (data === null || data.select === undefined) { + return; + } + + // Clear any currently selected rows, before restoring state + // None will be selected on first initialisation + if (dt.rows({ selected: true }).any()) { + dt.rows().deselect(); + } + if (data.select.rows !== undefined) { + dt.rows(data.select.rows).select(); + } + + if (dt.columns({ selected: true }).any()) { + dt.columns().deselect(); + } + if (data.select.columns !== undefined) { + dt.columns(data.select.columns).select(); + } + + if (dt.cells({ selected: true }).any()) { + dt.cells().deselect(); + } + if (data.select.cells !== undefined) { + for (var i = 0; i < data.select.cells.length; i++) { + dt.cell(data.select.cells[i].row, data.select.cells[i].column).select(); + } + } + + dt.state.save(); + }; + + dt.on('stateSaveParams', function (e, settings, data) { + data.select = {}; + data.select.rows = dt.rows({ selected: true }).ids(true).toArray(); + data.select.columns = dt.columns({ selected: true })[0]; + data.select.cells = dt.cells({ selected: true })[0].map(function (coords) { + return { row: dt.row(coords.row).id(true), column: coords.column }; + }); + }) + .on('stateLoadParams', selectAndSave) + .one('init', function () { + selectAndSave(undefined, undefined, savedSelected); + }); + + var init = ctx.oInit.select; + var defaults = DataTable.defaults.select; + var opts = init === undefined ? defaults : init; + + // Set defaults + var items = 'row'; + var style = 'api'; + var blurable = false; + var toggleable = true; + var info = true; + var selector = 'td, th'; + var className = 'selected'; + var headerCheckbox = true; + var setStyle = false; + + ctx._select = { + infoEls: [] + }; + + // Initialisation customisations + if (opts === true) { + style = 'os'; + setStyle = true; + } + else if (typeof opts === 'string') { + style = opts; + setStyle = true; + } + else if ($.isPlainObject(opts)) { + if (opts.blurable !== undefined) { + blurable = opts.blurable; + } + + if (opts.toggleable !== undefined) { + toggleable = opts.toggleable; + } + + if (opts.info !== undefined) { + info = opts.info; + } + + if (opts.items !== undefined) { + items = opts.items; + } + + if (opts.style !== undefined) { + style = opts.style; + setStyle = true; + } + else { + style = 'os'; + setStyle = true; + } + + if (opts.selector !== undefined) { + selector = opts.selector; + } + + if (opts.className !== undefined) { + className = opts.className; + } + + if (opts.headerCheckbox !== undefined) { + headerCheckbox = opts.headerCheckbox; + } + } + + dt.select.selector(selector); + dt.select.items(items); + dt.select.style(style); + dt.select.blurable(blurable); + dt.select.toggleable(toggleable); + dt.select.info(info); + ctx._select.className = className; + + // If the init options haven't enabled select, but there is a selectable + // class name, then enable + if (!setStyle && $(dt.table().node()).hasClass('selectable')) { + dt.select.style('os'); + } + + // Insert a checkbox into the header if needed - might need to wait + // for init complete, or it might already be done + if (headerCheckbox) { + initCheckboxHeader(dt); + + dt.on('init', function () { + initCheckboxHeader(dt); + }); + } +}; + +/* + +Select is a collection of API methods, event handlers, event emitters and +buttons (for the `Buttons` extension) for DataTables. It provides the following +features, with an overview of how they are implemented: + +## Selection of rows, columns and cells. Whether an item is selected or not is + stored in: + +* rows: a `_select_selected` property which contains a boolean value of the + DataTables' `aoData` object for each row +* columns: a `_select_selected` property which contains a boolean value of the + DataTables' `aoColumns` object for each column +* cells: a `_selected_cells` property which contains an array of boolean values + of the `aoData` object for each row. The array is the same length as the + columns array, with each element of it representing a cell. + +This method of using boolean flags allows Select to operate when nodes have not +been created for rows / cells (DataTables' defer rendering feature). + +## API methods + +A range of API methods are available for triggering selection and de-selection +of rows. Methods are also available to configure the selection events that can +be triggered by an end user (such as which items are to be selected). To a large +extent, these of API methods *is* Select. It is basically a collection of helper +functions that can be used to select items in a DataTable. + +Configuration of select is held in the object `_select` which is attached to the +DataTables settings object on initialisation. Select being available on a table +is not optional when Select is loaded, but its default is for selection only to +be available via the API - so the end user wouldn't be able to select rows +without additional configuration. + +The `_select` object contains the following properties: + +``` +{ + items:string - Can be `rows`, `columns` or `cells`. Defines what item + will be selected if the user is allowed to activate row + selection using the mouse. + style:string - Can be `none`, `single`, `multi` or `os`. Defines the + interaction style when selecting items + blurable:boolean - If row selection can be cleared by clicking outside of + the table + toggleable:boolean - If row selection can be cancelled by repeated clicking + on the row + info:boolean - If the selection summary should be shown in the table + information elements + infoEls:element[] - List of HTML elements with info elements for a table +} +``` + +In addition to the API methods, Select also extends the DataTables selector +options for rows, columns and cells adding a `selected` option to the selector +options object, allowing the developer to select only selected items or +unselected items. + +## Mouse selection of items + +Clicking on items can be used to select items. This is done by a simple event +handler that will select the items using the API methods. + + */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local functions + */ + +/** + * Add one or more cells to the selection when shift clicking in OS selection + * style cell selection. + * + * Cell range is more complicated than row and column as we want to select + * in the visible grid rather than by index in sequence. For example, if you + * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1 + * should also be selected (and not 1-3, 1-4. etc) + * + * @param {DataTable.Api} dt DataTable + * @param {object} idx Cell index to select to + * @param {object} last Cell index to select from + * @private + */ +function cellRange(dt, idx, last) { + var indexes; + var columnIndexes; + var rowIndexes; + var selectColumns = function (start, end) { + if (start > end) { + var tmp = end; + end = start; + start = tmp; + } + + var record = false; + return dt + .columns(':visible') + .indexes() + .filter(function (i) { + if (i === start) { + record = true; + } + + if (i === end) { + // not else if, as start might === end + record = false; + return true; + } + + return record; + }); + }; + + var selectRows = function (start, end) { + var indexes = dt.rows({ search: 'applied' }).indexes(); + + // Which comes first - might need to swap + if (indexes.indexOf(start) > indexes.indexOf(end)) { + var tmp = end; + end = start; + start = tmp; + } + + var record = false; + return indexes.filter(function (i) { + if (i === start) { + record = true; + } + + if (i === end) { + record = false; + return true; + } + + return record; + }); + }; + + if (!dt.cells({ selected: true }).any() && !last) { + // select from the top left cell to this one + columnIndexes = selectColumns(0, idx.column); + rowIndexes = selectRows(0, idx.row); + } + else { + // Get column indexes between old and new + columnIndexes = selectColumns(last.column, idx.column); + rowIndexes = selectRows(last.row, idx.row); + } + + indexes = dt.cells(rowIndexes, columnIndexes).flatten(); + + if (!dt.cells(idx, { selected: true }).any()) { + // Select range + dt.cells(indexes).select(); + } + else { + // Deselect range + dt.cells(indexes).deselect(); + } +} + +/** + * Disable mouse selection by removing the selectors + * + * @param {DataTable.Api} dt DataTable to remove events from + * @private + */ +function disableMouseSelection(dt) { + var ctx = dt.settings()[0]; + var selector = ctx._select.selector; + + $(dt.table().container()) + .off('mousedown.dtSelect', selector) + .off('mouseup.dtSelect', selector) + .off('click.dtSelect', selector); + + $('body').off('click.dtSelect' + _safeId(dt.table().node())); +} + +/** + * Attach mouse listeners to the table to allow mouse selection of items + * + * @param {DataTable.Api} dt DataTable to remove events from + * @private + */ +function enableMouseSelection(dt) { + var container = $(dt.table().container()); + var ctx = dt.settings()[0]; + var selector = ctx._select.selector; + var matchSelection; + + container + .on('mousedown.dtSelect', selector, function (e) { + // Disallow text selection for shift clicking on the table so multi + // element selection doesn't look terrible! + if (e.shiftKey || e.metaKey || e.ctrlKey) { + container + .css('-moz-user-select', 'none') + .one('selectstart.dtSelect', selector, function () { + return false; + }); + } + + if (window.getSelection) { + matchSelection = window.getSelection(); + } + }) + .on('mouseup.dtSelect', selector, function () { + // Allow text selection to occur again, Mozilla style (tested in FF + // 35.0.1 - still required) + container.css('-moz-user-select', ''); + }) + .on('click.dtSelect', selector, function (e) { + var items = dt.select.items(); + var idx; + + // If text was selected (click and drag), then we shouldn't change + // the row's selected state + if (matchSelection) { + var selection = window.getSelection(); + + // If the element that contains the selection is not in the table, we can ignore it + // This can happen if the developer selects text from the click event + if ( + !selection.anchorNode || + $(selection.anchorNode).closest('table')[0] === dt.table().node() + ) { + if (selection !== matchSelection) { + return; + } + } + } + + var ctx = dt.settings()[0]; + var container = dt.table().container(); + + // Ignore clicks inside a sub-table + if ($(e.target).closest('div.dt-container')[0] != container) { + return; + } + + var cell = dt.cell($(e.target).closest('td, th')); + + // Check the cell actually belongs to the host DataTable (so child + // rows, etc, are ignored) + if (!cell.any()) { + return; + } + + var event = $.Event('user-select.dt'); + eventTrigger(dt, event, [items, cell, e]); + + if (event.isDefaultPrevented()) { + return; + } + + var cellIndex = cell.index(); + if (items === 'row') { + idx = cellIndex.row; + typeSelect(e, dt, ctx, 'row', idx); + } + else if (items === 'column') { + idx = cell.index().column; + typeSelect(e, dt, ctx, 'column', idx); + } + else if (items === 'cell') { + idx = cell.index(); + typeSelect(e, dt, ctx, 'cell', idx); + } + + ctx._select_lastCell = cellIndex; + }); + + // Blurable + $('body').on('click.dtSelect' + _safeId(dt.table().node()), function (e) { + if (ctx._select.blurable) { + // If the click was inside the DataTables container, don't blur + if ($(e.target).parents().filter(dt.table().container()).length) { + return; + } + + // Ignore elements which have been removed from the DOM (i.e. paging + // buttons) + if ($(e.target).parents('html').length === 0) { + return; + } + + // Don't blur in Editor form + if ($(e.target).parents('div.DTE').length) { + return; + } + + var event = $.Event('select-blur.dt'); + eventTrigger(dt, event, [e.target, e]); + + if (event.isDefaultPrevented()) { + return; + } + + clear(ctx, true); + } + }); +} + +/** + * Trigger an event on a DataTable + * + * @param {DataTable.Api} api DataTable to trigger events on + * @param {boolean} selected true if selected, false if deselected + * @param {string} type Item type acting on + * @param {boolean} any Require that there are values before + * triggering + * @private + */ +function eventTrigger(api, type, args, any) { + if (any && !api.flatten().length) { + return; + } + + if (typeof type === 'string') { + type = type + '.dt'; + } + + args.unshift(api); + + $(api.table().node()).trigger(type, args); +} + +/** + * Update the information element of the DataTable showing information about the + * items selected. This is done by adding tags to the existing text + * + * @param {DataTable.Api} api DataTable to update + * @private + */ +function info(api, node) { + if (api.select.style() === 'api' || api.select.info() === false) { + return; + } + + var rows = api.rows({ selected: true }).flatten().length; + var columns = api.columns({ selected: true }).flatten().length; + var cells = api.cells({ selected: true }).flatten().length; + + var add = function (el, name, num) { + el.append( + $('').append( + api.i18n( + 'select.' + name + 's', + { _: '%d ' + name + 's selected', 0: '', 1: '1 ' + name + ' selected' }, + num + ) + ) + ); + }; + + var el = $(node); + var output = $(''); + + add(output, 'row', rows); + add(output, 'column', columns); + add(output, 'cell', cells); + + var existing = el.children('span.select-info'); + + if (existing.length) { + existing.remove(); + } + + if (output.text() !== '') { + el.append(output); + } +} + +/** + * Add a checkbox to the header for checkbox columns, allowing all rows to + * be selected, deselected or just to show the state. + * + * @param {*} dt API + */ +function initCheckboxHeader( dt ) { + // Find any checkbox column(s) + dt.columns('.dt-select').every(function () { + var header = this.header(); + + if (! $('input', header).length) { + // If no checkbox yet, insert one + var input = $('') + .attr({ + class: 'dt-select-checkbox', + type: 'checkbox', + 'aria-label': dt.i18n('select.aria.headerCheckbox') || 'Select all rows' + }) + .appendTo(header) + .on('change', function () { + if (this.checked) { + dt.rows({search: 'applied'}).select(); + } + else { + dt.rows({selected: true}).deselect(); + } + }) + .on('click', function (e) { + e.stopPropagation(); + }); + + // Update the header checkbox's state when the selection in the + // table changes + dt.on('draw select deselect', function (e, pass, type) { + if (type === 'row' || ! type) { + var count = dt.rows({selected: true}).count(); + var search = dt.rows({search: 'applied', selected: true}).count(); + var available = dt.rows({search: 'applied'}).count(); + + if (search && search <= count && search === available) { + input + .prop('checked', true) + .prop('indeterminate', false); + } + else if (search === 0 && count === 0) { + input + .prop('checked', false) + .prop('indeterminate', false); + } + else { + input + .prop('checked', false) + .prop('indeterminate', true); + } + } + }); + } + }); +} + +/** + * Initialisation of a new table. Attach event handlers and callbacks to allow + * Select to operate correctly. + * + * This will occur _after_ the initial DataTables initialisation, although + * before Ajax data is rendered, if there is ajax data + * + * @param {DataTable.settings} ctx Settings object to operate on + * @private + */ +function init(ctx) { + var api = new DataTable.Api(ctx); + ctx._select_init = true; + + // Row callback so that classes can be added to rows and cells if the item + // was selected before the element was created. This will happen with the + // `deferRender` option enabled. + // + // This method of attaching to `aoRowCreatedCallback` is a hack until + // DataTables has proper events for row manipulation If you are reviewing + // this code to create your own plug-ins, please do not do this! + ctx.aoRowCreatedCallback.push(function (row, data, index) { + var i, ien; + var d = ctx.aoData[index]; + + // Row + if (d._select_selected) { + $(row).addClass(ctx._select.className); + } + + // Cells and columns - if separated out, we would need to do two + // loops, so it makes sense to combine them into a single one + for (i = 0, ien = ctx.aoColumns.length; i < ien; i++) { + if ( + ctx.aoColumns[i]._select_selected || + (d._selected_cells && d._selected_cells[i]) + ) { + $(d.anCells[i]).addClass(ctx._select.className); + } + } + } + ); + + // On Ajax reload we want to reselect all rows which are currently selected, + // if there is an rowId (i.e. a unique value to identify each row with) + api.on('preXhr.dt.dtSelect', function (e, settings) { + if (settings !== api.settings()[0]) { + // Not triggered by our DataTable! + return; + } + + // note that column selection doesn't need to be cached and then + // reselected, as they are already selected + var rows = api + .rows({ selected: true }) + .ids(true) + .filter(function (d) { + return d !== undefined; + }); + + var cells = api + .cells({ selected: true }) + .eq(0) + .map(function (cellIdx) { + var id = api.row(cellIdx.row).id(true); + return id ? { row: id, column: cellIdx.column } : undefined; + }) + .filter(function (d) { + return d !== undefined; + }); + + // On the next draw, reselect the currently selected items + api.one('draw.dt.dtSelect', function () { + api.rows(rows).select(); + + // `cells` is not a cell index selector, so it needs a loop + if (cells.any()) { + cells.each(function (id) { + api.cells(id.row, id.column).select(); + }); + } + }); + }); + + // Update the table information element with selected item summary + api.on('info.dt', function (e, ctx, node) { + // Store the info node for updating on select / deselect + if (!ctx._select.infoEls.includes(node)) { + ctx._select.infoEls.push(node); + } + + info(api, node); + }); + + api.on('select.dtSelect.dt deselect.dtSelect.dt', function () { + ctx._select.infoEls.forEach(function (el) { + info(api, el); + }); + + api.state.save(); + }); + + // Clean up and release + api.on('destroy.dtSelect', function () { + // Remove class directly rather than calling deselect - which would trigger events + $(api.rows({ selected: true }).nodes()).removeClass(api.settings()[0]._select.className); + + disableMouseSelection(api); + api.off('.dtSelect'); + $('body').off('.dtSelect' + _safeId(api.table().node())); + }); +} + +/** + * Add one or more items (rows or columns) to the selection when shift clicking + * in OS selection style + * + * @param {DataTable.Api} dt DataTable + * @param {string} type Row or column range selector + * @param {object} idx Item index to select to + * @param {object} last Item index to select from + * @private + */ +function rowColumnRange(dt, type, idx, last) { + // Add a range of rows from the last selected row to this one + var indexes = dt[type + 's']({ search: 'applied' }).indexes(); + var idx1 = indexes.indexOf(last); + var idx2 = indexes.indexOf(idx); + + if (!dt[type + 's']({ selected: true }).any() && idx1 === -1) { + // select from top to here - slightly odd, but both Windows and Mac OS + // do this + indexes.splice(indexes.indexOf(idx) + 1, indexes.length); + } + else { + // reverse so we can shift click 'up' as well as down + if (idx1 > idx2) { + var tmp = idx2; + idx2 = idx1; + idx1 = tmp; + } + + indexes.splice(idx2 + 1, indexes.length); + indexes.splice(0, idx1); + } + + if (!dt[type](idx, { selected: true }).any()) { + // Select range + dt[type + 's'](indexes).select(); + } + else { + // Deselect range - need to keep the clicked on row selected + indexes.splice(indexes.indexOf(idx), 1); + dt[type + 's'](indexes).deselect(); + } +} + +/** + * Clear all selected items + * + * @param {DataTable.settings} ctx Settings object of the host DataTable + * @param {boolean} [force=false] Force the de-selection to happen, regardless + * of selection style + * @private + */ +function clear(ctx, force) { + if (force || ctx._select.style === 'single') { + var api = new DataTable.Api(ctx); + + api.rows({ selected: true }).deselect(); + api.columns({ selected: true }).deselect(); + api.cells({ selected: true }).deselect(); + } +} + +/** + * Select items based on the current configuration for style and items. + * + * @param {object} e Mouse event object + * @param {DataTables.Api} dt DataTable + * @param {DataTable.settings} ctx Settings object of the host DataTable + * @param {string} type Items to select + * @param {int|object} idx Index of the item to select + * @private + */ +function typeSelect(e, dt, ctx, type, idx) { + var style = dt.select.style(); + var toggleable = dt.select.toggleable(); + var isSelected = dt[type](idx, { selected: true }).any(); + + if (isSelected && !toggleable) { + return; + } + + if (style === 'os') { + if (e.ctrlKey || e.metaKey) { + // Add or remove from the selection + dt[type](idx).select(!isSelected); + } + else if (e.shiftKey) { + if (type === 'cell') { + cellRange(dt, idx, ctx._select_lastCell || null); + } + else { + rowColumnRange( + dt, + type, + idx, + ctx._select_lastCell ? ctx._select_lastCell[type] : null + ); + } + } + else { + // No cmd or shift click - deselect if selected, or select + // this row only + var selected = dt[type + 's']({ selected: true }); + + if (isSelected && selected.flatten().length === 1) { + dt[type](idx).deselect(); + } + else { + selected.deselect(); + dt[type](idx).select(); + } + } + } + else if (style == 'multi+shift') { + if (e.shiftKey) { + if (type === 'cell') { + cellRange(dt, idx, ctx._select_lastCell || null); + } + else { + rowColumnRange( + dt, + type, + idx, + ctx._select_lastCell ? ctx._select_lastCell[type] : null + ); + } + } + else { + dt[type](idx).select(!isSelected); + } + } + else { + dt[type](idx).select(!isSelected); + } +} + +function _safeId(node) { + return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-'); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables selectors + */ + +// row and column are basically identical just assigned to different properties +// and checking a different array, so we can dynamically create the functions to +// reduce the code size +$.each( + [ + { type: 'row', prop: 'aoData' }, + { type: 'column', prop: 'aoColumns' } + ], + function (i, o) { + DataTable.ext.selector[o.type].push(function (settings, opts, indexes) { + var selected = opts.selected; + var data; + var out = []; + + if (selected !== true && selected !== false) { + return indexes; + } + + for (var i = 0, ien = indexes.length; i < ien; i++) { + data = settings[o.prop][indexes[i]]; + + if ( + data && ( + (selected === true && data._select_selected === true) || + (selected === false && !data._select_selected) + ) + ) { + out.push(indexes[i]); + } + } + + return out; + }); + } +); + +DataTable.ext.selector.cell.push(function (settings, opts, cells) { + var selected = opts.selected; + var rowData; + var out = []; + + if (selected === undefined) { + return cells; + } + + for (var i = 0, ien = cells.length; i < ien; i++) { + rowData = settings.aoData[cells[i].row]; + + if ( + rowData && ( + (selected === true && + rowData._selected_cells && + rowData._selected_cells[cells[i].column] === true) || + (selected === false && + (!rowData._selected_cells || !rowData._selected_cells[cells[i].column])) + ) + ) { + out.push(cells[i]); + } + } + + return out; +}); + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables API + * + * For complete documentation, please refer to the docs/api directory or the + * DataTables site + */ + +// Local variables to improve compression +var apiRegister = DataTable.Api.register; +var apiRegisterPlural = DataTable.Api.registerPlural; + +apiRegister('select()', function () { + return this.iterator('table', function (ctx) { + DataTable.select.init(new DataTable.Api(ctx)); + }); +}); + +apiRegister('select.blurable()', function (flag) { + if (flag === undefined) { + return this.context[0]._select.blurable; + } + + return this.iterator('table', function (ctx) { + ctx._select.blurable = flag; + }); +}); + +apiRegister('select.toggleable()', function (flag) { + if (flag === undefined) { + return this.context[0]._select.toggleable; + } + + return this.iterator('table', function (ctx) { + ctx._select.toggleable = flag; + }); +}); + +apiRegister('select.info()', function (flag) { + if (flag === undefined) { + return this.context[0]._select.info; + } + + return this.iterator('table', function (ctx) { + ctx._select.info = flag; + }); +}); + +apiRegister('select.items()', function (items) { + if (items === undefined) { + return this.context[0]._select.items; + } + + return this.iterator('table', function (ctx) { + ctx._select.items = items; + + eventTrigger(new DataTable.Api(ctx), 'selectItems', [items]); + }); +}); + +// Takes effect from the _next_ selection. None disables future selection, but +// does not clear the current selection. Use the `deselect` methods for that +apiRegister('select.style()', function (style) { + if (style === undefined) { + return this.context[0]._select.style; + } + + return this.iterator('table', function (ctx) { + if (!ctx._select) { + DataTable.select.init(new DataTable.Api(ctx)); + } + + if (!ctx._select_init) { + init(ctx); + } + + ctx._select.style = style; + + // Add / remove mouse event handlers. They aren't required when only + // API selection is available + var dt = new DataTable.Api(ctx); + disableMouseSelection(dt); + + if (style !== 'api') { + enableMouseSelection(dt); + } + + eventTrigger(new DataTable.Api(ctx), 'selectStyle', [style]); + }); +}); + +apiRegister('select.selector()', function (selector) { + if (selector === undefined) { + return this.context[0]._select.selector; + } + + return this.iterator('table', function (ctx) { + disableMouseSelection(new DataTable.Api(ctx)); + + ctx._select.selector = selector; + + if (ctx._select.style !== 'api') { + enableMouseSelection(new DataTable.Api(ctx)); + } + }); +}); + +apiRegister('select.last()', function (set) { + let ctx = this.context[0]; + + if (set) { + ctx._select_lastCell = set; + return this; + } + + return ctx._select_lastCell; +}); + +apiRegisterPlural('rows().select()', 'row().select()', function (select) { + var api = this; + + if (select === false) { + return this.deselect(); + } + + this.iterator('row', function (ctx, idx) { + clear(ctx); + + // There is a good amount of knowledge of DataTables internals in + // this function. It _could_ be done without that, but it would hurt + // performance (or DT would need new APIs for this work) + var dtData = ctx.aoData[idx]; + var dtColumns = ctx.aoColumns; + + $(dtData.nTr).addClass(ctx._select.className); + dtData._select_selected = true; + + for (var i=0 ; i 0); + }); + + this.disable(); + }, + destroy: function (dt, node, config) { + dt.off(config._eventNamespace); + } + }, + showSelected: { + text: i18n('showSelected', 'Show only selected'), + className: 'buttons-show-selected', + action: function (e, dt) { + if (dt.search.fixed('dt-select')) { + // Remove existing function + dt.search.fixed('dt-select', null); + + this.active(false); + } + else { + // Use a fixed filtering function to match on selected rows + // This needs to reference the internal aoData since that is + // where Select stores its reference for the selected state + var dataSrc = dt.settings()[0].aoData; + + dt.search.fixed('dt-select', function (text, data, idx) { + // _select_selected is set by Select on the data object for the row + return dataSrc[idx]._select_selected; + }); + + this.active(true); + } + + dt.draw(); + } + } +}); + +$.each(['Row', 'Column', 'Cell'], function (i, item) { + var lc = item.toLowerCase(); + + DataTable.ext.buttons['select' + item + 's'] = { + text: i18n('select' + item + 's', 'Select ' + lc + 's'), + className: 'buttons-select-' + lc + 's', + action: function () { + this.select.items(lc); + }, + init: function (dt) { + var that = this; + + dt.on('selectItems.dt.DT', function (e, ctx, items) { + that.active(items === lc); + }); + } + }; +}); + +DataTable.type('select-checkbox', { + className: 'dt-select', + detect: function (data) { + // Rendering function will tell us if it is a checkbox type + return data === 'select-checkbox' ? data : false; + }, + order: { + pre: function (d) { + return d === 'X' ? -1 : 0; + } + } +}); + +$.extend(true, DataTable.defaults.oLanguage, { + select: { + aria: { + rowCheckbox: 'Select row' + } + } +}); + +DataTable.render.select = function (valueProp, nameProp) { + var valueFn = valueProp ? DataTable.util.get(valueProp) : null; + var nameFn = nameProp ? DataTable.util.get(nameProp) : null; + + return function (data, type, row, meta) { + var dtRow = meta.settings.aoData[meta.row]; + var selected = dtRow._select_selected; + var ariaLabel = meta.settings.oLanguage.select.aria.rowCheckbox; + + if (type === 'display') { + return $('') + .attr({ + 'aria-label': ariaLabel, + class: 'dt-select-checkbox', + name: nameFn ? nameFn(row) : null, + type: 'checkbox', + value: valueFn ? valueFn(row) : null, + checked: selected + })[0]; + } + else if (type === 'type') { + return 'select-checkbox'; + } + else if (type === 'filter') { + return ''; + } + + return selected ? 'X' : ''; + } +} + +// Legacy checkbox ordering +DataTable.ext.order['select-checkbox'] = function (settings, col) { + return this.api() + .column(col, { order: 'index' }) + .nodes() + .map(function (td) { + if (settings._select.items === 'row') { + return $(td).parent().hasClass(settings._select.className); + } + else if (settings._select.items === 'cell') { + return $(td).hasClass(settings._select.className); + } + return false; + }); +}; + +$.fn.DataTable.select = DataTable.select; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Initialisation + */ + +// DataTables creation - check if select has been defined in the options. Note +// this required that the table be in the document! If it isn't then something +// needs to trigger this method unfortunately. The next major release of +// DataTables will rework the events and address this. +$(document).on('preInit.dt.dtSelect', function (e, ctx) { + if (e.namespace !== 'dt') { + return; + } + + DataTable.select.init(new DataTable.Api(ctx)); +}); + + +export default DataTable; diff --git a/assets/js/lib/datatables.js b/assets/js/lib/datatables.js index 99675ae1..8e39548b 100644 --- a/assets/js/lib/datatables.js +++ b/assets/js/lib/datatables.js @@ -47,7 +47,8 @@ method: config.method, data: { _dt: config.name, - _init: true + _init: true, + order: config.initial_order ?? undefined, } }).done(function(data) { var baseState; @@ -97,6 +98,15 @@ dtOpts = config.options(dtOpts); } + //Choose the column where the className contains "select-column" and apply the select extension to its render field + //Added for Part-DB + for (let column of dtOpts.columns) { + if (column.className && column.className.includes('dt-select')) { + column.render = $.fn.dataTable.render.select(); + } + } + + root.html(data.template); dt = $('table', root).DataTable(dtOpts); if (config.state !== 'none') { diff --git a/assets/js/register_events.js b/assets/js/register_events.js index 22e91fdf..9732c0c1 100644 --- a/assets/js/register_events.js +++ b/assets/js/register_events.js @@ -20,6 +20,8 @@ 'use strict'; import {Dropdown} from "bootstrap"; +import ClipboardJS from "clipboard"; +import {Modal} from "bootstrap"; class RegisterEventHelper { constructor() { @@ -27,7 +29,14 @@ class RegisterEventHelper { this.configureDropdowns(); this.registerSpecialCharInput(); + //Initialize ClipboardJS + this.registerLoadHandler(() => { + new ClipboardJS('.btn'); + }); + this.registerModalDropRemovalOnFormSubmit(); + + } registerModalDropRemovalOnFormSubmit() { @@ -37,6 +46,15 @@ class RegisterEventHelper { if (back_drop) { back_drop.remove(); } + + //Remove scroll-lock if it is still active + if (document.body.classList.contains('modal-open')) { + document.body.classList.remove('modal-open'); + + //Remove the padding-right and overflow:hidden from the body + document.body.style.paddingRight = ''; + document.body.style.overflow = ''; + } }); } diff --git a/assets/js/tab_remember.js b/assets/js/tab_remember.js index 9ecd71c5..1bf35db5 100644 --- a/assets/js/tab_remember.js +++ b/assets/js/tab_remember.js @@ -19,7 +19,7 @@ "use strict"; -import {Tab, Dropdown} from "bootstrap"; +import {Tab, Dropdown, Collapse} from "bootstrap"; import tab from "bootstrap/js/src/tab"; /** @@ -54,6 +54,7 @@ class TabRememberHelper { const first_element = merged[0] ?? null; if(first_element) { this.revealElementOnTab(first_element); + this.revealElementInCollapse(first_element); } } @@ -62,10 +63,20 @@ class TabRememberHelper { * @param event */ onInvalid(event) { + this.revealElementInCollapse(event.target); this.revealElementOnTab(event.target); this.revealElementInDropdown(event.target); } + revealElementInCollapse(element) { + let collapse = element.closest('.collapse'); + + if(collapse) { + let bs_collapse = Collapse.getOrCreateInstance(collapse); + bs_collapse.show(); + } + } + revealElementInDropdown(element) { let dropdown = element.closest('.dropdown-menu'); diff --git a/assets/tomselect/autoselect_typed/autoselect_typed.js b/assets/tomselect/autoselect_typed/autoselect_typed.js new file mode 100644 index 00000000..8a426be7 --- /dev/null +++ b/assets/tomselect/autoselect_typed/autoselect_typed.js @@ -0,0 +1,63 @@ +/** + * Autoselect Typed plugin for Tomselect + * + * This plugin allows automatically selecting an option matching the typed text when the Tomselect element goes out of + * focus (is blurred) and/or when the delimiter is typed. + * + * #select_on_blur option + * Tomselect natively supports the "createOnBlur" option. This option picks up any remaining text in the input field + * and uses it to create a new option and selects that option. It does behave a bit strangely though, in that it will + * not select an already existing option when the input is blurred, so if you typed something that matches an option in + * the list and then click outside the box (without pressing enter) the entered text is just removed (unless you have + * allow duplicates on in which case it will create a new option). + * This plugin fixes that, such that Tomselect will first try to select an option matching the remaining uncommitted + * text and only when no matching option is found tries to create a new one (if createOnBlur and create is on) + * + * #select_on_delimiter option + * Normally when typing the delimiter (space by default) Tomselect will try to create a new option (and select it) (if + * create is on), but if the typed text matches an option (and allow duplicates is off) it refuses to react at all until + * you press enter. With this option, the delimiter will also allow selecting an option, not just creating it. + */ +function select_current_input(self){ + if(self.isLocked){ + return + } + + const val = self.inputValue() + //Do nothing if the input is empty + if (!val) { + return + } + + if (self.options[val]) { + self.addItem(val) + self.setTextboxValue() + } +} + +export default function(plugin_options_) { + const plugin_options = Object.assign({ + //Autoselect the typed text when the input element goes out of focus + select_on_blur: true, + //Autoselect the typed text when the delimiter is typed + select_on_delimiter: true, + }, plugin_options_); + + const self = this + + if(plugin_options.select_on_blur) { + this.hook("before", "onBlur", function () { + select_current_input(self) + }) + } + + if(plugin_options.select_on_delimiter) { + this.hook("before", "onKeyPress", function (e) { + const character = String.fromCharCode(e.keyCode || e.which); + if (self.settings.mode === 'multi' && character === self.settings.delimiter) { + select_current_input(self) + } + }) + } + +} \ No newline at end of file diff --git a/assets/tomselect/click_to_edit/click_to_edit.js b/assets/tomselect/click_to_edit/click_to_edit.js new file mode 100644 index 00000000..b7dcab03 --- /dev/null +++ b/assets/tomselect/click_to_edit/click_to_edit.js @@ -0,0 +1,93 @@ +/** + * click_to_edit plugin for Tomselect + * + * This plugin allows editing (and selecting text in) any selected item by clicking it. + * + * Usually, when the user typed some text and created an item in Tomselect that item cannot be edited anymore. To make + * a change, the item has to be deleted and retyped completely. There is also generally no way to copy text out of a + * tomselect item. The "restore_on_backspace" plugin improves that somewhat, by allowing the user to edit an item after + * pressing backspace. However, it is somewhat confusing to first have to focus the field an then hit backspace in order + * to copy a piece of text. It may also not be immediately obvious for editing. + * This plugin transforms an item into editable text when it is clicked, e.g. when the user tries to place the caret + * within an item or when they try to drag across the text to highlight it. + * It also plays nice with the remove_button plugin which still removes (deselects) an option entirely. + * + * It is recommended to also enable the autoselect_typed plugin when using this plugin. Without it, the text in the + * input field (i.e. the item that was just clicked) is lost when the user clicks outside the field. Also, when the user + * clicks an option (making it text) and then tries to enter another one by entering the delimiter (e.g. space) nothing + * happens until enter is pressed or the text is changed from what it was. + */ + +/** + * Return a dom element from either a dom query string, jQuery object, a dom element or html string + * https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518 + * + * param query should be {} + */ +const getDom = query => { + if (query.jquery) { + return query[0]; + } + if (query instanceof HTMLElement) { + return query; + } + if (isHtmlString(query)) { + var tpl = document.createElement('template'); + tpl.innerHTML = query.trim(); // Never return a text node of whitespace as the result + return tpl.content.firstChild; + } + return document.querySelector(query); +}; +const isHtmlString = arg => { + if (typeof arg === 'string' && arg.indexOf('<') > -1) { + return true; + } + return false; +}; + +function plugin(plugin_options_) { + const self = this + + const plugin_options = Object.assign({ + //If there is unsubmitted text in the input field, should that text be automatically used to select a matching + //element? If this is off, clicking on item1 and then clicking on item2 will result in item1 being deselected + auto_select_before_edit: true, + //If there is unsubmitted text in the input field, should that text be automatically used to create a matching + //element if no matching element was found or auto_select_before_edit is off? + auto_create_before_edit: true, + //customize this function to change which text the item is replaced with when clicking on it + text: option => { + return option[self.settings.labelField]; + } + }, plugin_options_); + + + self.hook('after', 'setupTemplates', () => { + const orig_render_item = self.settings.render.item; + self.settings.render.item = (data, escape) => { + const item = getDom(orig_render_item.call(self, data, escape)); + + item.addEventListener('click', evt => { + if (self.isLocked) { + return; + } + const val = self.inputValue(); + + if (self.options[val]) { + self.addItem(val) + } else if (self.settings.create) { + self.createItem(); + } + const option = self.options[item.dataset.value] + self.setTextboxValue(plugin_options.text.call(self, option)); + self.focus(); + self.removeItem(item); + } + ); + + return item; + } + }); + +} +export { plugin as default }; \ No newline at end of file diff --git a/bin/console b/bin/console index c933dc53..256c0a60 100755 --- a/bin/console +++ b/bin/console @@ -4,6 +4,17 @@ use App\Kernel; use Symfony\Bundle\FrameworkBundle\Console\Application; +if (!is_dir(dirname(__DIR__).'/vendor')) { + throw new LogicException('Dependencies are missing. Try running "composer install".'); +} + +//Increase xdebug.max_nesting_level to 1000 if required (see issue #411) +//Check if xdebug extension is active, and xdebug.max_nesting_level is set to 256 or lower +if (extension_loaded('xdebug') && ((int) ini_get('xdebug.max_nesting_level')) <= 256) { + //Increase xdebug.max_nesting_level to 1000 + ini_set('xdebug.max_nesting_level', '1000'); +} + if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) { throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".'); } diff --git a/bin/phpunit b/bin/phpunit index f26f2c72..692baccb 100755 --- a/bin/phpunit +++ b/bin/phpunit @@ -6,9 +6,13 @@ if (!ini_get('date.timezone')) { } if (is_file(dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit')) { - define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__).'/vendor/autoload.php'); - require PHPUNIT_COMPOSER_INSTALL; - PHPUnit\TextUI\Command::main(); + if (PHP_VERSION_ID >= 80000) { + require dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit'; + } else { + define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__).'/vendor/autoload.php'); + require PHPUNIT_COMPOSER_INSTALL; + PHPUnit\TextUI\Command::main(); + } } else { if (!is_file(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) { echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n"; diff --git a/codecov.yml b/codecov.yml index 34acb532..6ac0375c 100644 --- a/codecov.yml +++ b/codecov.yml @@ -5,4 +5,5 @@ coverage: status: project: default: - threshold: 5% \ No newline at end of file + threshold: 10% + target: 40% diff --git a/composer.json b/composer.json index fd96da4b..e57ce652 100644 --- a/composer.json +++ b/composer.json @@ -1,4 +1,5 @@ { + "name": "part-db/part-db-server", "type": "project", "license": "AGPL-3.0-or-later", "require": { @@ -10,21 +11,24 @@ "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", + "amphp/http-client": "^5.1", + "api-platform/core": "^3.1", "beberlei/doctrineextensions": "^1.2", - "brick/math": "^0.11.0", + "brick/math": "0.12.1 as 0.11.0", + "composer/ca-bundle": "^1.5", "composer/package-versions-deprecated": "^1.11.99.5", - "doctrine/annotations": "1.14.3", - "doctrine/data-fixtures": "^1.6.6", - "doctrine/dbal": "^3.4.6", + "doctrine/data-fixtures": "^2.0.0", + "doctrine/dbal": "^4.0.0", "doctrine/doctrine-bundle": "^2.0", "doctrine/doctrine-migrations-bundle": "^3.0", - "doctrine/orm": "dev-entity-level-commit-order#44d2a83 as 2.15.3", - "dompdf/dompdf": "dev-master#87bea32efe0b0db309e1d31537201f64d5508280 as v2.0.3", + "doctrine/orm": "^3.2.0", + "dompdf/dompdf": "^v3.0.0", "erusev/parsedown": "^1.7", "florianv/swap": "^4.0", "florianv/swap-bundle": "dev-master", "gregwar/captcha-bundle": "^2.1.0", - "jbtronics/2fa-webauthn": "^v2.0.0", + "hshn/base64-encoded-file": "^5.0", + "jbtronics/2fa-webauthn": "^v2.2.0", "jbtronics/dompdf-font-loader-bundle": "^1.0.0", "jfcherng/php-diff": "^6.14", "knpuniversity/oauth2-client-bundle": "^2.15", @@ -33,13 +37,14 @@ "liip/imagine-bundle": "^2.2", "nbgrp/onelogin-saml-bundle": "^1.3", "nelexa/zip": "^4.0", + "nelmio/cors-bundle": "^2.3", "nelmio/security-bundle": "^3.0", "nyholm/psr7": "^1.1", - "ocramius/proxy-manager": "2.2.*", - "omines/datatables-bundle": "^0.7.2", + "omines/datatables-bundle": "^0.9.1", + "paragonie/sodium_compat": "^1.21", "part-db/label-fonts": "^1.0", - "php-translation/symfony-bundle": "^0.14.0", - "phpdocumentor/reflection-docblock": "^5.2", + "rhukster/dom-sanitizer": "^1.0", + "runtime/frankenphp-symfony": "^0.2.0", "s9e/text-formatter": "^2.1", "scheb/2fa-backup-code": "^6.8.0", "scheb/2fa-bundle": "^6.8.0", @@ -48,64 +53,66 @@ "shivas/versioning-bundle": "^4.0", "spatie/db-dumper": "^3.3.1", "symfony/apache-pack": "^1.0", - "symfony/asset": "6.3.*", - "symfony/console": "6.3.*", - "symfony/dotenv": "6.3.*", - "symfony/expression-language": "6.3.*", + "symfony/asset": "6.4.*", + "symfony/console": "6.4.*", + "symfony/css-selector": "6.4.*", + "symfony/dom-crawler": "6.4.*", + "symfony/dotenv": "6.4.*", + "symfony/expression-language": "6.4.*", "symfony/flex": "^v2.3.1", - "symfony/form": "6.3.*", - "symfony/framework-bundle": "6.3.*", - "symfony/http-client": "6.3.*", - "symfony/http-kernel": "6.3.*", - "symfony/mailer": "6.3.*", + "symfony/form": "6.4.*", + "symfony/framework-bundle": "6.4.*", + "symfony/http-client": "6.4.*", + "symfony/http-kernel": "6.4.*", + "symfony/mailer": "6.4.*", "symfony/monolog-bundle": "^3.1", - "symfony/process": "6.3.*", - "symfony/property-access": "6.3.*", - "symfony/property-info": "6.3.*", - "symfony/proxy-manager-bridge": "6.3.*", - "symfony/rate-limiter": "6.3.*", - "symfony/runtime": "6.3.*", - "symfony/security-bundle": "6.3.*", - "symfony/serializer": "6.3.*", - "symfony/translation": "6.3.*", - "symfony/twig-bundle": "6.3.*", + "symfony/polyfill-php82": "^1.28", + "symfony/process": "6.4.*", + "symfony/property-access": "6.4.*", + "symfony/property-info": "6.4.*", + "symfony/rate-limiter": "6.4.*", + "symfony/runtime": "6.4.*", + "symfony/security-bundle": "6.4.*", + "symfony/serializer": "6.4.*", + "symfony/string": "6.4.*", + "symfony/translation": "6.4.*", + "symfony/twig-bundle": "6.4.*", "symfony/ux-translator": "^2.10", "symfony/ux-turbo": "^2.0", - "symfony/validator": "6.3.*", - "symfony/web-link": "6.3.*", + "symfony/validator": "6.4.*", + "symfony/web-link": "6.4.*", "symfony/webpack-encore-bundle": "^v2.0.1", - "symfony/yaml": "6.3.*", - "tecnickcom/tc-lib-barcode": "^1.15", + "symfony/yaml": "6.4.*", + "tecnickcom/tc-lib-barcode": "^2.1.4", "twig/cssinliner-extra": "^3.0", - "twig/extra-bundle": "^3.0", - "twig/html-extra": "^3.0", + "twig/extra-bundle": "^3.8", + "twig/html-extra": "^3.8", "twig/inky-extra": "^3.0", - "twig/intl-extra": "^3.0", - "twig/markdown-extra": "^3.0", - "web-auth/webauthn-symfony-bundle": "^4.0.0", - "webmozart/assert": "^1.4" + "twig/intl-extra": "^3.8", + "twig/markdown-extra": "^3.8", + "twig/string-extra": "^3.8", + "web-auth/webauthn-symfony-bundle": "^4.0.0" }, "require-dev": { - "dama/doctrine-test-bundle": "^7.0", - "doctrine/doctrine-fixtures-bundle": "^3.2", - "ekino/phpstan-banned-code": "^v1.0.0", + "dama/doctrine-test-bundle": "^v8.0.0", + "doctrine/doctrine-fixtures-bundle": "^4.0.0", + "ekino/phpstan-banned-code": "^v3.0.0", + "jbtronics/translation-editor-bundle": "^1.0", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.4.7", - "phpstan/phpstan-doctrine": "^1.2.11", - "phpstan/phpstan-strict-rules": "^1.5", - "phpstan/phpstan-symfony": "^1.1.7", - "psalm/plugin-symfony": "^v5.0.1", - "rector/rector": "^0.17.0", + "phpstan/phpstan": "^2.0.4", + "phpstan/phpstan-doctrine": "^2.0.1", + "phpstan/phpstan-strict-rules": "^2.0.1", + "phpstan/phpstan-symfony": "^2.0.0", + "phpunit/phpunit": "^9.5", + "rector/rector": "^2.0.4", "roave/security-advisories": "dev-latest", - "symfony/browser-kit": "6.3.*", - "symfony/css-selector": "6.3.*", - "symfony/debug-bundle": "6.3.*", + "symfony/browser-kit": "6.4.*", + "symfony/debug-bundle": "6.4.*", "symfony/maker-bundle": "^1.13", - "symfony/phpunit-bridge": "6.3.*", - "symfony/stopwatch": "6.3.*", - "symfony/web-profiler-bundle": "6.3.*", - "symplify/easy-coding-standard": "^11.0", - "vimeo/psalm": "^5.6.0" + "symfony/phpunit-bridge": "6.4.*", + "symfony/stopwatch": "6.4.*", + "symfony/web-profiler-bundle": "6.4.*", + "symplify/easy-coding-standard": "^12.0" }, "suggest": { "ext-bcmath": "Used to improve price calculation performance", @@ -156,7 +163,8 @@ "extra": { "symfony": { "allow-contrib": false, - "require": "6.3.*" + "require": "6.4.*", + "docker": true } } } diff --git a/composer.lock b/composer.lock index 08fca3d9..4d658092 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,1201 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1c3a6a5bba2865b104630aaf4336e483", + "content-hash": "27cd0d915eab5e7cb57215a4c0b529fb", "packages": [ { - "name": "beberlei/assert", - "version": "v3.3.2", + "name": "amphp/amp", + "version": "v3.1.0", "source": { "type": "git", - "url": "https://github.com/beberlei/assert.git", - "reference": "cb70015c04be1baee6f5f5c953703347c0ac1655" + "url": "https://github.com/amphp/amp.git", + "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/cb70015c04be1baee6f5f5c953703347c0ac1655", - "reference": "cb70015c04be1baee6f5f5c953703347c0ac1655", + "url": "https://api.github.com/repos/amphp/amp/zipball/7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", + "reference": "7cf7fef3d667bfe4b2560bc87e67d5387a7bcde9", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.23.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Future/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "https://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/v3.1.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-01-26T16:07:39+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46", + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/parser": "^1.1", + "amphp/pipeline": "^1", + "amphp/serialization": "^1", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2.3" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.22.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\ByteStream\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "https://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "support": { + "issues": "https://github.com/amphp/byte-stream/issues", + "source": "https://github.com/amphp/byte-stream/tree/v2.1.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-03-16T17:10:27+00:00" + }, + { + "name": "amphp/cache", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/cache.git", + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c", + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/serialization": "^1", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Cache\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A fiber-aware cache API based on Amp and Revolt.", + "homepage": "https://amphp.org/cache", + "support": { + "issues": "https://github.com/amphp/cache/issues", + "source": "https://github.com/amphp/cache/tree/v2.0.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-19T03:38:06+00:00" + }, + { + "name": "amphp/dns", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/dns.git", + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/cache": "^2", + "amphp/parser": "^1", + "amphp/process": "^2", + "daverandom/libdns": "^2.0.2", + "ext-filter": "*", + "ext-json": "*", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.20" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Dns\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Wright", + "email": "addr@daverandom.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Async DNS resolution for Amp.", + "homepage": "https://github.com/amphp/dns", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "dns", + "resolve" + ], + "support": { + "issues": "https://github.com/amphp/dns/issues", + "source": "https://github.com/amphp/dns/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-01-19T15:43:40+00:00" + }, + { + "name": "amphp/hpack", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/hpack.git", + "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/hpack/zipball/4f293064b15682a2b178b1367ddf0b8b5feb0239", + "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "http2jp/hpack-test-case": "^1", + "nikic/php-fuzzer": "^0.0.10", + "phpunit/phpunit": "^7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "HTTP/2 HPack implementation.", + "homepage": "https://github.com/amphp/hpack", + "keywords": [ + "headers", + "hpack", + "http-2" + ], + "support": { + "issues": "https://github.com/amphp/hpack/issues", + "source": "https://github.com/amphp/hpack/tree/v3.2.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-03-21T19:00:16+00:00" + }, + { + "name": "amphp/http", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/http.git", + "reference": "3680d80bd38b5d6f3c2cef2214ca6dd6cef26588" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http/zipball/3680d80bd38b5d6f3c2cef2214ca6dd6cef26588", + "reference": "3680d80bd38b5d6f3c2cef2214ca6dd6cef26588", + "shasum": "" + }, + "require": { + "amphp/hpack": "^3", + "amphp/parser": "^1.1", + "league/uri-components": "^2.4.2 | ^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "league/uri": "^6.8 | ^7.1", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.26.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/constants.php" + ], + "psr-4": { + "Amp\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Basic HTTP primitives which can be shared by servers and clients.", + "support": { + "issues": "https://github.com/amphp/http/issues", + "source": "https://github.com/amphp/http/tree/v2.1.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-11-23T14:57:26+00:00" + }, + { + "name": "amphp/http-client", + "version": "v5.3.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/http-client.git", + "reference": "cf885bf00550d645a27605626528a3b2ce5563ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http-client/zipball/cf885bf00550d645a27605626528a3b2ce5563ae", + "reference": "cf885bf00550d645a27605626528a3b2ce5563ae", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/hpack": "^3", + "amphp/http": "^2", + "amphp/pipeline": "^1", + "amphp/socket": "^2", + "amphp/sync": "^2", + "league/uri": "^7", + "league/uri-components": "^7", + "league/uri-interfaces": "^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2", + "revolt/event-loop": "^1" + }, + "conflict": { + "amphp/file": "<3 | >=5" + }, + "require-dev": { + "amphp/file": "^3 | ^4", + "amphp/http-server": "^3", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "ext-json": "*", + "kelunik/link-header-rfc5988": "^1", + "laminas/laminas-diactoros": "^2.3", + "phpunit/phpunit": "^9", + "psalm/phar": "~5.23" + }, + "suggest": { + "amphp/file": "Required for file request bodies and HTTP archive logging", + "ext-json": "Required for logging HTTP archives", + "ext-zlib": "Allows using compression for response bodies." + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\Http\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "An advanced async HTTP client library for PHP, enabling efficient, non-blocking, and concurrent requests and responses.", + "homepage": "https://amphp.org/http-client", + "keywords": [ + "async", + "client", + "concurrent", + "http", + "non-blocking", + "rest" + ], + "support": { + "issues": "https://github.com/amphp/http-client/issues", + "source": "https://github.com/amphp/http-client/tree/v5.3.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-05-18T18:27:44+00:00" + }, + { + "name": "amphp/parser", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/parser.git", + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Parser\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A generator parser to make streaming parsers simple.", + "homepage": "https://github.com/amphp/parser", + "keywords": [ + "async", + "non-blocking", + "parser", + "stream" + ], + "support": { + "issues": "https://github.com/amphp/parser/issues", + "source": "https://github.com/amphp/parser/tree/v1.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-03-21T19:16:53+00:00" + }, + { + "name": "amphp/pipeline", + "version": "v1.2.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/pipeline.git", + "reference": "7b52598c2e9105ebcddf247fc523161581930367" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367", + "reference": "7b52598c2e9105ebcddf247fc523161581930367", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "php": ">=8.1", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.18" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Pipeline\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Asynchronous iterators and operators.", + "homepage": "https://amphp.org/pipeline", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "iterator", + "non-blocking" + ], + "support": { + "issues": "https://github.com/amphp/pipeline/issues", + "source": "https://github.com/amphp/pipeline/tree/v1.2.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-03-16T16:33:53+00:00" + }, + { + "name": "amphp/process", + "version": "v2.0.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/process.git", + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Process\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A fiber-aware process manager based on Amp and Revolt.", + "homepage": "https://amphp.org/process", + "support": { + "issues": "https://github.com/amphp/process/issues", + "source": "https://github.com/amphp/process/tree/v2.0.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-19T03:13:44+00:00" + }, + { + "name": "amphp/serialization", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/serialization.git", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "phpunit/phpunit": "^9 || ^8 || ^7" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Serialization\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Serialization tools for IPC and data storage in PHP.", + "homepage": "https://github.com/amphp/serialization", + "keywords": [ + "async", + "asynchronous", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/amphp/serialization/issues", + "source": "https://github.com/amphp/serialization/tree/master" + }, + "time": "2020-03-25T21:39:07+00:00" + }, + { + "name": "amphp/socket", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/socket.git", + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1", + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/dns": "^2", + "ext-openssl": "*", + "kelunik/certificate": "^1.1", + "league/uri": "^6.5 | ^7", + "league/uri-interfaces": "^2.3 | ^7", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/process": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.20" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php", + "src/SocketAddress/functions.php" + ], + "psr-4": { + "Amp\\Socket\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Non-blocking socket connection / server implementations based on Amp and Revolt.", + "homepage": "https://github.com/amphp/socket", + "keywords": [ + "amp", + "async", + "encryption", + "non-blocking", + "sockets", + "tcp", + "tls" + ], + "support": { + "issues": "https://github.com/amphp/socket/issues", + "source": "https://github.com/amphp/socket/tree/v2.3.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-21T14:33:03+00:00" + }, + { + "name": "amphp/sync", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/sync.git", + "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/sync/zipball/217097b785130d77cfcc58ff583cf26cd1770bf1", + "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/pipeline": "^1", + "amphp/serialization": "^1", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.23" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Sync\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Stephen Coakley", + "email": "me@stephencoakley.com" + } + ], + "description": "Non-blocking synchronization primitives for PHP based on Amp and Revolt.", + "homepage": "https://github.com/amphp/sync", + "keywords": [ + "async", + "asynchronous", + "mutex", + "semaphore", + "synchronization" + ], + "support": { + "issues": "https://github.com/amphp/sync/issues", + "source": "https://github.com/amphp/sync/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-08-03T19:31:26+00:00" + }, + { + "name": "api-platform/core", + "version": "v3.4.17", + "source": { + "type": "git", + "url": "https://github.com/api-platform/core.git", + "reference": "c5fb664d17ed9ae919394514ea69a5039d2ad9ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/api-platform/core/zipball/c5fb664d17ed9ae919394514ea69a5039d2ad9ab", + "reference": "c5fb664d17ed9ae919394514ea69a5039d2ad9ab", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^1.0 || ^2.0", + "php": ">=8.1", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^3.1", + "symfony/http-foundation": "^6.4 || ^7.1", + "symfony/http-kernel": "^6.4 || ^7.1", + "symfony/property-access": "^6.4 || ^7.1", + "symfony/property-info": "^6.4 || ^7.1", + "symfony/serializer": "^6.4 || ^7.1", + "symfony/translation-contracts": "^3.3", + "symfony/web-link": "^6.4 || ^7.1", + "willdurand/negotiation": "^3.0" + }, + "conflict": { + "doctrine/common": "<3.2.2", + "doctrine/dbal": "<2.10", + "doctrine/mongodb-odm": "<2.4", + "doctrine/orm": "<2.14.0", + "doctrine/persistence": "<1.3", + "elasticsearch/elasticsearch": ">=8.0,<8.4", + "phpspec/prophecy": "<1.15", + "phpunit/phpunit": "<9.5", + "symfony/framework-bundle": "6.4.6 || 7.0.6", + "symfony/var-exporter": "<6.1.1" + }, + "replace": { + "api-platform/doctrine-common": "self.version", + "api-platform/doctrine-odm": "self.version", + "api-platform/doctrine-orm": "self.version", + "api-platform/documentation": "self.version", + "api-platform/elasticsearch": "self.version", + "api-platform/graphql": "self.version", + "api-platform/http-cache": "self.version", + "api-platform/hydra": "self.version", + "api-platform/json-api": "self.version", + "api-platform/json-hal": "self.version", + "api-platform/json-schema": "self.version", + "api-platform/jsonld": "self.version", + "api-platform/laravel": "self.version", + "api-platform/metadata": "self.version", + "api-platform/openapi": "self.version", + "api-platform/parameter-validator": "self.version", + "api-platform/ramsey-uuid": "self.version", + "api-platform/serializer": "self.version", + "api-platform/state": "self.version", + "api-platform/symfony": "self.version", + "api-platform/validator": "self.version" + }, + "require-dev": { + "api-platform/doctrine-common": "^3.4 || ^4.0", + "api-platform/doctrine-odm": "^3.4 || ^4.0", + "api-platform/doctrine-orm": "^3.4 || ^4.0", + "api-platform/documentation": "^3.4 || ^4.0", + "api-platform/elasticsearch": "^3.4 || ^4.0", + "api-platform/graphql": "^3.4 || ^4.0", + "api-platform/http-cache": "^3.4 || ^4.0", + "api-platform/hydra": "^3.4 || ^4.0", + "api-platform/json-api": "^3.3 || ^4.0", + "api-platform/json-schema": "^3.4 || ^4.0", + "api-platform/jsonld": "^3.4 || ^4.0", + "api-platform/metadata": "^3.4 || ^4.0", + "api-platform/openapi": "^3.4 || ^4.0", + "api-platform/parameter-validator": "^3.4", + "api-platform/ramsey-uuid": "^3.4 || ^4.0", + "api-platform/serializer": "^3.4 || ^4.0", + "api-platform/state": "^3.4 || ^4.0", + "api-platform/validator": "^3.4 || ^4.0", + "behat/behat": "^3.11", + "behat/mink": "^1.9", + "doctrine/cache": "^1.11 || ^2.1", + "doctrine/common": "^3.2.2", + "doctrine/dbal": "^3.4.0 || ^4.0", + "doctrine/doctrine-bundle": "^1.12 || ^2.0", + "doctrine/mongodb-odm": "^2.2", + "doctrine/mongodb-odm-bundle": "^4.0 || ^5.0", + "doctrine/orm": "^2.14 || ^3.0", + "elasticsearch/elasticsearch": "^7.11 || ^8.4", + "friends-of-behat/mink-browserkit-driver": "^1.3.1", + "friends-of-behat/mink-extension": "^2.2", + "friends-of-behat/symfony-extension": "^2.1", + "guzzlehttp/guzzle": "^6.0 || ^7.1", + "jangregor/phpstan-prophecy": "^1.0", + "justinrainbow/json-schema": "^5.2.1", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpdoc-parser": "^1.13|^2.0", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-doctrine": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-symfony": "^1.0", + "phpunit/phpunit": "^9.6", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "ramsey/uuid": "^3.9.7 || ^4.0", + "ramsey/uuid-doctrine": "^1.4 || ^2.0 || ^3.0", + "sebastian/comparator": "<5.0", + "soyuka/contexts": "v3.3.9", + "soyuka/pmu": "^0.0.12", + "soyuka/stubs-mongodb": "^1.0", + "symfony/asset": "^6.4 || ^7.1", + "symfony/browser-kit": "^6.4 || ^7.1", + "symfony/cache": "^6.4 || ^7.1", + "symfony/config": "^6.4 || ^7.1", + "symfony/console": "^6.4 || ^7.1", + "symfony/css-selector": "^6.4 || ^7.1", + "symfony/dependency-injection": "^6.4 || ^7.1", + "symfony/doctrine-bridge": "^6.4 || ^7.1", + "symfony/dom-crawler": "^6.4 || ^7.1", + "symfony/error-handler": "^6.4 || ^7.1", + "symfony/event-dispatcher": "^6.4 || ^7.1", + "symfony/expression-language": "^6.4 || ^7.1", + "symfony/finder": "^6.4 || ^7.1", + "symfony/form": "^6.4 || ^7.1", + "symfony/framework-bundle": "^6.4 || ^7.1", + "symfony/http-client": "^6.4 || ^7.1", + "symfony/intl": "^6.4 || ^7.1", + "symfony/maker-bundle": "^1.24", + "symfony/mercure-bundle": "*", + "symfony/messenger": "^6.4 || ^7.1", + "symfony/phpunit-bridge": "^6.4.1 || ^7.1", + "symfony/routing": "^6.4 || ^7.1", + "symfony/security-bundle": "^6.4 || ^7.1", + "symfony/security-core": "^6.4 || ^7.1", + "symfony/stopwatch": "^6.4 || ^7.1", + "symfony/string": "^6.4 || ^7.1", + "symfony/twig-bundle": "^6.4 || ^7.1", + "symfony/uid": "^6.4 || ^7.1", + "symfony/validator": "^6.4 || ^7.1", + "symfony/web-profiler-bundle": "^6.4 || ^7.1", + "symfony/yaml": "^6.4 || ^7.1", + "twig/twig": "^1.42.3 || ^2.12 || ^3.0", + "webonyx/graphql-php": "^14.0 || ^15.0" + }, + "suggest": { + "doctrine/mongodb-odm-bundle": "To support MongoDB. Only versions 4.0 and later are supported.", + "elasticsearch/elasticsearch": "To support Elasticsearch.", + "ocramius/package-versions": "To display the API Platform's version in the debug bar.", + "phpstan/phpdoc-parser": "To support extracting metadata from PHPDoc.", + "psr/cache-implementation": "To use metadata caching.", + "ramsey/uuid": "To support Ramsey's UUID identifiers.", + "symfony/cache": "To have metadata caching when using Symfony integration.", + "symfony/config": "To load XML configuration files.", + "symfony/expression-language": "To use authorization features.", + "symfony/http-client": "To use the HTTP cache invalidation system.", + "symfony/messenger": "To support messenger integration.", + "symfony/security": "To use authorization features.", + "symfony/twig-bundle": "To use the Swagger UI integration.", + "symfony/uid": "To support Symfony UUID/ULID identifiers.", + "symfony/web-profiler-bundle": "To use the data collector.", + "webonyx/graphql-php": "To support GraphQL." + }, + "type": "library", + "extra": { + "pmu": { + "projects": [ + "./src/*/composer.json", + "src/Doctrine/*/composer.json" + ] + }, + "thanks": { + "url": "https://github.com/api-platform/api-platform", + "name": "api-platform/api-platform" + }, + "symfony": { + "require": "^6.4 || ^7.1" + }, + "branch-alias": { + "dev-3.4": "3.4.x-dev", + "dev-main": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "ApiPlatform\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.fr", + "homepage": "https://dunglas.fr" + } + ], + "description": "Build a fully-featured hypermedia or GraphQL API in minutes!", + "homepage": "https://api-platform.com", + "keywords": [ + "Hydra", + "JSON-LD", + "api", + "graphql", + "hal", + "jsonapi", + "openapi", + "rest", + "swagger" + ], + "support": { + "issues": "https://github.com/api-platform/core/issues", + "source": "https://github.com/api-platform/core/tree/v3.4.17" + }, + "time": "2025-04-07T08:40:57+00:00" + }, + { + "name": "beberlei/assert", + "version": "v3.3.3", + "source": { + "type": "git", + "url": "https://github.com/beberlei/assert.git", + "reference": "b5fd8eacd8915a1b627b8bfc027803f1939734dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beberlei/assert/zipball/b5fd8eacd8915a1b627b8bfc027803f1939734dd", + "reference": "b5fd8eacd8915a1b627b8bfc027803f1939734dd", "shasum": "" }, "require": { @@ -25,7 +1206,7 @@ "ext-json": "*", "ext-mbstring": "*", "ext-simplexml": "*", - "php": "^7.0 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "*", @@ -69,33 +1250,38 @@ ], "support": { "issues": "https://github.com/beberlei/assert/issues", - "source": "https://github.com/beberlei/assert/tree/v3.3.2" + "source": "https://github.com/beberlei/assert/tree/v3.3.3" }, - "time": "2021-12-16T21:41:27+00:00" + "time": "2024-07-15T13:18:35+00:00" }, { "name": "beberlei/doctrineextensions", - "version": "v1.3.0", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/beberlei/DoctrineExtensions.git", - "reference": "008f162f191584a6c37c03a803f718802ba9dd9a" + "reference": "281f1650641c2f438b0a54d8eaa7ba50ac7e3eb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/DoctrineExtensions/zipball/008f162f191584a6c37c03a803f718802ba9dd9a", - "reference": "008f162f191584a6c37c03a803f718802ba9dd9a", + "url": "https://api.github.com/repos/beberlei/DoctrineExtensions/zipball/281f1650641c2f438b0a54d8eaa7ba50ac7e3eb6", + "reference": "281f1650641c2f438b0a54d8eaa7ba50ac7e3eb6", "shasum": "" }, "require": { - "doctrine/orm": "^2.7", + "doctrine/orm": "^2.19 || ^3.0", "php": "^7.2 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "nesbot/carbon": "*", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", - "symfony/yaml": "^4.2 || ^5.0", + "doctrine/annotations": "^1.14 || ^2", + "doctrine/coding-standard": "^9.0.2 || ^12.0", + "nesbot/carbon": "^2.72 || ^3", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5 || ^9.6", + "squizlabs/php_codesniffer": "^3.8", + "symfony/cache": "^5.4 || ^6.4 || ^7.0", + "symfony/yaml": "^5.4 || ^6.4 || ^7.0", + "vimeo/psalm": "^3.18 || ^5.22", "zf1/zend-date": "^1.12", "zf1/zend-registry": "^1.12" }, @@ -126,31 +1312,31 @@ "orm" ], "support": { - "source": "https://github.com/beberlei/DoctrineExtensions/tree/v1.3.0" + "source": "https://github.com/beberlei/DoctrineExtensions/tree/v1.5.0" }, - "time": "2020-11-29T07:37:23+00:00" + "time": "2024-03-03T17:55:15+00:00" }, { "name": "brick/math", - "version": "0.11.0", + "version": "0.12.1", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478" + "reference": "f510c0a40911935b77b86859eb5223d58d660df1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478", - "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478", + "url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1", + "reference": "f510c0a40911935b77b86859eb5223d58d660df1", "shasum": "" }, "require": { - "php": "^8.0" + "php": "^8.1" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^9.0", - "vimeo/psalm": "5.0.0" + "phpunit/phpunit": "^10.1", + "vimeo/psalm": "5.16.0" }, "type": "library", "autoload": { @@ -170,12 +1356,17 @@ "arithmetic", "bigdecimal", "bignum", + "bignumber", "brick", - "math" + "decimal", + "integer", + "math", + "mathematics", + "rational" ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.11.0" + "source": "https://github.com/brick/math/tree/0.12.1" }, "funding": [ { @@ -183,32 +1374,32 @@ "type": "github" } ], - "time": "2023-01-15T23:15:59+00:00" + "time": "2023-11-29T23:19:16+00:00" }, { "name": "composer/ca-bundle", - "version": "1.3.6", + "version": "1.5.6", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "90d087e988ff194065333d16bc5cf649872d9cdb" + "reference": "f65c239c970e7f072f067ab78646e9f0b2935175" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/90d087e988ff194065333d16bc5cf649872d9cdb", - "reference": "90d087e988ff194065333d16bc5cf649872d9cdb", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/f65c239c970e7f072f067ab78646e9f0b2935175", + "reference": "f65c239c970e7f072f067ab78646e9f0b2935175", "shasum": "" }, "require": { "ext-openssl": "*", "ext-pcre": "*", - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.55", - "psr/log": "^1.0", - "symfony/phpunit-bridge": "^4.2 || ^5", - "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + "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": { @@ -243,7 +1434,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.3.6" + "source": "https://github.com/composer/ca-bundle/tree/1.5.6" }, "funding": [ { @@ -259,7 +1450,7 @@ "type": "tidelift" } ], - "time": "2023-06-06T12:02:59+00:00" + "time": "2025-03-06T14:30:56+00:00" }, { "name": "composer/package-versions-deprecated", @@ -335,199 +1526,74 @@ "time": "2022-01-17T14:14:24+00:00" }, { - "name": "doctrine/annotations", - "version": "1.14.3", + "name": "daverandom/libdns", + "version": "v2.1.0", "source": { "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af" + "url": "https://github.com/DaveRandom/LibDNS.git", + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", - "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", + "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", "shasum": "" }, "require": { - "doctrine/lexer": "^1 || ^2", - "ext-tokenizer": "*", - "php": "^7.1 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^1.11 || ^2.0", - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "~1.4.10 || ^1.8.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "vimeo/psalm": "^4.10" + "ext-ctype": "*", + "php": ">=7.1" }, "suggest": { - "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + "ext-intl": "Required for IDN support" }, "type": "library", "autoload": { + "files": [ + "src/functions.php" + ], "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + "LibDNS\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "description": "DNS protocol implementation written in pure PHP", "keywords": [ - "annotations", - "docblock", - "parser" + "dns" ], "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.14.3" + "issues": "https://github.com/DaveRandom/LibDNS/issues", + "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0" }, - "time": "2023-02-01T09:20:38+00:00" - }, - { - "name": "doctrine/cache", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb", - "shasum": "" - }, - "require": { - "php": "~7.1 || ^8.0" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "homepage": "https://www.doctrine-project.org/projects/cache.html", - "keywords": [ - "abstraction", - "apcu", - "cache", - "caching", - "couchdb", - "memcached", - "php", - "redis", - "xcache" - ], - "support": { - "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/2.2.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", - "type": "tidelift" - } - ], - "time": "2022-05-20T20:07:39+00:00" + "time": "2024-04-12T12:12:48+00:00" }, { "name": "doctrine/collections", - "version": "2.1.3", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "3023e150f90a38843856147b58190aa8b46cc155" + "reference": "2eb07e5953eed811ce1b309a7478a3b236f2273d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/3023e150f90a38843856147b58190aa8b46cc155", - "reference": "3023e150f90a38843856147b58190aa8b46cc155", + "url": "https://api.github.com/repos/doctrine/collections/zipball/2eb07e5953eed811ce1b309a7478a3b236f2273d", + "reference": "2eb07e5953eed811ce1b309a7478a3b236f2273d", "shasum": "" }, "require": { "doctrine/deprecations": "^1", - "php": "^8.1" + "php": "^8.1", + "symfony/polyfill-php84": "^1.30" }, "require-dev": { - "doctrine/coding-standard": "^10.0", + "doctrine/coding-standard": "^12", "ext-json": "*", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^5.11" + "phpunit/phpunit": "^10.5" }, "type": "library", "autoload": { @@ -571,7 +1637,7 @@ ], "support": { "issues": "https://github.com/doctrine/collections/issues", - "source": "https://github.com/doctrine/collections/tree/2.1.3" + "source": "https://github.com/doctrine/collections/tree/2.3.0" }, "funding": [ { @@ -587,133 +1653,43 @@ "type": "tidelift" } ], - "time": "2023-07-06T15:15:36+00:00" - }, - { - "name": "doctrine/common", - "version": "3.4.3", - "source": { - "type": "git", - "url": "https://github.com/doctrine/common.git", - "reference": "8b5e5650391f851ed58910b3e3d48a71062eeced" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/8b5e5650391f851ed58910b3e3d48a71062eeced", - "reference": "8b5e5650391f851ed58910b3e3d48a71062eeced", - "shasum": "" - }, - "require": { - "doctrine/persistence": "^2.0 || ^3.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9.0 || ^10.0", - "doctrine/collections": "^1", - "phpstan/phpstan": "^1.4.1", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0", - "squizlabs/php_codesniffer": "^3.0", - "symfony/phpunit-bridge": "^6.1", - "vimeo/psalm": "^4.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.", - "homepage": "https://www.doctrine-project.org/projects/common.html", - "keywords": [ - "common", - "doctrine", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/common/issues", - "source": "https://github.com/doctrine/common/tree/3.4.3" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcommon", - "type": "tidelift" - } - ], - "time": "2022-10-09T11:47:59+00:00" + "time": "2025-03-22T10:17:19+00:00" }, { "name": "doctrine/data-fixtures", - "version": "1.6.6", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/doctrine/data-fixtures.git", - "reference": "4af35dadbfcf4b00abb2a217c4c8c8800cf5fcf4" + "reference": "f7f1e12d6bceb58c204b3e77210a103c1c57601e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/4af35dadbfcf4b00abb2a217c4c8c8800cf5fcf4", - "reference": "4af35dadbfcf4b00abb2a217c4c8c8800cf5fcf4", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/f7f1e12d6bceb58c204b3e77210a103c1c57601e", + "reference": "f7f1e12d6bceb58c204b3e77210a103c1c57601e", "shasum": "" }, "require": { - "doctrine/deprecations": "^0.5.3 || ^1.0", - "doctrine/persistence": "^1.3.3 || ^2.0 || ^3.0", - "php": "^7.2 || ^8.0" + "doctrine/persistence": "^3.1 || ^4.0", + "php": "^8.1", + "psr/log": "^1.1 || ^2 || ^3" }, "conflict": { - "doctrine/dbal": "<2.13", - "doctrine/orm": "<2.12", + "doctrine/dbal": "<3.5 || >=5", + "doctrine/orm": "<2.14 || >=4", "doctrine/phpcr-odm": "<1.3.0" }, "require-dev": { - "doctrine/coding-standard": "^11.0", - "doctrine/dbal": "^2.13 || ^3.0", + "doctrine/coding-standard": "^12", + "doctrine/dbal": "^3.5 || ^4", "doctrine/mongodb-odm": "^1.3.0 || ^2.0.0", - "doctrine/orm": "^2.12", + "doctrine/orm": "^2.14 || ^3", "ext-sqlite3": "*", - "phpstan/phpstan": "^1.5", - "phpunit/phpunit": "^8.5 || ^9.5 || ^10.0", - "symfony/cache": "^5.0 || ^6.0", - "vimeo/psalm": "^4.10 || ^5.9" + "fig/log-test": "^1", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5.3", + "symfony/cache": "^6.4 || ^7", + "symfony/var-exporter": "^6.4 || ^7" }, "suggest": { "alcaeus/mongo-php-adapter": "For using MongoDB ODM 1.3 with PHP 7 (deprecated)", @@ -744,7 +1720,7 @@ ], "support": { "issues": "https://github.com/doctrine/data-fixtures/issues", - "source": "https://github.com/doctrine/data-fixtures/tree/1.6.6" + "source": "https://github.com/doctrine/data-fixtures/tree/2.0.2" }, "funding": [ { @@ -760,50 +1736,44 @@ "type": "tidelift" } ], - "time": "2023-04-20T13:08:54+00:00" + "time": "2025-01-21T13:21:31+00:00" }, { "name": "doctrine/dbal", - "version": "3.6.5", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "96d5a70fd91efdcec81fc46316efc5bf3da17ddf" + "reference": "33d2d7fe1269b2301640c44cf2896ea607b30e3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/96d5a70fd91efdcec81fc46316efc5bf3da17ddf", - "reference": "96d5a70fd91efdcec81fc46316efc5bf3da17ddf", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/33d2d7fe1269b2301640c44cf2896ea607b30e3e", + "reference": "33d2d7fe1269b2301640c44cf2896ea607b30e3e", "shasum": "" }, "require": { - "composer-runtime-api": "^2", - "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3|^1", - "doctrine/event-manager": "^1|^2", - "php": "^7.4 || ^8.0", + "php": "^8.1", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, "require-dev": { "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", - "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.10.21", - "phpstan/phpstan-strict-rules": "^1.5", - "phpunit/phpunit": "9.6.9", - "psalm/plugin-phpunit": "0.18.4", - "squizlabs/php_codesniffer": "3.7.2", - "symfony/cache": "^5.4|^6.0", - "symfony/console": "^4.4|^5.4|^6.0", - "vimeo/psalm": "4.30.0" + "jetbrains/phpstorm-stubs": "2023.2", + "phpstan/phpstan": "2.1.1", + "phpstan/phpstan-phpunit": "2.0.3", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "10.5.39", + "slevomat/coding-standard": "8.13.1", + "squizlabs/php_codesniffer": "3.10.2", + "symfony/cache": "^6.3.8|^7.0", + "symfony/console": "^5.4|^6.3|^7.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." }, - "bin": [ - "bin/doctrine-dbal" - ], "type": "library", "autoload": { "psr-4": { @@ -856,7 +1826,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.6.5" + "source": "https://github.com/doctrine/dbal/tree/4.2.3" }, "funding": [ { @@ -872,33 +1842,34 @@ "type": "tidelift" } ], - "time": "2023-07-17T09:15:50+00:00" + "time": "2025-03-07T18:29:05+00:00" }, { "name": "doctrine/deprecations", - "version": "v1.1.1", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3" + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", - "reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" + }, "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "1.4.10 || 1.10.15", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "0.18.4", - "psr/log": "^1 || ^2 || ^3", - "vimeo/psalm": "4.30.0 || 5.12.0" + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "psr/log": "^1 || ^2 || ^3" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" @@ -906,7 +1877,7 @@ "type": "library", "autoload": { "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + "Doctrine\\Deprecations\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -917,64 +1888,70 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.1.1" + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" }, - "time": "2023-06-03T09:27:29+00:00" + "time": "2025-04-07T20:06:18+00:00" }, { "name": "doctrine/doctrine-bundle", - "version": "2.10.1", + "version": "2.14.0", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "f9d59c90b6f525dfc2a2064a695cb56e0ab40311" + "reference": "ca6a7350b421baf7fbdefbf9f4993292ed18effb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/f9d59c90b6f525dfc2a2064a695cb56e0ab40311", - "reference": "f9d59c90b6f525dfc2a2064a695cb56e0ab40311", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/ca6a7350b421baf7fbdefbf9f4993292ed18effb", + "reference": "ca6a7350b421baf7fbdefbf9f4993292ed18effb", "shasum": "" }, "require": { - "doctrine/cache": "^1.11 || ^2.0", - "doctrine/dbal": "^3.6.0", - "doctrine/persistence": "^2.2 || ^3", + "doctrine/dbal": "^3.7.0 || ^4.0", + "doctrine/persistence": "^3.1 || ^4", "doctrine/sql-formatter": "^1.0.1", - "php": "^7.4 || ^8.0", - "symfony/cache": "^5.4 || ^6.0", - "symfony/config": "^5.4 || ^6.0", - "symfony/console": "^5.4 || ^6.0", - "symfony/dependency-injection": "^5.4 || ^6.0", + "php": "^8.1", + "symfony/cache": "^6.4 || ^7.0", + "symfony/config": "^6.4 || ^7.0", + "symfony/console": "^6.4 || ^7.0", + "symfony/dependency-injection": "^6.4 || ^7.0", "symfony/deprecation-contracts": "^2.1 || ^3", - "symfony/doctrine-bridge": "^5.4.19 || ^6.0.7", - "symfony/framework-bundle": "^5.4 || ^6.0", - "symfony/service-contracts": "^1.1.1 || ^2.0 || ^3" + "symfony/doctrine-bridge": "^6.4.3 || ^7.0.3", + "symfony/framework-bundle": "^6.4 || ^7.0", + "symfony/service-contracts": "^2.5 || ^3" }, "conflict": { "doctrine/annotations": ">=3.0", - "doctrine/orm": "<2.11 || >=3.0", - "twig/twig": "<1.34 || >=2.0 <2.4" + "doctrine/cache": "< 1.11", + "doctrine/orm": "<2.17 || >=4.0", + "symfony/var-exporter": "< 6.4.1 || 7.0.0", + "twig/twig": "<2.13 || >=3.0 <3.0.4" }, "require-dev": { "doctrine/annotations": "^1 || ^2", - "doctrine/coding-standard": "^9.0", + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^12", "doctrine/deprecations": "^1.0", - "doctrine/orm": "^2.11 || ^3.0", + "doctrine/orm": "^2.17 || ^3.0", "friendsofphp/proxy-manager-lts": "^1.0", - "phpunit/phpunit": "^9.5.26 || ^10.0", - "psalm/plugin-phpunit": "^0.18.4", - "psalm/plugin-symfony": "^4", + "phpstan/phpstan": "2.1.1", + "phpstan/phpstan-phpunit": "2.0.3", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^9.6.22", "psr/log": "^1.1.4 || ^2.0 || ^3.0", - "symfony/phpunit-bridge": "^6.1", - "symfony/property-info": "^5.4 || ^6.0", - "symfony/proxy-manager-bridge": "^5.4 || ^6.0", - "symfony/security-bundle": "^5.4 || ^6.0", - "symfony/twig-bridge": "^5.4 || ^6.0", - "symfony/validator": "^5.4 || ^6.0", - "symfony/web-profiler-bundle": "^5.4 || ^6.0", - "symfony/yaml": "^5.4 || ^6.0", - "twig/twig": "^1.34 || ^2.12 || ^3.0", - "vimeo/psalm": "^4.30" + "symfony/doctrine-messenger": "^6.4 || ^7.0", + "symfony/messenger": "^6.4 || ^7.0", + "symfony/phpunit-bridge": "^7.2", + "symfony/property-info": "^6.4 || ^7.0", + "symfony/security-bundle": "^6.4 || ^7.0", + "symfony/stopwatch": "^6.4 || ^7.0", + "symfony/string": "^6.4 || ^7.0", + "symfony/twig-bridge": "^6.4 || ^7.0", + "symfony/validator": "^6.4 || ^7.0", + "symfony/var-exporter": "^6.4.1 || ^7.0.1", + "symfony/web-profiler-bundle": "^6.4 || ^7.0", + "symfony/yaml": "^6.4 || ^7.0", + "twig/twig": "^2.13 || ^3.0.4" }, "suggest": { "doctrine/orm": "The Doctrine ORM integration is optional in the bundle.", @@ -984,7 +1961,7 @@ "type": "symfony-bundle", "autoload": { "psr-4": { - "Doctrine\\Bundle\\DoctrineBundle\\": "" + "Doctrine\\Bundle\\DoctrineBundle\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1019,7 +1996,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.10.1" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.14.0" }, "funding": [ { @@ -1035,47 +2012,47 @@ "type": "tidelift" } ], - "time": "2023-06-28T07:47:41+00:00" + "time": "2025-03-22T17:28:21+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", - "version": "3.2.4", + "version": "3.4.2", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", - "reference": "94e6b0fe1a50901d52f59dbb9b4b0737718b2c1e" + "reference": "5a6ac7120c2924c4c070a869d08b11ccf9e277b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/94e6b0fe1a50901d52f59dbb9b4b0737718b2c1e", - "reference": "94e6b0fe1a50901d52f59dbb9b4b0737718b2c1e", + "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/5a6ac7120c2924c4c070a869d08b11ccf9e277b9", + "reference": "5a6ac7120c2924c4c070a869d08b11ccf9e277b9", "shasum": "" }, "require": { - "doctrine/doctrine-bundle": "~1.0|~2.0", + "doctrine/doctrine-bundle": "^2.4", "doctrine/migrations": "^3.2", - "php": "^7.2|^8.0", - "symfony/framework-bundle": "~3.4|~4.0|~5.0|~6.0" + "php": "^7.2 || ^8.0", + "symfony/deprecation-contracts": "^2.1 || ^3", + "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { - "doctrine/coding-standard": "^9", - "doctrine/orm": "^2.6", - "doctrine/persistence": "^1.3||^2.0", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-phpunit": "^1", - "phpstan/phpstan-strict-rules": "^1.1", - "phpunit/phpunit": "^8.5|^9.5", - "vimeo/psalm": "^4.22" + "composer/semver": "^3.0", + "doctrine/coding-standard": "^12", + "doctrine/orm": "^2.6 || ^3", + "phpstan/phpstan": "^1.4 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpstan/phpstan-symfony": "^1.3 || ^2", + "phpunit/phpunit": "^8.5 || ^9.5", + "symfony/phpunit-bridge": "^6.3 || ^7", + "symfony/var-exporter": "^5.4 || ^6 || ^7" }, "type": "symfony-bundle", "autoload": { "psr-4": { - "Doctrine\\Bundle\\MigrationsBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Doctrine\\Bundle\\MigrationsBundle\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1104,7 +2081,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", - "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.2.4" + "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.4.2" }, "funding": [ { @@ -1120,20 +2097,20 @@ "type": "tidelift" } ], - "time": "2023-06-02T08:19:26+00:00" + "time": "2025-03-11T17:36:26+00:00" }, { "name": "doctrine/event-manager", - "version": "2.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32" + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/750671534e0241a7c50ea5b43f67e23eb5c96f32", - "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e", + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e", "shasum": "" }, "require": { @@ -1143,10 +2120,10 @@ "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^10", + "doctrine/coding-standard": "^12", "phpstan/phpstan": "^1.8.8", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^4.28" + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "^5.24" }, "type": "library", "autoload": { @@ -1195,7 +2172,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/2.0.0" + "source": "https://github.com/doctrine/event-manager/tree/2.0.1" }, "funding": [ { @@ -1211,20 +2188,20 @@ "type": "tidelift" } ], - "time": "2022-10-12T20:59:15+00:00" + "time": "2024-05-22T20:47:39+00:00" }, { "name": "doctrine/inflector", - "version": "2.0.8", + "version": "2.0.10", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff" + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff", - "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", "shasum": "" }, "require": { @@ -1286,7 +2263,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.8" + "source": "https://github.com/doctrine/inflector/tree/2.0.10" }, "funding": [ { @@ -1302,7 +2279,7 @@ "type": "tidelift" } ], - "time": "2023-06-16T13:40:37+00:00" + "time": "2024-02-18T20:23:39+00:00" }, { "name": "doctrine/instantiator", @@ -1376,28 +2353,27 @@ }, { "name": "doctrine/lexer", - "version": "2.1.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/lexer.git", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", "shasum": "" }, "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^4.11 || ^5.0" + "vimeo/psalm": "^5.21" }, "type": "library", "autoload": { @@ -1434,7 +2410,7 @@ ], "support": { "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/2.1.0" + "source": "https://github.com/doctrine/lexer/tree/3.0.1" }, "funding": [ { @@ -1450,51 +2426,52 @@ "type": "tidelift" } ], - "time": "2022-12-14T08:49:07+00:00" + "time": "2024-02-05T11:56:58+00:00" }, { "name": "doctrine/migrations", - "version": "3.6.0", + "version": "3.9.0", "source": { "type": "git", "url": "https://github.com/doctrine/migrations.git", - "reference": "e542ad8bcd606d7a18d0875babb8a6d963c9c059" + "reference": "325b61e41d032f5f7d7e2d11cbefff656eadc9ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/migrations/zipball/e542ad8bcd606d7a18d0875babb8a6d963c9c059", - "reference": "e542ad8bcd606d7a18d0875babb8a6d963c9c059", + "url": "https://api.github.com/repos/doctrine/migrations/zipball/325b61e41d032f5f7d7e2d11cbefff656eadc9ab", + "reference": "325b61e41d032f5f7d7e2d11cbefff656eadc9ab", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/dbal": "^3.5.1", + "doctrine/dbal": "^3.6 || ^4", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2.0", "php": "^8.1", "psr/log": "^1.1.3 || ^2 || ^3", - "symfony/console": "^4.4.16 || ^5.4 || ^6.0", - "symfony/stopwatch": "^4.4 || ^5.4 || ^6.0", - "symfony/var-exporter": "^6.2" + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0", + "symfony/var-exporter": "^6.2 || ^7.0" }, "conflict": { - "doctrine/orm": "<2.12" + "doctrine/orm": "<2.12 || >=4" }, "require-dev": { - "doctrine/coding-standard": "^9", - "doctrine/orm": "^2.13", - "doctrine/persistence": "^2 || ^3", + "doctrine/coding-standard": "^12", + "doctrine/orm": "^2.13 || ^3", + "doctrine/persistence": "^2 || ^3 || ^4", "doctrine/sql-formatter": "^1.0", "ext-pdo_sqlite": "*", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.1", - "phpstan/phpstan-symfony": "^1.1", - "phpunit/phpunit": "^9.5.24", - "symfony/cache": "^4.4 || ^5.4 || ^6.0", - "symfony/process": "^4.4 || ^5.4 || ^6.0", - "symfony/yaml": "^4.4 || ^5.4 || ^6.0" + "fig/log-test": "^1", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpstan/phpstan-strict-rules": "^1.4", + "phpstan/phpstan-symfony": "^1.3", + "phpunit/phpunit": "^10.3", + "symfony/cache": "^5.4 || ^6.0 || ^7.0", + "symfony/process": "^5.4 || ^6.0 || ^7.0", + "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, "suggest": { "doctrine/sql-formatter": "Allows to generate formatted SQL with the diff command.", @@ -1506,7 +2483,7 @@ "type": "library", "autoload": { "psr-4": { - "Doctrine\\Migrations\\": "lib/Doctrine/Migrations" + "Doctrine\\Migrations\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1536,7 +2513,7 @@ ], "support": { "issues": "https://github.com/doctrine/migrations/issues", - "source": "https://github.com/doctrine/migrations/tree/3.6.0" + "source": "https://github.com/doctrine/migrations/tree/3.9.0" }, "funding": [ { @@ -1552,69 +2529,58 @@ "type": "tidelift" } ], - "time": "2023-02-15T18:49:46+00:00" + "time": "2025-03-26T06:48:45+00:00" }, { "name": "doctrine/orm", - "version": "dev-entity-level-commit-order", + "version": "3.3.3", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "44d2a83" + "reference": "1f1891d3e20ef9881e81c2f32c53e9dc88dfc9a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/44d2a83", - "reference": "44d2a83", + "url": "https://api.github.com/repos/doctrine/orm/zipball/1f1891d3e20ef9881e81c2f32c53e9dc88dfc9a7", + "reference": "1f1891d3e20ef9881e81c2f32c53e9dc88dfc9a7", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/cache": "^1.12.1 || ^2.1.1", - "doctrine/collections": "^1.5 || ^2.1", - "doctrine/common": "^3.0.3", - "doctrine/dbal": "^2.13.1 || ^3.2", + "doctrine/collections": "^2.2", + "doctrine/dbal": "^3.8.2 || ^4", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2", "doctrine/inflector": "^1.4 || ^2.0", "doctrine/instantiator": "^1.3 || ^2", - "doctrine/lexer": "^2", - "doctrine/persistence": "^2.4 || ^3", + "doctrine/lexer": "^3", + "doctrine/persistence": "^3.3.1 || ^4", "ext-ctype": "*", - "php": "^7.1 || ^8.0", + "php": "^8.1", "psr/cache": "^1 || ^2 || ^3", - "symfony/console": "^4.2 || ^5.0 || ^6.0", - "symfony/polyfill-php72": "^1.23", - "symfony/polyfill-php80": "^1.16" - }, - "conflict": { - "doctrine/annotations": "<1.13 || >= 3.0" + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/var-exporter": "^6.3.9 || ^7.0" }, "require-dev": { - "doctrine/annotations": "^1.13 || ^2", - "doctrine/coding-standard": "^9.0.2 || ^12.0", - "phpbench/phpbench": "^0.16.10 || ^1.0", - "phpstan/phpstan": "~1.4.10 || 1.10.18", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", + "doctrine/coding-standard": "^13.0", + "phpbench/phpbench": "^1.0", + "phpdocumentor/guides-cli": "^1.4", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "2.0.3", + "phpstan/phpstan-deprecation-rules": "^2", + "phpunit/phpunit": "^10.4.0", "psr/log": "^1 || ^2 || ^3", - "squizlabs/php_codesniffer": "3.7.2", - "symfony/cache": "^4.4 || ^5.4 || ^6.0", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2", - "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0", - "vimeo/psalm": "4.30.0 || 5.12.0" + "squizlabs/php_codesniffer": "3.12.0", + "symfony/cache": "^5.4 || ^6.2 || ^7.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", - "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0", - "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0" }, - "bin": [ - "bin/doctrine" - ], "type": "library", "autoload": { "psr-4": { - "Doctrine\\ORM\\": "lib/Doctrine/ORM" + "Doctrine\\ORM\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1651,42 +2617,39 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/entity-level-commit-order" + "source": "https://github.com/doctrine/orm/tree/3.3.3" }, - "time": "2023-06-28T09:45:39+00:00" + "time": "2025-05-02T17:42:51+00:00" }, { "name": "doctrine/persistence", - "version": "3.2.0", + "version": "4.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "63fee8c33bef740db6730eb2a750cd3da6495603" + "reference": "45004aca79189474f113cbe3a53847c2115a55fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/63fee8c33bef740db6730eb2a750cd3da6495603", - "reference": "63fee8c33bef740db6730eb2a750cd3da6495603", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/45004aca79189474f113cbe3a53847c2115a55fa", + "reference": "45004aca79189474f113cbe3a53847c2115a55fa", "shasum": "" }, "require": { "doctrine/event-manager": "^1 || ^2", - "php": "^7.2 || ^8.0", + "php": "^8.1", "psr/cache": "^1.0 || ^2.0 || ^3.0" }, "conflict": { "doctrine/common": "<2.10" }, "require-dev": { - "composer/package-versions-deprecated": "^1.11", - "doctrine/coding-standard": "^11", - "doctrine/common": "^3.0", - "phpstan/phpstan": "1.9.4", + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "1.12.7", "phpstan/phpstan-phpunit": "^1", "phpstan/phpstan-strict-rules": "^1.1", - "phpunit/phpunit": "^8.5 || ^9.5", - "symfony/cache": "^4.4 || ^5.4 || ^6.0", - "vimeo/psalm": "4.30.0 || 5.3.0" + "phpunit/phpunit": "^9.6", + "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0" }, "type": "library", "autoload": { @@ -1735,7 +2698,7 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/3.2.0" + "source": "https://github.com/doctrine/persistence/tree/4.0.0" }, "funding": [ { @@ -1751,27 +2714,30 @@ "type": "tidelift" } ], - "time": "2023-05-17T18:32:04+00:00" + "time": "2024-11-01T21:49:07+00:00" }, { "name": "doctrine/sql-formatter", - "version": "1.1.3", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/doctrine/sql-formatter.git", - "reference": "25a06c7bf4c6b8218f47928654252863ffc890a5" + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/25a06c7bf4c6b8218f47928654252863ffc890a5", - "reference": "25a06c7bf4c6b8218f47928654252863ffc890a5", + "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/d6d00aba6fd2957fe5216fe2b7673e9985db20c8", + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4" + "doctrine/coding-standard": "^12", + "ergebnis/phpunit-slow-test-detector": "^2.14", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5" }, "bin": [ "bin/sql-formatter" @@ -1801,30 +2767,30 @@ ], "support": { "issues": "https://github.com/doctrine/sql-formatter/issues", - "source": "https://github.com/doctrine/sql-formatter/tree/1.1.3" + "source": "https://github.com/doctrine/sql-formatter/tree/1.5.2" }, - "time": "2022-05-23T21:33:49+00:00" + "time": "2025-01-24T11:45:48+00:00" }, { "name": "dompdf/dompdf", - "version": "dev-master", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "87bea32efe0b0db309e1d31537201f64d5508280" + "reference": "a51bd7a063a65499446919286fb18b518177155a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/87bea32efe0b0db309e1d31537201f64d5508280", - "reference": "87bea32efe0b0db309e1d31537201f64d5508280", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/a51bd7a063a65499446919286fb18b518177155a", + "reference": "a51bd7a063a65499446919286fb18b518177155a", "shasum": "" }, "require": { + "dompdf/php-font-lib": "^1.0.0", + "dompdf/php-svg-lib": "^1.0.0", "ext-dom": "*", "ext-mbstring": "*", "masterminds/html5": "^2.0", - "phenx/php-font-lib": ">=0.5.4 <1.0.0", - "phenx/php-svg-lib": ">=0.3.3 <1.0.0", "php": "^7.1 || ^8.0" }, "require-dev": { @@ -1832,9 +2798,9 @@ "ext-json": "*", "ext-zip": "*", "mockery/mockery": "^1.3", - "phpunit/phpunit": "^7.5 || ^8 || ^9", + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11", "squizlabs/php_codesniffer": "^3.5", - "symfony/process": "^4.4 || ^5.4 || ^6.2" + "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" }, "suggest": { "ext-gd": "Needed to process images", @@ -1842,7 +2808,6 @@ "ext-imagick": "Improves image processing performance", "ext-zlib": "Needed for pdf stream compression" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -1866,22 +2831,113 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/master" + "source": "https://github.com/dompdf/dompdf/tree/v3.1.0" }, - "time": "2023-06-23T12:41:01+00:00" + "time": "2025-01-15T14:09:04+00:00" }, { - "name": "egulias/email-validator", - "version": "4.0.1", + "name": "dompdf/php-font-lib", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/egulias/EmailValidator.git", - "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff" + "url": "https://github.com/dompdf/php-font-lib.git", + "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/3a85486b709bc384dae8eb78fb2eec649bdb64ff", - "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", + "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "FontLib\\": "src/FontLib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "The FontLib Community", + "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse, export and make subsets of different types of font files.", + "homepage": "https://github.com/dompdf/php-font-lib", + "support": { + "issues": "https://github.com/dompdf/php-font-lib/issues", + "source": "https://github.com/dompdf/php-font-lib/tree/1.0.1" + }, + "time": "2024-12-02T14:37:59+00:00" + }, + { + "name": "dompdf/php-svg-lib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-svg-lib.git", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0", + "sabberworm/php-css-parser": "^8.4" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Svg\\": "src/Svg" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "The SvgLib Community", + "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse and export to PDF SVG files.", + "homepage": "https://github.com/dompdf/php-svg-lib", + "support": { + "issues": "https://github.com/dompdf/php-svg-lib/issues", + "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0" + }, + "time": "2024-04-29T13:26:35+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", "shasum": "" }, "require": { @@ -1890,8 +2946,8 @@ "symfony/polyfill-intl-idn": "^1.26" }, "require-dev": { - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^4.30" + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" @@ -1927,7 +2983,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.1" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" }, "funding": [ { @@ -1935,7 +2991,7 @@ "type": "github" } ], - "time": "2023-01-14T14:17:03+00:00" + "time": "2025-03-06T22:45:56+00:00" }, { "name": "erusev/parsedown", @@ -1989,16 +3045,16 @@ }, { "name": "florianv/exchanger", - "version": "2.8.0", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/florianv/exchanger.git", - "reference": "be3e4b316a0fd90bac186cc8b8206e995df161ba" + "reference": "9214f51665fb907e7aa2397e21a90c456eb0c448" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/florianv/exchanger/zipball/be3e4b316a0fd90bac186cc8b8206e995df161ba", - "reference": "be3e4b316a0fd90bac186cc8b8206e995df161ba", + "url": "https://api.github.com/repos/florianv/exchanger/zipball/9214f51665fb907e7aa2397e21a90c456eb0c448", + "reference": "9214f51665fb907e7aa2397e21a90c456eb0c448", "shasum": "" }, "require": { @@ -2009,7 +3065,7 @@ "php-http/client-implementation": "^1.0", "php-http/discovery": "^1.6", "php-http/httplug": "^1.0 || ^2.0", - "php-http/message-factory": "^1.0.2", + "psr/http-factory": "^1.0.2", "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" }, "require-dev": { @@ -2055,9 +3111,9 @@ ], "support": { "issues": "https://github.com/florianv/exchanger/issues", - "source": "https://github.com/florianv/exchanger/tree/2.8.0" + "source": "https://github.com/florianv/exchanger/tree/2.8.1" }, - "time": "2022-12-11T05:52:51+00:00" + "time": "2023-11-03T17:11:52+00:00" }, { "name": "florianv/swap", @@ -2125,25 +3181,25 @@ "source": { "type": "git", "url": "https://github.com/florianv/symfony-swap.git", - "reference": "fc6154976533e386ac6783c02ff19ab65aed4029" + "reference": "c8cd268ad6e2f636f10b91df9850e3941d7f5807" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/florianv/symfony-swap/zipball/fc6154976533e386ac6783c02ff19ab65aed4029", - "reference": "fc6154976533e386ac6783c02ff19ab65aed4029", + "url": "https://api.github.com/repos/florianv/symfony-swap/zipball/c8cd268ad6e2f636f10b91df9850e3941d7f5807", + "reference": "c8cd268ad6e2f636f10b91df9850e3941d7f5807", "shasum": "" }, "require": { "florianv/swap": "^4.0", "php": "^7.1.3|^8.0", - "symfony/framework-bundle": "~3.0|~4.0|~5.0|~6.0" + "symfony/framework-bundle": "~3.0|~4.0|~5.0|~6.0|~7.0" }, "require-dev": { "nyholm/psr7": "^1.1", "php-http/guzzle6-adapter": "^1.0", "php-http/message": "^1.7", "phpunit/phpunit": "~5.7|~6.0|~7.0|~8.0|~9.0", - "symfony/cache": "~3.0|~4.0|~5.0|~6.0" + "symfony/cache": "~3.0|~4.0|~5.0|~6.0|~7.0" }, "suggest": { "symfony/cache": "For caching" @@ -2186,102 +3242,20 @@ "issues": "https://github.com/florianv/symfony-swap/issues", "source": "https://github.com/florianv/symfony-swap/tree/master" }, - "time": "2023-01-12T08:17:02+00:00" - }, - { - "name": "friendsofphp/proxy-manager-lts", - "version": "v1.0.16", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/proxy-manager-lts.git", - "reference": "ecadbdc9052e4ad08c60c8a02268712e50427f7c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/ecadbdc9052e4ad08c60c8a02268712e50427f7c", - "reference": "ecadbdc9052e4ad08c60c8a02268712e50427f7c", - "shasum": "" - }, - "require": { - "laminas/laminas-code": "~3.4.1|^4.0", - "php": ">=7.1", - "symfony/filesystem": "^4.4.17|^5.0|^6.0|^7.0" - }, - "conflict": { - "laminas/laminas-stdlib": "<3.2.1", - "zendframework/zend-stdlib": "<3.2.1" - }, - "replace": { - "ocramius/proxy-manager": "^2.1" - }, - "require-dev": { - "ext-phar": "*", - "symfony/phpunit-bridge": "^5.4|^6.0|^7.0" - }, - "type": "library", - "extra": { - "thanks": { - "name": "ocramius/proxy-manager", - "url": "https://github.com/Ocramius/ProxyManager" - } - }, - "autoload": { - "psr-4": { - "ProxyManager\\": "src/ProxyManager" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - } - ], - "description": "Adding support for a wider range of PHP versions to ocramius/proxy-manager", - "homepage": "https://github.com/FriendsOfPHP/proxy-manager-lts", - "keywords": [ - "aop", - "lazy loading", - "proxy", - "proxy pattern", - "service proxies" - ], - "support": { - "issues": "https://github.com/FriendsOfPHP/proxy-manager-lts/issues", - "source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.16" - }, - "funding": [ - { - "url": "https://github.com/Ocramius", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/ocramius/proxy-manager", - "type": "tidelift" - } - ], - "time": "2023-05-24T07:17:17+00:00" + "time": "2024-07-09T13:51:01+00:00" }, { "name": "gregwar/captcha", - "version": "v1.2.0", + "version": "v1.2.1", "source": { "type": "git", "url": "https://github.com/Gregwar/Captcha.git", - "reference": "6e5b61b66ac89885b505153f4ef9a74ffa5b3074" + "reference": "229d3cdfe33d6f1349e0aec94a26e9205a6db08e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Gregwar/Captcha/zipball/6e5b61b66ac89885b505153f4ef9a74ffa5b3074", - "reference": "6e5b61b66ac89885b505153f4ef9a74ffa5b3074", + "url": "https://api.github.com/repos/Gregwar/Captcha/zipball/229d3cdfe33d6f1349e0aec94a26e9205a6db08e", + "reference": "229d3cdfe33d6f1349e0aec94a26e9205a6db08e", "shasum": "" }, "require": { @@ -2323,36 +3297,37 @@ ], "support": { "issues": "https://github.com/Gregwar/Captcha/issues", - "source": "https://github.com/Gregwar/Captcha/tree/v1.2.0" + "source": "https://github.com/Gregwar/Captcha/tree/v1.2.1" }, - "time": "2023-03-24T22:12:41+00:00" + "time": "2023-09-26T13:45:37+00:00" }, { "name": "gregwar/captcha-bundle", - "version": "v2.2.0", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/Gregwar/CaptchaBundle.git", - "reference": "2b55ba41fd890f1a94d30e53a530c344bf12d6a5" + "reference": "8eb95c0911a1db9e3b2f368f6319e0945b959a6c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Gregwar/CaptchaBundle/zipball/2b55ba41fd890f1a94d30e53a530c344bf12d6a5", - "reference": "2b55ba41fd890f1a94d30e53a530c344bf12d6a5", + "url": "https://api.github.com/repos/Gregwar/CaptchaBundle/zipball/8eb95c0911a1db9e3b2f368f6319e0945b959a6c", + "reference": "8eb95c0911a1db9e3b2f368f6319e0945b959a6c", "shasum": "" }, "require": { "ext-gd": "*", - "gregwar/captcha": "^1.1.9", - "php": ">=7.1.3", - "symfony/form": "~5.0|~6.0", - "symfony/framework-bundle": "~5.0|~6.0", - "symfony/translation": "~5.0|^6.0", - "twig/twig": "^2.10|^3.0" + "gregwar/captcha": "^1.2.1", + "php": ">=8.0.2", + "symfony/form": "~6.0|~7.0", + "symfony/framework-bundle": "~6.0|~7.0", + "symfony/translation": "~6.0|^7.0", + "twig/twig": "^3.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.66", - "symplify/easy-coding-standard": "^6.1" + "friendsofphp/php-cs-fixer": "^3.45", + "phpstan/phpstan": "^1.10", + "symplify/easy-coding-standard": "^12" }, "type": "symfony-bundle", "autoload": { @@ -2368,7 +3343,7 @@ { "name": "Grégoire Passault", "email": "g.passault@gmail.com", - "homepage": "http://www.gregwar.com/" + "homepage": "https://www.gregwar.com/" }, { "name": "Jeremy Livingston", @@ -2389,28 +3364,28 @@ ], "support": { "issues": "https://github.com/Gregwar/CaptchaBundle/issues", - "source": "https://github.com/Gregwar/CaptchaBundle/tree/v2.2.0" + "source": "https://github.com/Gregwar/CaptchaBundle/tree/v2.3.0" }, - "time": "2022-01-11T08:28:06+00:00" + "time": "2024-06-06T13:14:57+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "7.7.0", + "version": "7.9.3", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5" + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fb7566caccf22d74d1ab270de3551f72a58399f5", - "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0", - "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", + "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" @@ -2419,11 +3394,11 @@ "psr/http-client-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", + "bamarni/composer-bin-plugin": "^1.8.2", "ext-curl": "*", - "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "guzzle/client-integration-tests": "3.0.2", "php-http/message-factory": "^1.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", "psr/log": "^1.1 || ^2.0 || ^3.0" }, "suggest": { @@ -2501,7 +3476,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.7.0" + "source": "https://github.com/guzzle/guzzle/tree/7.9.3" }, "funding": [ { @@ -2517,28 +3492,28 @@ "type": "tidelift" } ], - "time": "2023-05-21T14:04:53+00:00" + "time": "2025-03-27T13:37:11+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.0.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6" + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/3a494dc7dc1d7d12e511890177ae2d0e6c107da6", - "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6", + "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" }, "type": "library", "extra": { @@ -2584,7 +3559,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.0.0" + "source": "https://github.com/guzzle/promises/tree/2.2.0" }, "funding": [ { @@ -2600,20 +3575,20 @@ "type": "tidelift" } ], - "time": "2023-05-21T13:50:22+00:00" + "time": "2025-03-27T13:27:01+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.5.0", + "version": "2.7.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6" + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", "shasum": "" }, "require": { @@ -2627,9 +3602,9 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "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" @@ -2700,7 +3675,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.5.0" + "source": "https://github.com/guzzle/psr7/tree/2.7.1" }, "funding": [ { @@ -2716,24 +3691,86 @@ "type": "tidelift" } ], - "time": "2023-04-17T16:11:26+00:00" + "time": "2025-03-27T12:30:47+00:00" }, { - "name": "imagine/imagine", - "version": "1.3.5", + "name": "hshn/base64-encoded-file", + "version": "v5.0.1", "source": { "type": "git", - "url": "https://github.com/php-imagine/Imagine.git", - "reference": "7151d553edec4dc2bbac60419f7a74ff34700e7f" + "url": "https://github.com/hshn/base64-encoded-file.git", + "reference": "54fa81461ba4fbf5b67ed71d22b43ea5cc8c8748" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-imagine/Imagine/zipball/7151d553edec4dc2bbac60419f7a74ff34700e7f", - "reference": "7151d553edec4dc2bbac60419f7a74ff34700e7f", + "url": "https://api.github.com/repos/hshn/base64-encoded-file/zipball/54fa81461ba4fbf5b67ed71d22b43ea5cc8c8748", + "reference": "54fa81461ba4fbf5b67ed71d22b43ea5cc8c8748", "shasum": "" }, "require": { - "php": ">=5.5" + "php": "^8.1.0", + "symfony/http-foundation": "^5.4 || ^6.0 || ^7.0", + "symfony/mime": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0.0", + "symfony/config": "^5.4 || ^6.0 || ^7.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/form": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "symfony/serializer": "^5.4 || ^6.0 || ^7.0" + }, + "suggest": { + "symfony/config": "to use the bundle in a Symfony project", + "symfony/dependency-injection": "to use the bundle in a Symfony project", + "symfony/form": "to use base64_encoded_file type", + "symfony/http-kernel": "to use the bundle in a Symfony project", + "symfony/serializer": "to convert a base64 string to a Base64EncodedFile object" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Hshn\\Base64EncodedFile\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Shota Hoshino", + "email": "sht.hshn@gmail.com" + } + ], + "description": "Provides handling base64 encoded files, and the integration of symfony/form", + "support": { + "issues": "https://github.com/hshn/base64-encoded-file/issues", + "source": "https://github.com/hshn/base64-encoded-file/tree/v5.0.1" + }, + "time": "2023-12-24T07:23:07+00:00" + }, + { + "name": "imagine/imagine", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/php-imagine/Imagine.git", + "reference": "80ab21434890dee9ba54969d31c51ac8d4d551e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-imagine/Imagine/zipball/80ab21434890dee9ba54969d31c51ac8d4d551e0", + "reference": "80ab21434890dee9ba54969d31c51ac8d4d551e0", + "shasum": "" + }, + "require": { + "php": ">=7.1" }, "require-dev": { "phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5 || ^8.4 || ^9.3" @@ -2766,7 +3803,7 @@ "homepage": "http://avalanche123.com" } ], - "description": "Image processing for PHP 5.3", + "description": "Image processing for PHP", "homepage": "http://imagine.readthedocs.org/", "keywords": [ "drawing", @@ -2776,33 +3813,34 @@ ], "support": { "issues": "https://github.com/php-imagine/Imagine/issues", - "source": "https://github.com/php-imagine/Imagine/tree/1.3.5" + "source": "https://github.com/php-imagine/Imagine/tree/1.5.0" }, - "time": "2023-06-07T14:49:52+00:00" + "time": "2024-12-03T14:37:55+00:00" }, { "name": "jbtronics/2fa-webauthn", - "version": "v2.0.1", + "version": "v2.2.3", "source": { "type": "git", "url": "https://github.com/jbtronics/2fa-webauthn.git", - "reference": "0bd4222b21cec7c4b7693e43dc4093d965329e00" + "reference": "fda6f39e70784cbf1f93cf758bf798563219d451" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jbtronics/2fa-webauthn/zipball/0bd4222b21cec7c4b7693e43dc4093d965329e00", - "reference": "0bd4222b21cec7c4b7693e43dc4093d965329e00", + "url": "https://api.github.com/repos/jbtronics/2fa-webauthn/zipball/fda6f39e70784cbf1f93cf758bf798563219d451", + "reference": "fda6f39e70784cbf1f93cf758bf798563219d451", "shasum": "" }, "require": { "ext-json": "*", "nyholm/psr7": "^1.5", "php": "^8.1", - "scheb/2fa-bundle": "^6.0.0", - "symfony/framework-bundle": "^6.0", - "symfony/psr-http-message-bridge": "^2.1", - "symfony/uid": "^6.0", - "web-auth/webauthn-lib": "^4.0" + "psr/log": "^3.0.0|^2.0.0", + "scheb/2fa-bundle": "^6.0.0|^7.0.0", + "symfony/framework-bundle": "^6.0|^7.0", + "symfony/psr-http-message-bridge": "^2.1|^6.1|^7.0", + "symfony/uid": "^6.0|^7.0", + "web-auth/webauthn-lib": "^4.7" }, "require-dev": { "phpunit/phpunit": "^9.5", @@ -2835,30 +3873,30 @@ ], "support": { "issues": "https://github.com/jbtronics/2fa-webauthn/issues", - "source": "https://github.com/jbtronics/2fa-webauthn/tree/v2.0.1" + "source": "https://github.com/jbtronics/2fa-webauthn/tree/v2.2.3" }, - "time": "2023-07-17T21:39:09+00:00" + "time": "2025-03-27T19:23:40+00:00" }, { "name": "jbtronics/dompdf-font-loader-bundle", - "version": "v1.0.0", + "version": "v1.1.3", "source": { "type": "git", "url": "https://github.com/jbtronics/dompdf-font-loader-bundle.git", - "reference": "8323aa3d4c3e70536b958a44f159208a6a0f7fa2" + "reference": "da01d9655826105d53f9d0e8ba4f9d838201dcb2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jbtronics/dompdf-font-loader-bundle/zipball/8323aa3d4c3e70536b958a44f159208a6a0f7fa2", - "reference": "8323aa3d4c3e70536b958a44f159208a6a0f7fa2", + "url": "https://api.github.com/repos/jbtronics/dompdf-font-loader-bundle/zipball/da01d9655826105d53f9d0e8ba4f9d838201dcb2", + "reference": "da01d9655826105d53f9d0e8ba4f9d838201dcb2", "shasum": "" }, "require": { - "dompdf/dompdf": "v1.0.0|v2.0.3", + "dompdf/dompdf": "^1.0.0|^2.0.0|^3.0.0", "ext-json": "*", "php": "^8.1", - "symfony/finder": "^6.0", - "symfony/framework-bundle": "^6.0" + "symfony/finder": "^6.0|^7.0", + "symfony/framework-bundle": "^6.0|^7.0" }, "require-dev": { "phpunit/phpunit": "^9.5", @@ -2890,9 +3928,9 @@ ], "support": { "issues": "https://github.com/jbtronics/dompdf-font-loader-bundle/issues", - "source": "https://github.com/jbtronics/dompdf-font-loader-bundle/tree/v1.0.0" + "source": "https://github.com/jbtronics/dompdf-font-loader-bundle/tree/v1.1.3" }, - "time": "2023-07-02T00:21:14+00:00" + "time": "2025-02-07T23:21:03+00:00" }, { "name": "jfcherng/php-color-output", @@ -2955,16 +3993,16 @@ }, { "name": "jfcherng/php-diff", - "version": "6.15.3", + "version": "6.16.2", "source": { "type": "git", "url": "https://github.com/jfcherng/php-diff.git", - "reference": "39be09756f8eda115299add3f34dc64b4bc32b66" + "reference": "7f46bcfc582e81769237d0b3f6b8a548efe8799d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jfcherng/php-diff/zipball/39be09756f8eda115299add3f34dc64b4bc32b66", - "reference": "39be09756f8eda115299add3f34dc64b4bc32b66", + "url": "https://api.github.com/repos/jfcherng/php-diff/zipball/7f46bcfc582e81769237d0b3f6b8a548efe8799d", + "reference": "7f46bcfc582e81769237d0b3f6b8a548efe8799d", "shasum": "" }, "require": { @@ -2974,7 +4012,7 @@ "php": ">=7.4" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.8", + "friendsofphp/php-cs-fixer": "^3.51", "liip/rmt": "^1.6", "phan/phan": "^5", "phpunit/phpunit": "^9", @@ -3009,7 +4047,7 @@ ], "support": { "issues": "https://github.com/jfcherng/php-diff/issues", - "source": "https://github.com/jfcherng/php-diff/tree/6.15.3" + "source": "https://github.com/jfcherng/php-diff/tree/6.16.2" }, "funding": [ { @@ -3017,7 +4055,7 @@ "type": "custom" } ], - "time": "2023-06-15T12:29:57+00:00" + "time": "2024-03-10T17:40:29+00:00" }, { "name": "jfcherng/php-mb-string", @@ -3132,33 +4170,90 @@ "time": "2023-05-21T07:57:08+00:00" }, { - "name": "knpuniversity/oauth2-client-bundle", - "version": "v2.15.0", + "name": "kelunik/certificate", + "version": "v1.1.3", "source": { "type": "git", - "url": "https://github.com/knpuniversity/oauth2-client-bundle.git", - "reference": "9df0736d02eb20b953ec8e9986743611747d9ed9" + "url": "https://github.com/kelunik/certificate.git", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/knpuniversity/oauth2-client-bundle/zipball/9df0736d02eb20b953ec8e9986743611747d9ed9", - "reference": "9df0736d02eb20b953ec8e9986743611747d9ed9", + "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=7.0" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^6 | 7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Kelunik\\Certificate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Access certificate details and transform between different formats.", + "keywords": [ + "DER", + "certificate", + "certificates", + "openssl", + "pem", + "x509" + ], + "support": { + "issues": "https://github.com/kelunik/certificate/issues", + "source": "https://github.com/kelunik/certificate/tree/v1.1.3" + }, + "time": "2023-02-03T21:26:53+00:00" + }, + { + "name": "knpuniversity/oauth2-client-bundle", + "version": "v2.18.3", + "source": { + "type": "git", + "url": "https://github.com/knpuniversity/oauth2-client-bundle.git", + "reference": "c38ca88a70aae3694ca346a41b13b9a8f6e33ed4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/knpuniversity/oauth2-client-bundle/zipball/c38ca88a70aae3694ca346a41b13b9a8f6e33ed4", + "reference": "c38ca88a70aae3694ca346a41b13b9a8f6e33ed4", "shasum": "" }, "require": { "league/oauth2-client": "^2.0", - "php": ">=7.4", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/framework-bundle": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/routing": "^4.4|^5.0|^6.0" + "php": ">=8.1", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0" }, "require-dev": { "league/oauth2-facebook": "^1.1|^2.0", - "phpstan/phpstan": "^0.12", - "symfony/phpunit-bridge": "^5.3.1|^6.0", - "symfony/security-guard": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4|^5.0|^6.0" + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", + "symfony/security-guard": "^5.4", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "suggest": { "symfony/security-guard": "For integration with Symfony's Guard Security layer" @@ -3187,72 +4282,9 @@ ], "support": { "issues": "https://github.com/knpuniversity/oauth2-client-bundle/issues", - "source": "https://github.com/knpuniversity/oauth2-client-bundle/tree/v2.15.0" + "source": "https://github.com/knpuniversity/oauth2-client-bundle/tree/v2.18.3" }, - "time": "2023-05-03T16:44:38+00:00" - }, - { - "name": "laminas/laminas-code", - "version": "4.11.0", - "source": { - "type": "git", - "url": "https://github.com/laminas/laminas-code.git", - "reference": "169123b3ede20a9193480c53de2a8194f8c073ec" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-code/zipball/169123b3ede20a9193480c53de2a8194f8c073ec", - "reference": "169123b3ede20a9193480c53de2a8194f8c073ec", - "shasum": "" - }, - "require": { - "php": "~8.1.0 || ~8.2.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0.0", - "ext-phar": "*", - "laminas/laminas-coding-standard": "^2.3.0", - "laminas/laminas-stdlib": "^3.6.1", - "phpunit/phpunit": "^10.0.9", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.7.1" - }, - "suggest": { - "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", - "laminas/laminas-stdlib": "Laminas\\Stdlib component" - }, - "type": "library", - "autoload": { - "psr-4": { - "Laminas\\Code\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Extensions to the PHP Reflection API, static code scanning, and code generation", - "homepage": "https://laminas.dev", - "keywords": [ - "code", - "laminas", - "laminasframework" - ], - "support": { - "chat": "https://laminas.dev/chat", - "docs": "https://docs.laminas.dev/laminas-code/", - "forum": "https://discourse.laminas.dev", - "issues": "https://github.com/laminas/laminas-code/issues", - "rss": "https://github.com/laminas/laminas-code/releases.atom", - "source": "https://github.com/laminas/laminas-code" - }, - "funding": [ - { - "url": "https://funding.communitybridge.org/projects/laminas-project", - "type": "community_bridge" - } - ], - "time": "2023-05-14T12:05:38+00:00" + "time": "2024-10-02T14:26:09+00:00" }, { "name": "lcobucci/clock", @@ -3320,37 +4352,35 @@ }, { "name": "lcobucci/jwt", - "version": "5.0.0", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34" + "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34", - "reference": "47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/08071d8d2c7f4b00222cc4b1fb6aa46990a80f83", + "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83", "shasum": "" }, "require": { - "ext-hash": "*", - "ext-json": "*", "ext-openssl": "*", "ext-sodium": "*", - "php": "~8.1.0 || ~8.2.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", "psr/clock": "^1.0" }, "require-dev": { - "infection/infection": "^0.26.19", + "infection/infection": "^0.27.0", "lcobucci/clock": "^3.0", - "lcobucci/coding-standard": "^9.0", - "phpbench/phpbench": "^1.2.8", + "lcobucci/coding-standard": "^11.0", + "phpbench/phpbench": "^1.2.9", "phpstan/extension-installer": "^1.2", - "phpstan/phpstan": "^1.10.3", - "phpstan/phpstan-deprecation-rules": "^1.1.2", - "phpstan/phpstan-phpunit": "^1.3.8", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", "phpstan/phpstan-strict-rules": "^1.5.0", - "phpunit/phpunit": "^10.0.12" + "phpunit/phpunit": "^10.2.6" }, "suggest": { "lcobucci/clock": ">= 3.0" @@ -3379,7 +4409,7 @@ ], "support": { "issues": "https://github.com/lcobucci/jwt/issues", - "source": "https://github.com/lcobucci/jwt/tree/5.0.0" + "source": "https://github.com/lcobucci/jwt/tree/5.3.0" }, "funding": [ { @@ -3391,7 +4421,7 @@ "type": "patreon" } ], - "time": "2023-02-25T21:35:16+00:00" + "time": "2024-04-11T23:07:54+00:00" }, { "name": "league/csv", @@ -3568,35 +4598,30 @@ }, { "name": "league/oauth2-client", - "version": "2.7.0", + "version": "2.8.1", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-client.git", - "reference": "160d6274b03562ebeb55ed18399281d8118b76c8" + "reference": "9df2924ca644736c835fc60466a3a60390d334f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/160d6274b03562ebeb55ed18399281d8118b76c8", - "reference": "160d6274b03562ebeb55ed18399281d8118b76c8", + "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/9df2924ca644736c835fc60466a3a60390d334f9", + "reference": "9df2924ca644736c835fc60466a3a60390d334f9", "shasum": "" }, "require": { - "guzzlehttp/guzzle": "^6.0 || ^7.0", - "paragonie/random_compat": "^1 || ^2 || ^9.99", - "php": "^5.6 || ^7.0 || ^8.0" + "ext-json": "*", + "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", + "php": "^7.1 || >=8.0.0 <8.5.0" }, "require-dev": { "mockery/mockery": "^1.3.5", - "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpunit/phpunit": "^5.7 || ^6.0 || ^9.5", - "squizlabs/php_codesniffer": "^2.3 || ^3.0" + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "^3.11" }, "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.0.x-dev" - } - }, "autoload": { "psr-4": { "League\\OAuth2\\Client\\": "src/" @@ -3632,57 +4657,314 @@ ], "support": { "issues": "https://github.com/thephpleague/oauth2-client/issues", - "source": "https://github.com/thephpleague/oauth2-client/tree/2.7.0" + "source": "https://github.com/thephpleague/oauth2-client/tree/2.8.1" }, - "time": "2023-04-16T18:19:15+00:00" + "time": "2025-02-26T04:37:30+00:00" }, { - "name": "liip/imagine-bundle", - "version": "2.11.0", + "name": "league/uri", + "version": "7.5.1", "source": { "type": "git", - "url": "https://github.com/liip/LiipImagineBundle.git", - "reference": "2e943e6be4309ec90fcff90227053898203c1c8e" + "url": "https://github.com/thephpleague/uri.git", + "reference": "81fb5145d2644324614cc532b28efd0215bda430" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/liip/LiipImagineBundle/zipball/2e943e6be4309ec90fcff90227053898203c1c8e", - "reference": "2e943e6be4309ec90fcff90227053898203c1c8e", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", + "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.5", + "php": "^8.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "league/uri-components": "Needed to easily manipulate URI objects components", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.5.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:40:02+00:00" + }, + { + "name": "league/uri-components", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-components.git", + "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", + "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", + "shasum": "" + }, + "require": { + "league/uri": "^7.5", + "php": "^8.1" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "ext-mbstring": "to use the sorting algorithm of URLSearchParams", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI components manipulation library", + "homepage": "http://uri.thephpleague.com", + "keywords": [ + "authority", + "components", + "fragment", + "host", + "middleware", + "modifier", + "path", + "port", + "query", + "rfc3986", + "scheme", + "uri", + "url", + "userinfo" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-components/tree/7.5.1" + }, + "funding": [ + { + "url": "https://github.com/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:40:02+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.5.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-factory": "^1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interfaces and classes for URI representation and interaction", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:18:47+00:00" + }, + { + "name": "liip/imagine-bundle", + "version": "2.13.3", + "source": { + "type": "git", + "url": "https://github.com/liip/LiipImagineBundle.git", + "reference": "3faccde327f91368e51d05ecad49a9cd915abd81" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/liip/LiipImagineBundle/zipball/3faccde327f91368e51d05ecad49a9cd915abd81", + "reference": "3faccde327f91368e51d05ecad49a9cd915abd81", "shasum": "" }, "require": { "ext-mbstring": "*", "imagine/imagine": "^1.3.2", - "php": "^7.1|^8.0", - "symfony/filesystem": "^3.4|^4.4|^5.3|^6.0", - "symfony/finder": "^3.4|^4.4|^5.3|^6.0", - "symfony/framework-bundle": "^3.4.23|^4.4|^5.3|^6.0", - "symfony/mime": "^4.4|^5.3|^6.0", - "symfony/options-resolver": "^3.4|^4.4|^5.3|^6.0", - "symfony/process": "^3.4|^4.4|^5.3|^6.0", + "php": "^7.2|^8.0", + "symfony/filesystem": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/finder": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/framework-bundle": "^3.4.23|^4.4|^5.3|^6.0|^7.0", + "symfony/mime": "^4.4|^5.3|^6.0|^7.0", + "symfony/options-resolver": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/process": "^3.4|^4.4|^5.3|^6.0|^7.0", "twig/twig": "^1.44|^2.9|^3.0" }, "require-dev": { "amazonwebservices/aws-sdk-for-php": "^1.0", - "aws/aws-sdk-php": "^2.4", + "aws/aws-sdk-php": "^2.4|^3.0", "doctrine/cache": "^1.11|^2.0", "doctrine/persistence": "^1.3|^2.0", "enqueue/enqueue-bundle": "^0.9|^0.10", "ext-gd": "*", "league/flysystem": "^1.0|^2.0|^3.0", - "phpstan/phpstan": "^0.12.64", + "phpstan/phpstan": "^1.10.0", "psr/cache": "^1.0|^2.0|^3.0", "psr/log": "^1.0", - "symfony/browser-kit": "^3.4|^4.4|^5.3|^6.0", - "symfony/cache": "^3.4|^4.4|^5.3|^6.0", - "symfony/console": "^3.4|^4.4|^5.3|^6.0", - "symfony/dependency-injection": "^3.4|^4.4|^5.3|^6.0", - "symfony/form": "^3.4|^4.4|^5.3|^6.0", - "symfony/messenger": "^4.4|^5.3|^6.0", - "symfony/phpunit-bridge": "^5.3", + "symfony/asset": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/browser-kit": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/cache": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/console": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/dependency-injection": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/form": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/messenger": "^4.4|^5.3|^6.0|^7.0", + "symfony/phpunit-bridge": "^7.0.2", "symfony/templating": "^3.4|^4.4|^5.3|^6.0", - "symfony/validator": "^3.4|^4.4|^5.3|^6.0", - "symfony/yaml": "^3.4|^4.4|^5.3|^6.0" + "symfony/validator": "^3.4|^4.4|^5.3|^6.0|^7.0", + "symfony/yaml": "^3.4|^4.4|^5.3|^6.0|^7.0" }, "suggest": { "alcaeus/mongo-php-adapter": "required for mongodb components", @@ -3694,10 +4976,12 @@ "ext-gd": "required to use gd driver", "ext-gmagick": "required to use gmagick driver", "ext-imagick": "required to use imagick driver", + "ext-json": "required to read JSON manifest versioning", "ext-mongodb": "required for mongodb components", "league/flysystem": "required to use FlySystem data loader or cache resolver", "monolog/monolog": "A psr/log compatible logger is required to enable logging", "rokka/imagine-vips": "required to use 'vips' driver", + "symfony/asset": "If you want to use asset versioning", "symfony/messenger": "If you like to process images in background", "symfony/templating": "required to use deprecated Templating component instead of Twig" }, @@ -3721,7 +5005,7 @@ } ], "description": "This bundle provides an image manipulation abstraction toolkit for Symfony-based projects.", - "homepage": "http://liip.ch", + "homepage": "https://www.liip.ch", "keywords": [ "bundle", "image", @@ -3735,9 +5019,9 @@ ], "support": { "issues": "https://github.com/liip/LiipImagineBundle/issues", - "source": "https://github.com/liip/LiipImagineBundle/tree/2.11.0" + "source": "https://github.com/liip/LiipImagineBundle/tree/2.13.3" }, - "time": "2023-05-16T06:13:14+00:00" + "time": "2024-12-12T09:38:23+00:00" }, { "name": "lorenzo/pinky", @@ -3794,16 +5078,16 @@ }, { "name": "masterminds/html5", - "version": "2.8.1", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf" + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf", - "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", "shasum": "" }, "require": { @@ -3811,7 +5095,7 @@ "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8" + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" }, "type": "library", "extra": { @@ -3855,22 +5139,22 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.8.1" + "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" }, - "time": "2023-05-10T11:58:31+00:00" + "time": "2024-03-31T07:05:07+00:00" }, { "name": "monolog/monolog", - "version": "3.4.0", + "version": "3.9.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "e2392369686d420ca32df3803de28b5d6f76867d" + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/e2392369686d420ca32df3803de28b5d6f76867d", - "reference": "e2392369686d420ca32df3803de28b5d6f76867d", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", "shasum": "" }, "require": { @@ -3890,12 +5174,14 @@ "guzzlehttp/psr7": "^2.2", "mongodb/mongodb": "^1.8", "php-amqplib/php-amqplib": "~2.4 || ^3", - "phpstan/phpstan": "^1.9", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "^10.1", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", "predis/predis": "^1.1 || ^2", - "ruflin/elastica": "^7", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", "symfony/mailer": "^5.4 || ^6", "symfony/mime": "^5.4 || ^6" }, @@ -3946,7 +5232,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.4.0" + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" }, "funding": [ { @@ -3958,45 +5244,41 @@ "type": "tidelift" } ], - "time": "2023-06-21T08:46:11+00:00" + "time": "2025-03-24T10:02:05+00:00" }, { "name": "nbgrp/onelogin-saml-bundle", - "version": "v1.3.2", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/nbgrp/onelogin-saml-bundle.git", - "reference": "907a59431edcfbb962b2bb952d987693b63ca757" + "reference": "3341544e72b699ab69357ab38cee9c80941ce1c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nbgrp/onelogin-saml-bundle/zipball/907a59431edcfbb962b2bb952d987693b63ca757", - "reference": "907a59431edcfbb962b2bb952d987693b63ca757", + "url": "https://api.github.com/repos/nbgrp/onelogin-saml-bundle/zipball/3341544e72b699ab69357ab38cee9c80941ce1c6", + "reference": "3341544e72b699ab69357ab38cee9c80941ce1c6", "shasum": "" }, "require": { "onelogin/php-saml": "^4", "php": "^8.1", "psr/log": "^1 || ^2 || ^3", - "symfony/config": "^6", - "symfony/dependency-injection": "^6", + "symfony/config": "^6.4", + "symfony/dependency-injection": "^6.4", "symfony/deprecation-contracts": "^3", "symfony/event-dispatcher-contracts": "^3", - "symfony/http-foundation": "^6", - "symfony/http-kernel": "^6", - "symfony/routing": "^6", - "symfony/security-bundle": "^6", - "symfony/security-core": "^6", - "symfony/security-http": "^6" - }, - "conflict": { - "symfony/http-kernel": "<6.2", - "symfony/security-core": "<6.2" + "symfony/http-foundation": "^6.4", + "symfony/http-kernel": "^6.4", + "symfony/routing": "^6.4", + "symfony/security-bundle": "^6.4", + "symfony/security-core": "^6.4", + "symfony/security-http": "^6.4" }, "require-dev": { "doctrine/orm": "^2.3 || ^3", - "symfony/event-dispatcher": "^6", - "symfony/phpunit-bridge": "^6" + "symfony/event-dispatcher": "^6.4", + "symfony/phpunit-bridge": "^6.4" }, "type": "symfony-bundle", "autoload": { @@ -4023,9 +5305,9 @@ ], "support": { "issues": "https://github.com/nbgrp/onelogin-saml-bundle/issues", - "source": "https://github.com/nbgrp/onelogin-saml-bundle/tree/v1.3.2" + "source": "https://github.com/nbgrp/onelogin-saml-bundle/tree/v1.4.0" }, - "time": "2023-03-22T20:23:42+00:00" + "time": "2023-11-29T12:22:32+00:00" }, { "name": "nelexa/zip", @@ -4101,27 +5383,90 @@ "time": "2022-06-17T11:17:46+00:00" }, { - "name": "nelmio/security-bundle", - "version": "v3.0.0", + "name": "nelmio/cors-bundle", + "version": "2.5.0", "source": { "type": "git", - "url": "https://github.com/nelmio/NelmioSecurityBundle.git", - "reference": "34699d40d81b58b6bd256e34489c799620dff2a4" + "url": "https://github.com/nelmio/NelmioCorsBundle.git", + "reference": "3a526fe025cd20e04a6a11370cf5ab28dbb5a544" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nelmio/NelmioSecurityBundle/zipball/34699d40d81b58b6bd256e34489c799620dff2a4", - "reference": "34699d40d81b58b6bd256e34489c799620dff2a4", + "url": "https://api.github.com/repos/nelmio/NelmioCorsBundle/zipball/3a526fe025cd20e04a6a11370cf5ab28dbb5a544", + "reference": "3a526fe025cd20e04a6a11370cf5ab28dbb5a544", + "shasum": "" + }, + "require": { + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.3.6", + "symfony/phpunit-bridge": "^5.4 || ^6.0 || ^7.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Nelmio\\CorsBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nelmio", + "homepage": "http://nelm.io" + }, + { + "name": "Symfony Community", + "homepage": "https://github.com/nelmio/NelmioCorsBundle/contributors" + } + ], + "description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Symfony application", + "keywords": [ + "api", + "cors", + "crossdomain" + ], + "support": { + "issues": "https://github.com/nelmio/NelmioCorsBundle/issues", + "source": "https://github.com/nelmio/NelmioCorsBundle/tree/2.5.0" + }, + "time": "2024-06-24T21:25:28+00:00" + }, + { + "name": "nelmio/security-bundle", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/nelmio/NelmioSecurityBundle.git", + "reference": "b1c5e323d71152bc1a61a4f8fbf7d88c6fa3e2e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nelmio/NelmioSecurityBundle/zipball/b1c5e323d71152bc1a61a4f8fbf7d88c6fa3e2e7", + "reference": "b1c5e323d71152bc1a61a4f8fbf7d88c6fa3e2e7", "shasum": "" }, "require": { "php": "^7.4 || ^8.0", - "symfony/framework-bundle": "^4.4 || ^5.4 || ^6.0", - "symfony/http-kernel": "^4.4 || ^5.4 || ^6.0", - "symfony/security-core": "^4.4 || ^5.4 || ^6.0", - "symfony/security-csrf": "^4.4 || ^5.4 || ^6.0", - "symfony/security-http": "^4.4 || ^5.4 || ^6.0", - "symfony/yaml": "^4.4 || ^5.4 || ^6.0", + "symfony/deprecation-contracts": "^2.5 || ^3", + "symfony/framework-bundle": "^5.4 || ^6.3 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.3 || ^7.0", + "symfony/security-core": "^5.4 || ^6.3 || ^7.0", + "symfony/security-csrf": "^5.4 || ^6.3 || ^7.0", + "symfony/security-http": "^5.4 || ^6.3 || ^7.0", + "symfony/yaml": "^5.4 || ^6.3 || ^7.0", "ua-parser/uap-php": "^3.4.4" }, "require-dev": { @@ -4132,10 +5477,10 @@ "phpstan/phpstan-symfony": "^1.1", "phpunit/phpunit": "^9.5", "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/browser-kit": "^4.4 || ^5.4 || ^6.0", - "symfony/cache": "^4.4 || ^5.4 || ^6.0", - "symfony/phpunit-bridge": "^6.0", - "symfony/twig-bundle": "^4.4 || ^5.4 || ^6.0", + "symfony/browser-kit": "^5.4 || ^6.3 || ^7.0", + "symfony/cache": "^5.4 || ^6.3 || ^7.0", + "symfony/phpunit-bridge": "^6.3 || ^7.0", + "symfony/twig-bundle": "^5.4 || ^6.3 || ^7.0", "twig/twig": "^2.10 || ^3.0" }, "type": "symfony-bundle", @@ -4169,95 +5514,39 @@ ], "support": { "issues": "https://github.com/nelmio/NelmioSecurityBundle/issues", - "source": "https://github.com/nelmio/NelmioSecurityBundle/tree/v3.0.0" + "source": "https://github.com/nelmio/NelmioSecurityBundle/tree/v3.5.1" }, - "time": "2022-03-17T07:30:15+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v4.16.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "19526a33fb561ef417e822e85f08a00db4059c17" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", - "reference": "19526a33fb561ef417e822e85f08a00db4059c17", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.0" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.9-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/v4.16.0" - }, - "time": "2023-06-25T14:52:30+00:00" + "time": "2025-03-13T09:17:16+00:00" }, { "name": "nikolaposa/version", - "version": "4.1.0", + "version": "4.2.1", "source": { "type": "git", "url": "https://github.com/nikolaposa/version.git", - "reference": "0aada6b801962c084ae465f7569397dc2186b6a7" + "reference": "2b9ee2f0b09333b6ce00bd6b63132cdf1d7a1428" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikolaposa/version/zipball/0aada6b801962c084ae465f7569397dc2186b6a7", - "reference": "0aada6b801962c084ae465f7569397dc2186b6a7", + "url": "https://api.github.com/repos/nikolaposa/version/zipball/2b9ee2f0b09333b6ce00bd6b63132cdf1d7a1428", + "reference": "2b9ee2f0b09333b6ce00bd6b63132cdf1d7a1428", "shasum": "" }, "require": { "beberlei/assert": "^3.2", - "php": "^7.2 || ^8.0" + "php": "^8.1" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.17", - "phpstan/phpstan": "^0.12.10", - "phpstan/phpstan-beberlei-assert": "^0.12.2", - "phpstan/phpstan-phpunit": "^0.12.6", - "phpunit/phpunit": "^8.0" + "friendsofphp/php-cs-fixer": "^3.44", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-beberlei-assert": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0.x-dev" + "dev-master": "4.2.x-dev" } }, "autoload": { @@ -4286,79 +5575,22 @@ ], "support": { "issues": "https://github.com/nikolaposa/version/issues", - "source": "https://github.com/nikolaposa/version/tree/4.1.0" + "source": "https://github.com/nikolaposa/version/tree/4.2.1" }, - "time": "2020-12-12T10:47:10+00:00" - }, - { - "name": "nyholm/nsa", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/Nyholm/NSA.git", - "reference": "c264c17ed2aa8251c64ad289442ed53f64cdb283" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Nyholm/NSA/zipball/c264c17ed2aa8251c64ad289442ed53f64cdb283", - "reference": "c264c17ed2aa8251c64ad289442ed53f64cdb283", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "webmozart/assert": "^1.1.0" - }, - "require-dev": { - "symfony/phpunit-bridge": "^4.4 || ^5.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Nyholm\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - } - ], - "description": "See everything and do whatever you want. No privacy rule will stop us. Used in tests, debugging and fixtures to access properties and methods.", - "homepage": "https://tnyholm.se", - "keywords": [ - "Fixture", - "debug", - "reflection", - "test" - ], - "support": { - "issues": "https://github.com/Nyholm/NSA/issues", - "source": "https://github.com/Nyholm/NSA/tree/1.3.0" - }, - "funding": [ - { - "url": "https://github.com/nyholm", - "type": "github" - } - ], - "time": "2021-07-15T18:25:37+00:00" + "time": "2025-03-24T19:12:02+00:00" }, { "name": "nyholm/psr7", - "version": "1.8.0", + "version": "1.8.2", "source": { "type": "git", "url": "https://github.com/Nyholm/psr7.git", - "reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be" + "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Nyholm/psr7/zipball/3cb4d163b58589e47b35103e8e5e6a6a475b47be", - "reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/a71f2b11690f4b24d099d6b16690a90ae14fc6f3", + "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3", "shasum": "" }, "require": { @@ -4411,7 +5643,7 @@ ], "support": { "issues": "https://github.com/Nyholm/psr7/issues", - "source": "https://github.com/Nyholm/psr7/tree/1.8.0" + "source": "https://github.com/Nyholm/psr7/tree/1.8.2" }, "funding": [ { @@ -4423,63 +5655,73 @@ "type": "github" } ], - "time": "2023-05-02T11:26:24+00:00" + "time": "2024-09-09T07:06:30+00:00" }, { "name": "omines/datatables-bundle", - "version": "0.7.2", + "version": "0.9.2", "source": { "type": "git", "url": "https://github.com/omines/datatables-bundle.git", - "reference": "8e0dce49a271e0cfdf128d42bf81a336f8f02232" + "reference": "15974fc7dde750f8a3eff32d9ad4d9de6028583f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/omines/datatables-bundle/zipball/8e0dce49a271e0cfdf128d42bf81a336f8f02232", - "reference": "8e0dce49a271e0cfdf128d42bf81a336f8f02232", + "url": "https://api.github.com/repos/omines/datatables-bundle/zipball/15974fc7dde750f8a3eff32d9ad4d9de6028583f", + "reference": "15974fc7dde750f8a3eff32d9ad4d9de6028583f", "shasum": "" }, "require": { - "php": ">=8.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/framework-bundle": "^5.4|^6.0", - "symfony/options-resolver": "^5.4|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0" + "php": ">=8.1", + "symfony/event-dispatcher": "^6.4|^7.1", + "symfony/framework-bundle": "^6.4|^7.1", + "symfony/options-resolver": "^6.4|^7.1", + "symfony/polyfill-mbstring": "^1.31.0", + "symfony/property-access": "^6.4|^7.1", + "symfony/translation": "^6.4|^7.1" + }, + "conflict": { + "doctrine/orm": "^3.0 <3.3" }, "require-dev": { - "doctrine/common": "^2.6|^3.3", - "doctrine/doctrine-bundle": "^2.7|^3.0", - "doctrine/orm": "^2.13.1", - "doctrine/persistence": "^2.0|^3.0.3", + "doctrine/common": "^3.4.5", + "doctrine/doctrine-bundle": "^2.13.1", + "doctrine/orm": "^2.19.3|^3.3.0", + "doctrine/persistence": "^3.4.0", "ext-curl": "*", "ext-json": "*", + "ext-mbstring": "*", + "ext-mongodb": "*", "ext-pdo_sqlite": "*", "ext-zip": "*", - "friendsofphp/php-cs-fixer": "^3.9.5", - "mongodb/mongodb": "^1.12", - "ocramius/package-versions": "^2.5", - "phpoffice/phpspreadsheet": "^1.24.1", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8.2", - "phpstan/phpstan-doctrine": "^1.3.12", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-symfony": "^1.2.9", - "ruflin/elastica": "^6.0|^7.2", - "symfony/browser-kit": "^5.4|^6.1.3", - "symfony/css-selector": "^5.4|^6.1.3", - "symfony/dom-crawler": "^5.4|^6.1.3", - "symfony/intl": "^5.4|^6.1", - "symfony/mime": "^5.4|^6.1.3", - "symfony/phpunit-bridge": "^5.4|^6.1.3", - "symfony/twig-bundle": "^5.4|^6.1.1", - "symfony/var-dumper": "^5.4|^6.1.3", - "symfony/yaml": "^5.4|^6.1.3" + "friendsofphp/php-cs-fixer": "^3.65.0", + "mongodb/mongodb": "^1.20.0", + "ocramius/package-versions": "^2.9", + "openspout/openspout": "^4.23", + "phpoffice/phpspreadsheet": "^2.3.3|^3.5", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.0.3", + "phpstan/phpstan-doctrine": "^2.0.1", + "phpstan/phpstan-phpunit": "^2.0.1", + "phpstan/phpstan-symfony": "^2.0.0", + "phpunit/phpunit": "^10.5.38|^11.4.4", + "ruflin/elastica": "^6.2|^7.3.2", + "symfony/browser-kit": "^6.4.13|^7.1", + "symfony/css-selector": "^6.4.13|^7.1", + "symfony/doctrine-bridge": "^6.4.13|^7.1", + "symfony/dom-crawler": "^6.4.13|^7.1", + "symfony/intl": "^6.4.13|^7.1", + "symfony/mime": "^6.4.13|^7.1", + "symfony/phpunit-bridge": "^7.2", + "symfony/twig-bundle": "^6.4|^7.1", + "symfony/var-dumper": "^6.4.13|^7.1", + "symfony/yaml": "^6.4.13|^7.1" }, "suggest": { "doctrine/doctrine-bundle": "For integrated access to Doctrine object managers", "doctrine/orm": "For full automated integration with Doctrine entities", "mongodb/mongodb": "For integration with MongoDB collections", + "openspout/openspout": "To use the OpenSpout Excel exporter", "phpoffice/phpspreadsheet": "To export the data from DataTables to Excel", "ruflin/elastica": "For integration with Elasticsearch indexes", "symfony/twig-bundle": "To use default Twig based rendering and TwigColumn" @@ -4487,7 +5729,7 @@ "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "0.7-dev" + "dev-master": "0.9-dev" } }, "autoload": { @@ -4503,12 +5745,12 @@ { "name": "Robbert Beesems", "email": "robbert.beesems@omines.com", - "homepage": "https://omines.nl/" + "homepage": "https://www.omines.nl/" }, { "name": "Niels Keurentjes", "email": "niels.keurentjes@omines.com", - "homepage": "https://omines.nl/" + "homepage": "https://www.omines.nl/" } ], "description": "Symfony DataTables Bundle with native Doctrine ORM, Elastica and MongoDB support", @@ -4525,27 +5767,33 @@ ], "support": { "issues": "https://github.com/omines/datatables-bundle/issues", - "source": "https://github.com/omines/datatables-bundle/tree/0.7.2" + "source": "https://github.com/omines/datatables-bundle/tree/0.9.2" }, - "time": "2023-04-24T09:09:02+00:00" + "funding": [ + { + "url": "https://github.com/curry684", + "type": "github" + } + ], + "time": "2025-01-23T14:53:20+00:00" }, { "name": "onelogin/php-saml", - "version": "4.1.0", + "version": "4.2.0", "source": { "type": "git", - "url": "https://github.com/onelogin/php-saml.git", - "reference": "b22a57ebd13e838b90df5d3346090bc37056409d" + "url": "https://github.com/SAML-Toolkits/php-saml.git", + "reference": "d3b5172f137db2f412239432d77253ceaaa1e939" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/onelogin/php-saml/zipball/b22a57ebd13e838b90df5d3346090bc37056409d", - "reference": "b22a57ebd13e838b90df5d3346090bc37056409d", + "url": "https://api.github.com/repos/SAML-Toolkits/php-saml/zipball/d3b5172f137db2f412239432d77253ceaaa1e939", + "reference": "d3b5172f137db2f412239432d77253ceaaa1e939", "shasum": "" }, "require": { "php": ">=7.3", - "robrichards/xmlseclibs": ">=3.1.1" + "robrichards/xmlseclibs": "^3.1" }, "require-dev": { "pdepend/pdepend": "^2.8.0", @@ -4571,32 +5819,40 @@ "license": [ "MIT" ], - "description": "OneLogin PHP SAML Toolkit", - "homepage": "https://developers.onelogin.com/saml/php", + "description": "PHP SAML Toolkit", + "homepage": "https://github.com/SAML-Toolkits/php-saml", "keywords": [ + "Federation", "SAML2", - "onelogin", + "SSO", + "identity", "saml" ], "support": { - "email": "sixto.garcia@onelogin.com", - "issues": "https://github.com/onelogin/php-saml/issues", - "source": "https://github.com/onelogin/php-saml/" + "email": "sixto.martin.garcia@gmail.com", + "issues": "https://github.com/onelogin/SAML-Toolkits/issues", + "source": "https://github.com/onelogin/SAML-Toolkits/" }, - "time": "2022-07-15T20:44:36+00:00" + "funding": [ + { + "url": "https://github.com/SAML-Toolkits", + "type": "github" + } + ], + "time": "2024-05-30T15:10:40+00:00" }, { "name": "paragonie/constant_time_encoding", - "version": "v2.6.3", + "version": "v2.7.0", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "58c3f47f650c94ec05a151692652a868995d2938" + "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/58c3f47f650c94ec05a151692652a868995d2938", - "reference": "58c3f47f650c94ec05a151692652a868995d2938", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105", + "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105", "shasum": "" }, "require": { @@ -4650,7 +5906,7 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2022-06-14T06:56:20+00:00" + "time": "2024-05-08T12:18:48+00:00" }, { "name": "paragonie/random_compat", @@ -4703,17 +5959,103 @@ "time": "2020-10-15T08:29:30+00:00" }, { - "name": "part-db/label-fonts", - "version": "v1.0.0", + "name": "paragonie/sodium_compat", + "version": "v1.21.1", "source": { "type": "git", - "url": "https://github.com/Part-DB/label-fonts.git", - "reference": "65f4a47d877f45e39804cd86a4fc65789b49ee2f" + "url": "https://github.com/paragonie/sodium_compat.git", + "reference": "bb312875dcdd20680419564fe42ba1d9564b9e37" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Part-DB/label-fonts/zipball/65f4a47d877f45e39804cd86a4fc65789b49ee2f", - "reference": "65f4a47d877f45e39804cd86a4fc65789b49ee2f", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/bb312875dcdd20680419564fe42ba1d9564b9e37", + "reference": "bb312875dcdd20680419564fe42ba1d9564b9e37", + "shasum": "" + }, + "require": { + "paragonie/random_compat": ">=1", + "php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^3|^4|^5|^6|^7|^8|^9" + }, + "suggest": { + "ext-libsodium": "PHP < 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security.", + "ext-sodium": "PHP >= 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security." + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com" + }, + { + "name": "Frank Denis", + "email": "jedisct1@pureftpd.org" + } + ], + "description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists", + "keywords": [ + "Authentication", + "BLAKE2b", + "ChaCha20", + "ChaCha20-Poly1305", + "Chapoly", + "Curve25519", + "Ed25519", + "EdDSA", + "Edwards-curve Digital Signature Algorithm", + "Elliptic Curve Diffie-Hellman", + "Poly1305", + "Pure-PHP cryptography", + "RFC 7748", + "RFC 8032", + "Salpoly", + "Salsa20", + "X25519", + "XChaCha20-Poly1305", + "XSalsa20-Poly1305", + "Xchacha20", + "Xsalsa20", + "aead", + "cryptography", + "ecdh", + "elliptic curve", + "elliptic curve cryptography", + "encryption", + "libsodium", + "php", + "public-key cryptography", + "secret-key cryptography", + "side-channel resistant" + ], + "support": { + "issues": "https://github.com/paragonie/sodium_compat/issues", + "source": "https://github.com/paragonie/sodium_compat/tree/v1.21.1" + }, + "time": "2024-04-22T22:05:04+00:00" + }, + { + "name": "part-db/label-fonts", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/Part-DB/label-fonts.git", + "reference": "77c84b70ed3bb005df15f30ff835ddec490394b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Part-DB/label-fonts/zipball/77c84b70ed3bb005df15f30ff835ddec490394b9", + "reference": "77c84b70ed3bb005df15f30ff835ddec490394b9", "shasum": "" }, "type": "library", @@ -4736,112 +6078,22 @@ ], "support": { "issues": "https://github.com/Part-DB/label-fonts/issues", - "source": "https://github.com/Part-DB/label-fonts/tree/v1.0.0" + "source": "https://github.com/Part-DB/label-fonts/tree/v1.1.0" }, - "time": "2023-07-02T01:01:20+00:00" - }, - { - "name": "phenx/php-font-lib", - "version": "0.5.4", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-font-lib.git", - "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/dd448ad1ce34c63d09baccd05415e361300c35b4", - "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4", - "shasum": "" - }, - "require": { - "ext-mbstring": "*" - }, - "require-dev": { - "symfony/phpunit-bridge": "^3 || ^4 || ^5" - }, - "type": "library", - "autoload": { - "psr-4": { - "FontLib\\": "src/FontLib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse, export and make subsets of different types of font files.", - "homepage": "https://github.com/PhenX/php-font-lib", - "support": { - "issues": "https://github.com/dompdf/php-font-lib/issues", - "source": "https://github.com/dompdf/php-font-lib/tree/0.5.4" - }, - "time": "2021-12-17T19:44:54+00:00" - }, - { - "name": "phenx/php-svg-lib", - "version": "0.5.0", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "76876c6cf3080bcb6f249d7d59705108166a6685" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/76876c6cf3080bcb6f249d7d59705108166a6685", - "reference": "76876c6cf3080bcb6f249d7d59705108166a6685", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^7.1 || ^8.0", - "sabberworm/php-css-parser": "^8.4" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Svg\\": "src/Svg" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse and export to PDF SVG files.", - "homepage": "https://github.com/PhenX/php-svg-lib", - "support": { - "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.0" - }, - "time": "2022-09-06T12:16:56+00:00" + "time": "2024-02-08T21:44:38+00:00" }, { "name": "php-http/discovery", - "version": "1.19.1", + "version": "1.20.0", "source": { "type": "git", "url": "https://github.com/php-http/discovery.git", - "reference": "57f3de01d32085fea20865f9b16fb0e69347c39e" + "reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/57f3de01d32085fea20865f9b16fb0e69347c39e", - "reference": "57f3de01d32085fea20865f9b16fb0e69347c39e", + "url": "https://api.github.com/repos/php-http/discovery/zipball/82fe4c73ef3363caed49ff8dd1539ba06044910d", + "reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d", "shasum": "" }, "require": { @@ -4865,7 +6117,8 @@ "php-http/httplug": "^1.0 || ^2.0", "php-http/message-factory": "^1.0", "phpspec/phpspec": "^5.1 || ^6.1 || ^7.3", - "symfony/phpunit-bridge": "^6.2" + "sebastian/comparator": "^3.0.5 || ^4.0.8", + "symfony/phpunit-bridge": "^6.4.4 || ^7.0.1" }, "type": "composer-plugin", "extra": { @@ -4904,22 +6157,22 @@ ], "support": { "issues": "https://github.com/php-http/discovery/issues", - "source": "https://github.com/php-http/discovery/tree/1.19.1" + "source": "https://github.com/php-http/discovery/tree/1.20.0" }, - "time": "2023-07-11T07:02:26+00:00" + "time": "2024-10-02T11:20:13+00:00" }, { "name": "php-http/httplug", - "version": "2.4.0", + "version": "2.4.1", "source": { "type": "git", "url": "https://github.com/php-http/httplug.git", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67" + "reference": "5cad731844891a4c282f3f3e1b582c46839d22f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/httplug/zipball/625ad742c360c8ac580fcc647a1541d29e257f67", - "reference": "625ad742c360c8ac580fcc647a1541d29e257f67", + "url": "https://api.github.com/repos/php-http/httplug/zipball/5cad731844891a4c282f3f3e1b582c46839d22f4", + "reference": "5cad731844891a4c282f3f3e1b582c46839d22f4", "shasum": "" }, "require": { @@ -4961,92 +6214,32 @@ ], "support": { "issues": "https://github.com/php-http/httplug/issues", - "source": "https://github.com/php-http/httplug/tree/2.4.0" + "source": "https://github.com/php-http/httplug/tree/2.4.1" }, - "time": "2023-04-14T15:10:03+00:00" - }, - { - "name": "php-http/message-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-http/message-factory.git", - "reference": "4d8778e1c7d405cbb471574821c1ff5b68cc8f57" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-http/message-factory/zipball/4d8778e1c7d405cbb471574821c1ff5b68cc8f57", - "reference": "4d8778e1c7d405cbb471574821c1ff5b68cc8f57", - "shasum": "" - }, - "require": { - "php": ">=5.4", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com" - } - ], - "description": "Factory interfaces for PSR-7 HTTP Message", - "homepage": "http://php-http.org", - "keywords": [ - "factory", - "http", - "message", - "stream", - "uri" - ], - "support": { - "issues": "https://github.com/php-http/message-factory/issues", - "source": "https://github.com/php-http/message-factory/tree/1.1.0" - }, - "abandoned": "psr/http-factory", - "time": "2023-04-14T14:16:17+00:00" + "time": "2024-09-23T11:39:58+00:00" }, { "name": "php-http/promise", - "version": "1.1.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/php-http/promise.git", - "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88" + "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/promise/zipball/4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", - "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88", + "url": "https://api.github.com/repos/php-http/promise/zipball/fc85b1fba37c169a69a07ef0d5a8075770cc1f83", + "reference": "fc85b1fba37c169a69a07ef0d5a8075770cc1f83", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "friends-of-phpspec/phpspec-code-coverage": "^4.3.2", - "phpspec/phpspec": "^5.1.2 || ^6.2" + "friends-of-phpspec/phpspec-code-coverage": "^4.3.2 || ^6.3", + "phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, "autoload": { "psr-4": { "Http\\Promise\\": "src/" @@ -5073,238 +6266,9 @@ ], "support": { "issues": "https://github.com/php-http/promise/issues", - "source": "https://github.com/php-http/promise/tree/1.1.0" + "source": "https://github.com/php-http/promise/tree/1.3.1" }, - "time": "2020-07-07T09:29:14+00:00" - }, - { - "name": "php-translation/common", - "version": "3.2.0", - "source": { - "type": "git", - "url": "https://github.com/php-translation/common.git", - "reference": "986ddf4e3b2b3458d2a7353658bd40764d8ca1d1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-translation/common/zipball/986ddf4e3b2b3458d2a7353658bd40764d8ca1d1", - "reference": "986ddf4e3b2b3458d2a7353658bd40764d8ca1d1", - "shasum": "" - }, - "require": { - "php": ">=7.2", - "symfony/translation": " ^3.4 || ^4.3 || ^5.0 || ^6.0" - }, - "require-dev": { - "phpunit/phpunit": "^8.4", - "symfony/phpunit-bridge": "^4.3 || ^5.0 || ^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Translation\\Common\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - } - ], - "description": "Common translation stuff", - "support": { - "issues": "https://github.com/php-translation/common/issues", - "source": "https://github.com/php-translation/common/tree/3.2.0" - }, - "time": "2022-02-04T11:49:38+00:00" - }, - { - "name": "php-translation/extractor", - "version": "2.1.1", - "source": { - "type": "git", - "url": "https://github.com/php-translation/extractor.git", - "reference": "09ad2f3654e6badb95a739b0284f5785531f7c8d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-translation/extractor/zipball/09ad2f3654e6badb95a739b0284f5785531f7c8d", - "reference": "09ad2f3654e6badb95a739b0284f5785531f7c8d", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^1.7 || ^2.0", - "nikic/php-parser": "^3.0 || ^4.0", - "php": "^7.2 || ^8.0", - "symfony/finder": "^3.4 || ^4.4 || ^5.0 || ^6.0", - "twig/twig": "^2.0 || ^3.0" - }, - "require-dev": { - "knplabs/knp-menu": "^3.1", - "symfony/phpunit-bridge": "^5.0 || ^6.0", - "symfony/translation": "^3.4 || ^4.4 || ^5.0 || ^6.0", - "symfony/twig-bridge": "^3.4 || ^4.4 || ^5.0 || ^6.0", - "symfony/validator": "^3.4 || ^4.4 || ^5.0 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-4": { - "Translation\\Extractor\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - } - ], - "description": "Extract translations form the source code", - "support": { - "issues": "https://github.com/php-translation/extractor/issues", - "source": "https://github.com/php-translation/extractor/tree/2.1.1" - }, - "time": "2023-03-28T11:37:22+00:00" - }, - { - "name": "php-translation/symfony-bundle", - "version": "0.14.0", - "source": { - "type": "git", - "url": "https://github.com/php-translation/symfony-bundle.git", - "reference": "1eb4d47c451eaae3efe2ca99b80b433cc4aeaf58" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-translation/symfony-bundle/zipball/1eb4d47c451eaae3efe2ca99b80b433cc4aeaf58", - "reference": "1eb4d47c451eaae3efe2ca99b80b433cc4aeaf58", - "shasum": "" - }, - "require": { - "nyholm/nsa": "^1.1", - "php": "^8.0", - "php-translation/extractor": "^2.0", - "php-translation/symfony-storage": "^2.1", - "symfony/asset": "^5.3 || ^6.0", - "symfony/console": "^5.3 || ^6.0", - "symfony/finder": "^5.3 || ^6.0", - "symfony/framework-bundle": "^5.3 || ^6.0", - "symfony/intl": "^5.3 || ^6.0", - "symfony/translation": "^5.3 || ^6.0", - "symfony/twig-bundle": "^5.3 || ^6.0", - "symfony/validator": "^5.3 || ^6.0", - "twig/twig": "^2.14.4 || ^3.3" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.3", - "matthiasnoback/symfony-config-test": "^4.1", - "matthiasnoback/symfony-dependency-injection-test": "^4.1", - "nyholm/psr7": "^1.1", - "nyholm/symfony-bundle-test": "^2.0", - "php-http/curl-client": "^1.7 || ^2.0", - "php-http/message": "^1.11", - "php-http/message-factory": "^1.0.2", - "php-translation/translator": "^1.0", - "symfony/dependency-injection": "^5.3 || ^6.0", - "symfony/phpunit-bridge": "^5.2 || ^6.0", - "symfony/twig-bridge": "^5.3 || ^6.0", - "symfony/web-profiler-bundle": "^5.3 || ^6.0" - }, - "suggest": { - "php-http/httplug-bundle": "To easier configure your httplug clients." - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "0.12-dev" - } - }, - "autoload": { - "psr-4": { - "Translation\\Bundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - } - ], - "support": { - "issues": "https://github.com/php-translation/symfony-bundle/issues", - "source": "https://github.com/php-translation/symfony-bundle/tree/0.14.0" - }, - "time": "2023-07-11T17:58:52+00:00" - }, - { - "name": "php-translation/symfony-storage", - "version": "2.3.1", - "source": { - "type": "git", - "url": "https://github.com/php-translation/symfony-storage.git", - "reference": "95d52dd86d41fe0ec2c75e1469b5003956044cc8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-translation/symfony-storage/zipball/95d52dd86d41fe0ec2c75e1469b5003956044cc8", - "reference": "95d52dd86d41fe0ec2c75e1469b5003956044cc8", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "php-translation/common": "^3.0", - "symfony/translation": "^3.4 || ^4.2 || ^5.0 || ^6.0" - }, - "require-dev": { - "phpunit/phpunit": ">=8.5.20", - "symfony/framework-bundle": " ^3.4 || ^4.2 || ^5.0 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.4-dev" - } - }, - "autoload": { - "psr-4": { - "Translation\\SymfonyStorage\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com" - } - ], - "description": "A translation file storage using Symfony translation component.", - "support": { - "issues": "https://github.com/php-translation/symfony-storage/issues", - "source": "https://github.com/php-translation/symfony-storage/tree/2.3.1" - }, - "time": "2022-02-14T11:36:15+00:00" + "time": "2024-03-15T13:55:21+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -5361,28 +6325,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "version": "5.6.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62", + "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62", "shasum": "" }, "require": { + "doctrine/deprecations": "^1.1", "ext-filter": "*", - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7|^2.0", "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "mockery/mockery": "~1.3.5 || ~1.6.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "psalm/phar": "^5.26" }, "type": "library", "extra": { @@ -5406,35 +6377,35 @@ }, { "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "email": "opensource@ijaap.nl" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2" }, - "time": "2021-10-19T17:43:47+00:00" + "time": "2025-04-13T19:20:35+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.2", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d" + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b2fe4d22a5426f38e014855322200b97b5362c0d", - "reference": "b2fe4d22a5426f38e014855322200b97b5362c0d", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", "shasum": "" }, "require": { "doctrine/deprecations": "^1.0", - "php": "^7.4 || ^8.0", + "php": "^7.3 || ^8.0", "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.13" + "phpstan/phpdoc-parser": "^1.18|^2.0" }, "require-dev": { "ext-tokenizer": "*", @@ -5470,36 +6441,36 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.2" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" }, - "time": "2023-05-30T18:13:47+00:00" + "time": "2024-11-09T15:12:26+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.23.0", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "a2b24135c35852b348894320d47b3902a94bc494" + "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a2b24135c35852b348894320d47b3902a94bc494", - "reference": "a2b24135c35852b348894320d47b3902a94bc494", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", + "reference": "9b30d6fd026b2c132b3985ce6b23bec09ab3aa68", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "doctrine/annotations": "^2.0", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^5.3.0", "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", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", "symfony/process": "^5.2" }, "type": "library", @@ -5517,9 +6488,9 @@ "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.23.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.1.0" }, - "time": "2023-07-23T22:17:56+00:00" + "time": "2025-02-19T13:28:12+00:00" }, { "name": "psr/cache", @@ -5723,16 +6694,16 @@ }, { "name": "psr/http-client", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", "shasum": "" }, "require": { @@ -5769,26 +6740,26 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/1.0.2" + "source": "https://github.com/php-fig/http-client" }, - "time": "2023-04-10T20:12:12+00:00" + "time": "2023-09-23T14:17:50+00:00" }, { "name": "psr/http-factory", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.0.0", + "php": ">=7.1", "psr/http-message": "^1.0 || ^2.0" }, "type": "library", @@ -5812,7 +6783,7 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -5824,9 +6795,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2023-04-10T20:10:41+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", @@ -5939,16 +6910,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -5983,9 +6954,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { "name": "psr/simple-cache", @@ -6083,17 +7054,134 @@ "time": "2019-03-08T08:55:37+00:00" }, { - "name": "robrichards/xmlseclibs", - "version": "3.1.1", + "name": "revolt/event-loop", + "version": "v1.0.7", "source": { "type": "git", - "url": "https://github.com/robrichards/xmlseclibs.git", - "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df" + "url": "https://github.com/revoltphp/event-loop.git", + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/f8f19e58f26cdb42c54b214ff8a820760292f8df", - "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df", + "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3", + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.15" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Revolt\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "ceesjank@gmail.com" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Rock-solid event loop for concurrent PHP applications.", + "keywords": [ + "async", + "asynchronous", + "concurrency", + "event", + "event-loop", + "non-blocking", + "scheduler" + ], + "support": { + "issues": "https://github.com/revoltphp/event-loop/issues", + "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7" + }, + "time": "2025-01-25T19:27:39+00:00" + }, + { + "name": "rhukster/dom-sanitizer", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/rhukster/dom-sanitizer.git", + "reference": "c2a98f27ad742668b254282ccc5581871d0fb601" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rhukster/dom-sanitizer/zipball/c2a98f27ad742668b254282ccc5581871d0fb601", + "reference": "c2a98f27ad742668b254282ccc5581871d0fb601", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Rhukster\\DomSanitizer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andy Miller", + "email": "rhuk@rhuk.net" + } + ], + "description": "A simple but effective DOM/SVG/MathML Sanitizer for PHP 7.4+", + "support": { + "issues": "https://github.com/rhukster/dom-sanitizer/issues", + "source": "https://github.com/rhukster/dom-sanitizer/tree/1.0.7" + }, + "time": "2023-11-06T16:46:48+00:00" + }, + { + "name": "robrichards/xmlseclibs", + "version": "3.1.3", + "source": { + "type": "git", + "url": "https://github.com/robrichards/xmlseclibs.git", + "reference": "2bdfd742624d739dfadbd415f00181b4a77aaf07" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/2bdfd742624d739dfadbd415f00181b4a77aaf07", + "reference": "2bdfd742624d739dfadbd415f00181b4a77aaf07", "shasum": "" }, "require": { @@ -6120,9 +7208,61 @@ ], "support": { "issues": "https://github.com/robrichards/xmlseclibs/issues", - "source": "https://github.com/robrichards/xmlseclibs/tree/3.1.1" + "source": "https://github.com/robrichards/xmlseclibs/tree/3.1.3" }, - "time": "2020-09-05T13:00:25+00:00" + "time": "2024-11-20T21:13:56+00:00" + }, + { + "name": "runtime/frankenphp-symfony", + "version": "0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-runtime/frankenphp-symfony.git", + "reference": "56822c3631d9522a3136a4c33082d006bdfe4bad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-runtime/frankenphp-symfony/zipball/56822c3631d9522a3136a4c33082d006bdfe4bad", + "reference": "56822c3631d9522a3136a4c33082d006bdfe4bad", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "symfony/runtime": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Runtime\\FrankenPhpSymfony\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.dev" + } + ], + "description": "FrankenPHP runtime for Symfony", + "support": { + "issues": "https://github.com/php-runtime/frankenphp-symfony/issues", + "source": "https://github.com/php-runtime/frankenphp-symfony/tree/0.2.0" + }, + "funding": [ + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2023-12-12T12:06:11+00:00" }, { "name": "s9e/regexp-builder", @@ -6168,24 +7308,26 @@ }, { "name": "s9e/sweetdom", - "version": "2.1.1", + "version": "3.4.1", "source": { "type": "git", "url": "https://github.com/s9e/SweetDOM.git", - "reference": "dd5d814f93621b1489bfbac8e0331122b928a18a" + "reference": "ef3a7d2745b30b4ad0d1d3d60be391a3604c69dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/s9e/SweetDOM/zipball/dd5d814f93621b1489bfbac8e0331122b928a18a", - "reference": "dd5d814f93621b1489bfbac8e0331122b928a18a", + "url": "https://api.github.com/repos/s9e/SweetDOM/zipball/ef3a7d2745b30b4ad0d1d3d60be391a3604c69dd", + "reference": "ef3a7d2745b30b4ad0d1d3d60be391a3604c69dd", "shasum": "" }, "require": { "ext-dom": "*", - "php": ">=8.0" + "php": "^8.1" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "friendsofphp/php-cs-fixer": "^3.52", + "phpunit/phpunit": "^10.0", + "s9e/repdoc": "dev-wip" }, "type": "library", "autoload": { @@ -6206,34 +7348,35 @@ ], "support": { "issues": "https://github.com/s9e/SweetDOM/issues", - "source": "https://github.com/s9e/SweetDOM/tree/2.1.1" + "source": "https://github.com/s9e/SweetDOM/tree/3.4.1" }, - "time": "2023-06-05T19:10:26+00:00" + "time": "2024-03-23T14:03:01+00:00" }, { "name": "s9e/text-formatter", - "version": "2.14.0", + "version": "2.19.0", "source": { "type": "git", "url": "https://github.com/s9e/TextFormatter.git", - "reference": "48a2f3a3fb18af8d78330204732a3369441c4060" + "reference": "d65a4f61cbe494937afb3150dc73b6e757d400d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/s9e/TextFormatter/zipball/48a2f3a3fb18af8d78330204732a3369441c4060", - "reference": "48a2f3a3fb18af8d78330204732a3369441c4060", + "url": "https://api.github.com/repos/s9e/TextFormatter/zipball/d65a4f61cbe494937afb3150dc73b6e757d400d3", + "reference": "d65a4f61cbe494937afb3150dc73b6e757d400d3", "shasum": "" }, "require": { "ext-dom": "*", "ext-filter": "*", "lib-pcre": ">=8.13", - "php": "^8.0", + "php": "^8.1", "s9e/regexp-builder": "^1.4", - "s9e/sweetdom": "^2.0" + "s9e/sweetdom": "^3.4" }, "require-dev": { "code-lts/doctum": "*", + "friendsofphp/php-cs-fixer": "^3.52", "matthiasmullie/minify": "*", "phpunit/phpunit": "^9.5" }, @@ -6248,7 +7391,7 @@ }, "type": "library", "extra": { - "version": "2.14.0" + "version": "2.19.0" }, "autoload": { "psr-4": { @@ -6280,36 +7423,40 @@ ], "support": { "issues": "https://github.com/s9e/TextFormatter/issues", - "source": "https://github.com/s9e/TextFormatter/tree/2.14.0" + "source": "https://github.com/s9e/TextFormatter/tree/2.19.0" }, - "time": "2023-06-08T07:19:50+00:00" + "time": "2025-04-26T09:27:34+00:00" }, { "name": "sabberworm/php-css-parser", - "version": "8.4.0", + "version": "v8.8.0", "source": { "type": "git", - "url": "https://github.com/sabberworm/PHP-CSS-Parser.git", - "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30" + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "3de493bdddfd1f051249af725c7e0d2c38fed740" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sabberworm/PHP-CSS-Parser/zipball/e41d2140031d533348b2192a83f02d8dd8a71d30", - "reference": "e41d2140031d533348b2192a83f02d8dd8a71d30", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/3de493bdddfd1f051249af725c7e0d2c38fed740", + "reference": "3de493bdddfd1f051249af725c7e0d2c38fed740", "shasum": "" }, "require": { "ext-iconv": "*", - "php": ">=5.6.20" + "php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "require-dev": { - "codacy/coverage": "^1.4", - "phpunit/phpunit": "^4.8.36" + "phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41" }, "suggest": { "ext-mbstring": "for parsing UTF-8 CSS" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.0.x-dev" + } + }, "autoload": { "psr-4": { "Sabberworm\\CSS\\": "src/" @@ -6322,6 +7469,14 @@ "authors": [ { "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" } ], "description": "Parser for CSS Files written in PHP", @@ -6332,27 +7487,27 @@ "stylesheet" ], "support": { - "issues": "https://github.com/sabberworm/PHP-CSS-Parser/issues", - "source": "https://github.com/sabberworm/PHP-CSS-Parser/tree/8.4.0" + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.8.0" }, - "time": "2021-12-11T13:40:54+00:00" + "time": "2025-03-23T17:59:05+00:00" }, { "name": "scheb/2fa-backup-code", - "version": "v6.8.0", + "version": "v6.13.1", "source": { "type": "git", "url": "https://github.com/scheb/2fa-backup-code.git", - "reference": "b01965cd221cda280526e48e7f56966154b9ba2f" + "reference": "6dceeb5be0f6339d76f8e380ee09631c8bbebc7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-backup-code/zipball/b01965cd221cda280526e48e7f56966154b9ba2f", - "reference": "b01965cd221cda280526e48e7f56966154b9ba2f", + "url": "https://api.github.com/repos/scheb/2fa-backup-code/zipball/6dceeb5be0f6339d76f8e380ee09631c8bbebc7e", + "reference": "6dceeb5be0f6339d76f8e380ee09631c8bbebc7e", "shasum": "" }, "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "scheb/2fa-bundle": "self.version" }, "type": "library", @@ -6382,27 +7537,27 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-backup-code/tree/v6.8.0" + "source": "https://github.com/scheb/2fa-backup-code/tree/v6.13.1" }, - "time": "2022-12-10T15:20:09+00:00" + "time": "2024-11-29T19:22:48+00:00" }, { "name": "scheb/2fa-bundle", - "version": "v6.8.0", + "version": "v6.13.1", "source": { "type": "git", "url": "https://github.com/scheb/2fa-bundle.git", - "reference": "4f8e9e87f90cf50c72b0857ea2b88453cf1d2446" + "reference": "8eadd57ebc2078ef273dca72b1ac4bd283812346" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-bundle/zipball/4f8e9e87f90cf50c72b0857ea2b88453cf1d2446", - "reference": "4f8e9e87f90cf50c72b0857ea2b88453cf1d2446", + "url": "https://api.github.com/repos/scheb/2fa-bundle/zipball/8eadd57ebc2078ef273dca72b1ac4bd283812346", + "reference": "8eadd57ebc2078ef273dca72b1ac4bd283812346", "shasum": "" }, "require": { "ext-json": "*", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "symfony/config": "^5.4 || ^6.0", "symfony/dependency-injection": "^5.4 || ^6.0", "symfony/event-dispatcher": "^5.4 || ^6.0", @@ -6414,7 +7569,8 @@ "symfony/twig-bundle": "^5.4 || ^6.0" }, "conflict": { - "scheb/two-factor-bundle": "*" + "scheb/two-factor-bundle": "*", + "symfony/security-core": "^7" }, "suggest": { "scheb/2fa-backup-code": "Emergency codes when you have no access to other methods", @@ -6449,27 +7605,27 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-bundle/tree/v6.8.0" + "source": "https://github.com/scheb/2fa-bundle/tree/v6.13.1" }, - "time": "2023-01-26T18:47:22+00:00" + "time": "2024-11-29T19:29:49+00:00" }, { "name": "scheb/2fa-google-authenticator", - "version": "v6.8.0", + "version": "v6.13.1", "source": { "type": "git", "url": "https://github.com/scheb/2fa-google-authenticator.git", - "reference": "20eab4c1814b587cac71c4516a06b192ca838294" + "reference": "2c960a5cb32edb4c37f719f10180df378a44fd6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-google-authenticator/zipball/20eab4c1814b587cac71c4516a06b192ca838294", - "reference": "20eab4c1814b587cac71c4516a06b192ca838294", + "url": "https://api.github.com/repos/scheb/2fa-google-authenticator/zipball/2c960a5cb32edb4c37f719f10180df378a44fd6f", + "reference": "2c960a5cb32edb4c37f719f10180df378a44fd6f", "shasum": "" }, "require": { "paragonie/constant_time_encoding": "^2.4", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "scheb/2fa-bundle": "self.version", "spomky-labs/otphp": "^10.0 || ^11.0" }, @@ -6500,28 +7656,28 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-google-authenticator/tree/v6.8.0" + "source": "https://github.com/scheb/2fa-google-authenticator/tree/v6.13.1" }, - "time": "2022-12-10T15:20:09+00:00" + "time": "2024-11-29T19:22:48+00:00" }, { "name": "scheb/2fa-trusted-device", - "version": "v6.8.0", + "version": "v6.13.1", "source": { "type": "git", "url": "https://github.com/scheb/2fa-trusted-device.git", - "reference": "cac6feaf9f2c7d3a1aade86942f7b7b234fcd151" + "reference": "38e690325232a4037ff4aec8de926c938906942c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-trusted-device/zipball/cac6feaf9f2c7d3a1aade86942f7b7b234fcd151", - "reference": "cac6feaf9f2c7d3a1aade86942f7b7b234fcd151", + "url": "https://api.github.com/repos/scheb/2fa-trusted-device/zipball/38e690325232a4037ff4aec8de926c938906942c", + "reference": "38e690325232a4037ff4aec8de926c938906942c", "shasum": "" }, "require": { "lcobucci/clock": "^2.0 || ^3.0", "lcobucci/jwt": "^4.1 || ^5.0", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0", + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "scheb/2fa-bundle": "self.version" }, "type": "library", @@ -6551,36 +7707,36 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-trusted-device/tree/v6.8.0" + "source": "https://github.com/scheb/2fa-trusted-device/tree/v6.13.1" }, - "time": "2023-04-01T11:20:00+00:00" + "time": "2024-11-29T19:22:48+00:00" }, { "name": "shivas/versioning-bundle", - "version": "4.0.3", + "version": "4.1.1", "source": { "type": "git", "url": "https://github.com/shivas/versioning-bundle.git", - "reference": "88d8fe08f7be8ce7b802adecc71a90f40b7bb8e4" + "reference": "fd89e3501ff1b0d3e6abe61eb7a878d1d4746868" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/shivas/versioning-bundle/zipball/88d8fe08f7be8ce7b802adecc71a90f40b7bb8e4", - "reference": "88d8fe08f7be8ce7b802adecc71a90f40b7bb8e4", + "url": "https://api.github.com/repos/shivas/versioning-bundle/zipball/fd89e3501ff1b0d3e6abe61eb7a878d1d4746868", + "reference": "fd89e3501ff1b0d3e6abe61eb7a878d1d4746868", "shasum": "" }, "require": { "nikolaposa/version": "^4", - "php": "^7.2 || ^8", - "symfony/console": "^3.4 || ^4 || ^5 || ^6", - "symfony/framework-bundle": "^3.4 || ^4 || ^5 || ^6", - "symfony/process": "^3.4 || ^4 || ^5 || ^6" + "php": "^7.2.5 || ^8", + "symfony/console": "^5.4 || ^6 || ^7", + "symfony/framework-bundle": "^5.4 || ^6 || ^7", + "symfony/process": "^5.4 || ^6 || ^7" }, "require-dev": { "mikey179/vfsstream": "^2", - "nyholm/symfony-bundle-test": "1.x-dev", + "nyholm/symfony-bundle-test": "^3.0", "phpunit/phpunit": "^8.5.27", - "symfony/phpunit-bridge": "^5 || ^6", + "symfony/phpunit-bridge": "^5.4 || ^6 || ^7", "twig/twig": "^2 || ^3" }, "type": "symfony-bundle", @@ -6610,28 +7766,28 @@ ], "support": { "issues": "https://github.com/shivas/versioning-bundle/issues", - "source": "https://github.com/shivas/versioning-bundle/tree/4.0.3", + "source": "https://github.com/shivas/versioning-bundle/tree/4.1.1", "wiki": "https://github.com/shivas/versioning-bundle/wiki" }, - "time": "2023-07-30T17:15:29+00:00" + "time": "2024-08-14T19:33:15+00:00" }, { "name": "spatie/db-dumper", - "version": "3.4.0", + "version": "3.8.0", "source": { "type": "git", "url": "https://github.com/spatie/db-dumper.git", - "reference": "bbd5ae0f331d47e6534eb307e256c11a65c8e24a" + "reference": "91e1fd4dc000aefc9753cda2da37069fc996baee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/db-dumper/zipball/bbd5ae0f331d47e6534eb307e256c11a65c8e24a", - "reference": "bbd5ae0f331d47e6534eb307e256c11a65c8e24a", + "url": "https://api.github.com/repos/spatie/db-dumper/zipball/91e1fd4dc000aefc9753cda2da37069fc996baee", + "reference": "91e1fd4dc000aefc9753cda2da37069fc996baee", "shasum": "" }, "require": { "php": "^8.0", - "symfony/process": "^5.0|^6.0" + "symfony/process": "^5.0|^6.0|^7.0" }, "require-dev": { "pestphp/pest": "^1.22" @@ -6664,7 +7820,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/db-dumper/tree/3.4.0" + "source": "https://github.com/spatie/db-dumper/tree/3.8.0" }, "funding": [ { @@ -6676,111 +7832,31 @@ "type": "github" } ], - "time": "2023-06-27T08:34:52+00:00" - }, - { - "name": "spomky-labs/cbor-bundle", - "version": "v3.0.0", - "source": { - "type": "git", - "url": "https://github.com/Spomky-Labs/cbor-bundle.git", - "reference": "157ca6ed2f6e957f9e95d71ca86bc67bf42ee79c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/cbor-bundle/zipball/157ca6ed2f6e957f9e95d71ca86bc67bf42ee79c", - "reference": "157ca6ed2f6e957f9e95d71ca86bc67bf42ee79c", - "shasum": "" - }, - "require": { - "php": ">=8.0", - "spomky-labs/cbor-php": "^3.0", - "symfony/config": "^5.3|^6.0", - "symfony/dependency-injection": "^5.3|^6.0", - "symfony/http-kernel": "^5.3|^6.0" - }, - "require-dev": { - "infection/infection": "^0.25.3", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-beberlei-assert": "^1.0", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.0", - "rector/rector": "^0.12.5", - "symfony/framework-bundle": "^5.3|^6.0", - "symfony/phpunit-bridge": "^5.3|^6.0", - "symplify/easy-coding-standard": "^9.4" - }, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "SpomkyLabs\\CborBundle\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/spomky-labs/cbor-bundle/contributors" - } - ], - "description": "CBOR Encoder/Decoder Bundle for Symfony.", - "homepage": "https://github.com/spomky-labs", - "keywords": [ - "Concise Binary Object Representation", - "RFC7049", - "bundle", - "cbor", - "symfony" - ], - "support": { - "issues": "https://github.com/Spomky-Labs/cbor-bundle/issues", - "source": "https://github.com/Spomky-Labs/cbor-bundle/tree/v3.0.0" - }, - "funding": [ - { - "url": "https://github.com/Spomky", - "type": "github" - }, - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" - } - ], - "time": "2021-11-23T21:41:00+00:00" + "time": "2025-02-14T15:04:22+00:00" }, { "name": "spomky-labs/cbor-php", - "version": "3.0.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/Spomky-Labs/cbor-php.git", - "reference": "81d5dff7a1101d680729b5789f4359d01b15e6c5" + "reference": "499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/81d5dff7a1101d680729b5789f4359d01b15e6c5", - "reference": "81d5dff7a1101d680729b5789f4359d01b15e6c5", + "url": "https://api.github.com/repos/Spomky-Labs/cbor-php/zipball/499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4", + "reference": "499d9bff0a6d59c4f1b813cc617fc3fd56d6dca4", "shasum": "" }, "require": { - "brick/math": "^0.9|^0.10|^0.11", + "brick/math": "^0.9|^0.10|^0.11|^0.12", "ext-mbstring": "*", "php": ">=8.0" }, "require-dev": { "ekino/phpstan-banned-code": "^1.0", "ext-json": "*", - "infection/infection": "^0.26", + "infection/infection": "^0.29", "php-parallel-lint/php-parallel-lint": "^1.3", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", @@ -6788,12 +7864,12 @@ "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^10.0", - "qossmic/deptrac-shim": "^1.0", - "rector/rector": "^0.15", + "phpunit/phpunit": "^10.1|^11.0", + "qossmic/deptrac": "^2.0", + "rector/rector": "^1.0", "roave/security-advisories": "dev-latest", - "symfony/var-dumper": "^6.0", - "symplify/easy-coding-standard": "^11.1" + "symfony/var-dumper": "^6.0|^7.0", + "symplify/easy-coding-standard": "^12.0" }, "suggest": { "ext-bcmath": "GMP or BCMath extensions will drastically improve the library performance. BCMath extension needed to handle the Big Float and Decimal Fraction Tags", @@ -6827,7 +7903,7 @@ ], "support": { "issues": "https://github.com/Spomky-Labs/cbor-php/issues", - "source": "https://github.com/Spomky-Labs/cbor-php/tree/3.0.2" + "source": "https://github.com/Spomky-Labs/cbor-php/tree/3.1.0" }, "funding": [ { @@ -6839,40 +7915,42 @@ "type": "patreon" } ], - "time": "2023-02-28T21:37:12+00:00" + "time": "2024-07-18T08:37:03+00:00" }, { "name": "spomky-labs/otphp", - "version": "11.2.0", + "version": "11.3.0", "source": { "type": "git", "url": "https://github.com/Spomky-Labs/otphp.git", - "reference": "9a1569038bb1c8e98040b14b8bcbba54f25e7795" + "reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/9a1569038bb1c8e98040b14b8bcbba54f25e7795", - "reference": "9a1569038bb1c8e98040b14b8bcbba54f25e7795", + "url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33", + "reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33", "shasum": "" }, "require": { "ext-mbstring": "*", - "paragonie/constant_time_encoding": "^2.0", - "php": "^8.1" + "paragonie/constant_time_encoding": "^2.0 || ^3.0", + "php": ">=8.1", + "psr/clock": "^1.0", + "symfony/deprecation-contracts": "^3.2" }, "require-dev": { "ekino/phpstan-banned-code": "^1.0", - "infection/infection": "^0.26", + "infection/infection": "^0.26|^0.27|^0.28|^0.29", "php-parallel-lint/php-parallel-lint": "^1.3", "phpstan/phpstan": "^1.0", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5.26", + "phpunit/phpunit": "^9.5.26|^10.0|^11.0", "qossmic/deptrac-shim": "^1.0", - "rector/rector": "^0.15", - "symfony/phpunit-bridge": "^6.1", - "symplify/easy-coding-standard": "^11.0" + "rector/rector": "^1.0", + "symfony/phpunit-bridge": "^6.1|^7.0", + "symplify/easy-coding-standard": "^12.0" }, "type": "library", "autoload": { @@ -6907,7 +7985,7 @@ ], "support": { "issues": "https://github.com/Spomky-Labs/otphp/issues", - "source": "https://github.com/Spomky-Labs/otphp/tree/11.2.0" + "source": "https://github.com/Spomky-Labs/otphp/tree/11.3.0" }, "funding": [ { @@ -6919,45 +7997,44 @@ "type": "patreon" } ], - "time": "2023-03-16T19:16:25+00:00" + "time": "2024-06-12T11:22:32+00:00" }, { "name": "spomky-labs/pki-framework", - "version": "1.1.0", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/Spomky-Labs/pki-framework.git", - "reference": "d3ba688bf40e7c6e0dabf065ee18fc210734e760" + "reference": "5ff1dcc21e961b60149a80e77f744fc047800b31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/d3ba688bf40e7c6e0dabf065ee18fc210734e760", - "reference": "d3ba688bf40e7c6e0dabf065ee18fc210734e760", + "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/5ff1dcc21e961b60149a80e77f744fc047800b31", + "reference": "5ff1dcc21e961b60149a80e77f744fc047800b31", "shasum": "" }, "require": { - "brick/math": "^0.10 || ^0.11", + "brick/math": "^0.10|^0.11|^0.12|^0.13", "ext-mbstring": "*", "php": ">=8.1" }, "require-dev": { - "ekino/phpstan-banned-code": "^1.0", + "ekino/phpstan-banned-code": "^1.0|^2.0|^3.0", "ext-gmp": "*", "ext-openssl": "*", - "infection/infection": "^0.26", + "infection/infection": "^0.28|^0.29", "php-parallel-lint/php-parallel-lint": "^1.3", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-beberlei-assert": "^1.0", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.3", - "phpunit/phpunit": "^10.0", - "rector/rector": "^0.15", + "phpstan/extension-installer": "^1.3|^2.0", + "phpstan/phpstan": "^1.8|^2.0", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.1|^2.0", + "phpstan/phpstan-strict-rules": "^1.3|^2.0", + "phpunit/phpunit": "^10.1|^11.0|^12.0", + "rector/rector": "^1.0|^2.0", "roave/security-advisories": "dev-latest", - "symfony/phpunit-bridge": "^6.1", - "symfony/var-dumper": "^6.1", - "symplify/easy-coding-standard": "^11.1", - "thecodingmachine/phpstan-safe-rule": "^1.2" + "symfony/string": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symplify/easy-coding-standard": "^12.0" }, "suggest": { "ext-bcmath": "For better performance (or GMP)", @@ -7017,7 +8094,7 @@ ], "support": { "issues": "https://github.com/Spomky-Labs/pki-framework/issues", - "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.1.0" + "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.2.3" }, "funding": [ { @@ -7029,7 +8106,7 @@ "type": "patreon" } ], - "time": "2023-02-13T17:21:24+00:00" + "time": "2025-04-25T15:57:13+00:00" }, { "name": "symfony/apache-pack", @@ -7059,16 +8136,16 @@ }, { "name": "symfony/asset", - "version": "v6.3.0", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "b77a4cc8e266b7e0db688de740f9ee7253aa411c" + "reference": "2466c17d61d14539cddf77e57ebb9cc971185302" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/b77a4cc8e266b7e0db688de740f9ee7253aa411c", - "reference": "b77a4cc8e266b7e0db688de740f9ee7253aa411c", + "url": "https://api.github.com/repos/symfony/asset/zipball/2466c17d61d14539cddf77e57ebb9cc971185302", + "reference": "2466c17d61d14539cddf77e57ebb9cc971185302", "shasum": "" }, "require": { @@ -7078,9 +8155,9 @@ "symfony/http-foundation": "<5.4" }, "require-dev": { - "symfony/http-client": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0" + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -7108,7 +8185,7 @@ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v6.3.0" + "source": "https://github.com/symfony/asset/tree/v6.4.13" }, "funding": [ { @@ -7124,20 +8201,20 @@ "type": "tidelift" } ], - "time": "2023-04-21T14:41:17+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/cache", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "d176b97600860df13e851538c2df2ad88e9e5ca9" + "reference": "d1abcf763a7414f2e572f676f22da7a06c8cd9ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/d176b97600860df13e851538c2df2ad88e9e5ca9", - "reference": "d176b97600860df13e851538c2df2ad88e9e5ca9", + "url": "https://api.github.com/repos/symfony/cache/zipball/d1abcf763a7414f2e572f676f22da7a06c8cd9ee", + "reference": "d1abcf763a7414f2e572f676f22da7a06c8cd9ee", "shasum": "" }, "require": { @@ -7146,7 +8223,7 @@ "psr/log": "^1.1|^2|^3", "symfony/cache-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.2.10" + "symfony/var-exporter": "^6.3.6|^7.0" }, "conflict": { "doctrine/dbal": "<2.13.1", @@ -7161,15 +8238,15 @@ }, "require-dev": { "cache/integration-tests": "dev-master", - "doctrine/dbal": "^2.13.1|^3.0", + "doctrine/dbal": "^2.13.1|^3|^4", "predis/predis": "^1.1|^2.0", "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/filesystem": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/messenger": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -7204,7 +8281,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.3.2" + "source": "https://github.com/symfony/cache/tree/v6.4.21" }, "funding": [ { @@ -7220,20 +8297,20 @@ "type": "tidelift" } ], - "time": "2023-07-27T16:19:14+00:00" + "time": "2025-04-08T08:21:20+00:00" }, { "name": "symfony/cache-contracts", - "version": "v3.3.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "ad945640ccc0ae6e208bcea7d7de4b39b569896b" + "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/ad945640ccc0ae6e208bcea7d7de4b39b569896b", - "reference": "ad945640ccc0ae6e208bcea7d7de4b39b569896b", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", + "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", "shasum": "" }, "require": { @@ -7242,12 +8319,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -7280,7 +8357,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.3.0" + "source": "https://github.com/symfony/cache-contracts/tree/v3.5.1" }, "funding": [ { @@ -7296,25 +8373,26 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/clock", - "version": "v6.3.1", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "2c72817f85cbdd0ae4e49643514a889004934296" + "reference": "b2bf55c4dd115003309eafa87ee7df9ed3dde81b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/2c72817f85cbdd0ae4e49643514a889004934296", - "reference": "2c72817f85cbdd0ae4e49643514a889004934296", + "url": "https://api.github.com/repos/symfony/clock/zipball/b2bf55c4dd115003309eafa87ee7df9ed3dde81b", + "reference": "b2bf55c4dd115003309eafa87ee7df9ed3dde81b", "shasum": "" }, "require": { "php": ">=8.1", - "psr/clock": "^1.0" + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" }, "provide": { "psr/clock-implementation": "1.0" @@ -7353,7 +8431,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v6.3.1" + "source": "https://github.com/symfony/clock/tree/v6.4.13" }, "funding": [ { @@ -7369,26 +8447,26 @@ "type": "tidelift" } ], - "time": "2023-06-08T23:46:55+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/config", - "version": "v6.3.2", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467" + "reference": "4e55e7e4ffddd343671ea972216d4509f46c22ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", - "reference": "b47ca238b03e7b0d7880ffd1cf06e8d637ca1467", + "url": "https://api.github.com/repos/symfony/config/zipball/4e55e7e4ffddd343671ea972216d4509f46c22ef", + "reference": "4e55e7e4ffddd343671ea972216d4509f46c22ef", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { @@ -7396,11 +8474,11 @@ "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/messenger": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0" + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -7428,7 +8506,7 @@ "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/v6.3.2" + "source": "https://github.com/symfony/config/tree/v6.4.14" }, "funding": [ { @@ -7444,20 +8522,20 @@ "type": "tidelift" } ], - "time": "2023-07-19T20:22:16+00:00" + "time": "2024-11-04T11:33:53+00:00" }, { "name": "symfony/console", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898" + "reference": "a3011c7b7adb58d89f6c0d822abb641d7a5f9719" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/aa5d64ad3f63f2e48964fc81ee45cb318a723898", - "reference": "aa5d64ad3f63f2e48964fc81ee45cb318a723898", + "url": "https://api.github.com/repos/symfony/console/zipball/a3011c7b7adb58d89f6c0d822abb641d7a5f9719", + "reference": "a3011c7b7adb58d89f6c0d822abb641d7a5f9719", "shasum": "" }, "require": { @@ -7465,7 +8543,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0" + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { "symfony/dependency-injection": "<5.4", @@ -7479,12 +8557,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/lock": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -7518,7 +8600,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.3.2" + "source": "https://github.com/symfony/console/tree/v6.4.21" }, "funding": [ { @@ -7534,20 +8616,20 @@ "type": "tidelift" } ], - "time": "2023-07-19T20:17:28+00:00" + "time": "2025-04-07T15:42:41+00:00" }, { "name": "symfony/css-selector", - "version": "v6.3.2", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "883d961421ab1709877c10ac99451632a3d6fa57" + "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/883d961421ab1709877c10ac99451632a3d6fa57", - "reference": "883d961421ab1709877c10ac99451632a3d6fa57", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/cb23e97813c5837a041b73a6d63a9ddff0778f5e", + "reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e", "shasum": "" }, "require": { @@ -7583,7 +8665,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.3.2" + "source": "https://github.com/symfony/css-selector/tree/v6.4.13" }, "funding": [ { @@ -7599,20 +8681,20 @@ "type": "tidelift" } ], - "time": "2023-07-12T16:00:22+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.3.2", + "version": "v6.4.20", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "474cfbc46aba85a1ca11a27db684480d0db64ba7" + "reference": "c49796a9184a532843e78e50df9e55708b92543a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/474cfbc46aba85a1ca11a27db684480d0db64ba7", - "reference": "474cfbc46aba85a1ca11a27db684480d0db64ba7", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c49796a9184a532843e78e50df9e55708b92543a", + "reference": "c49796a9184a532843e78e50df9e55708b92543a", "shasum": "" }, "require": { @@ -7620,7 +8702,7 @@ "psr/container": "^1.1|^2.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.2.10" + "symfony/var-exporter": "^6.4.20|^7.2.5" }, "conflict": { "ext-psr": "<1.1|>=2", @@ -7634,9 +8716,9 @@ "symfony/service-implementation": "1.1|2.0|3.0" }, "require-dev": { - "symfony/config": "^6.1", - "symfony/expression-language": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" + "symfony/config": "^6.1|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -7664,7 +8746,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.3.2" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.20" }, "funding": [ { @@ -7680,20 +8762,20 @@ "type": "tidelift" } ], - "time": "2023-07-19T20:17:28+00:00" + "time": "2025-03-13T09:55:08+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.3.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -7701,12 +8783,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -7731,7 +8813,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -7747,25 +8829,25 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/doctrine-bridge", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "61c7d16fbb61ffe3a08d1b965355d6b1006c3594" + "reference": "fcce66ede41ca56100b91fd4a00131ba6cf89aba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/61c7d16fbb61ffe3a08d1b965355d6b1006c3594", - "reference": "61c7d16fbb61ffe3a08d1b965355d6b1006c3594", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/fcce66ede41ca56100b91fd4a00131ba6cf89aba", + "reference": "fcce66ede41ca56100b91fd4a00131ba6cf89aba", "shasum": "" }, "require": { "doctrine/event-manager": "^1.2|^2", - "doctrine/persistence": "^2|^3", + "doctrine/persistence": "^2.5|^3.1|^4", "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "~1.8", @@ -7773,47 +8855,45 @@ "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "doctrine/annotations": "<1.13.1", "doctrine/dbal": "<2.13.1", "doctrine/lexer": "<1.1", - "doctrine/orm": "<2.12", + "doctrine/orm": "<2.15", "symfony/cache": "<5.4", "symfony/dependency-injection": "<6.2", - "symfony/form": "<5.4.21|>=6,<6.2.7", + "symfony/form": "<5.4.38|>=6,<6.4.6|>=7,<7.0.6", "symfony/http-foundation": "<6.3", "symfony/http-kernel": "<6.2", "symfony/lock": "<6.3", "symfony/messenger": "<5.4", "symfony/property-info": "<5.4", "symfony/security-bundle": "<5.4", - "symfony/security-core": "<6.0", - "symfony/validator": "<5.4.25|>=6,<6.2.12|>=6.3,<6.3.1" + "symfony/security-core": "<6.4", + "symfony/validator": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.13.1|^2", "doctrine/collections": "^1.0|^2.0", - "doctrine/data-fixtures": "^1.1", - "doctrine/dbal": "^2.13.1|^3.0", - "doctrine/orm": "^2.12", + "doctrine/data-fixtures": "^1.1|^2", + "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/orm": "^2.15|^3", "psr/log": "^1|^2|^3", - "symfony/cache": "^5.4|^6.0", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^6.2", - "symfony/doctrine-messenger": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/form": "^5.4.21|^6.2.7", - "symfony/http-kernel": "^6.3", - "symfony/lock": "^6.3", - "symfony/messenger": "^5.4|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/property-info": "^5.4|^6.0", - "symfony/proxy-manager-bridge": "^5.4|^6.0", - "symfony/security-core": "^6.0", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", - "symfony/uid": "^5.4|^6.0", - "symfony/validator": "^5.4.25|~6.2.12|^6.3.1", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^6.2|^7.0", + "symfony/doctrine-messenger": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4.38|^6.4.6|^7.0.6", + "symfony/http-kernel": "^6.3|^7.0", + "symfony/lock": "^6.3|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/proxy-manager-bridge": "^6.4", + "symfony/security-core": "^6.4|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "symfony-bridge", "autoload": { @@ -7841,7 +8921,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v6.3.2" + "source": "https://github.com/symfony/doctrine-bridge/tree/v6.4.21" }, "funding": [ { @@ -7857,20 +8937,87 @@ "type": "tidelift" } ], - "time": "2023-07-20T14:51:28+00:00" + "time": "2025-04-27T15:22:02+00:00" }, { - "name": "symfony/dotenv", - "version": "v6.3.0", + "name": "symfony/dom-crawler", + "version": "v6.4.19", "source": { "type": "git", - "url": "https://github.com/symfony/dotenv.git", - "reference": "ceadb434fe2a6763a03d2d110441745834f3dd1e" + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "19073e3e0bb50cbc1cb286077069b3107085206f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/ceadb434fe2a6763a03d2d110441745834f3dd1e", - "reference": "ceadb434fe2a6763a03d2d110441745834f3dd1e", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/19073e3e0bb50cbc1cb286077069b3107085206f", + "reference": "19073e3e0bb50cbc1cb286077069b3107085206f", + "shasum": "" + }, + "require": { + "masterminds/html5": "^2.6", + "php": ">=8.1", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "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 DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v6.4.19" + }, + "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-14T17:58:34+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v6.4.16", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "1ac5e7e7e862d4d574258daf08bd569ba926e4a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/1ac5e7e7e862d4d574258daf08bd569ba926e4a5", + "reference": "1ac5e7e7e862d4d574258daf08bd569ba926e4a5", "shasum": "" }, "require": { @@ -7881,8 +9028,8 @@ "symfony/process": "<5.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0" + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -7915,7 +9062,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.3.0" + "source": "https://github.com/symfony/dotenv/tree/v6.4.16" }, "funding": [ { @@ -7931,34 +9078,35 @@ "type": "tidelift" } ], - "time": "2023-04-21T14:41:17+00:00" + "time": "2024-11-27T11:08:19+00:00" }, { "name": "symfony/error-handler", - "version": "v6.3.2", + "version": "v6.4.20", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "85fd65ed295c4078367c784e8a5a6cee30348b7a" + "reference": "aa3bcf4f7674719df078e61cc8062e5b7f752031" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/85fd65ed295c4078367c784e8a5a6cee30348b7a", - "reference": "85fd65ed295c4078367c784e8a5a6cee30348b7a", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/aa3bcf4f7674719df078e61cc8062e5b7f752031", + "reference": "aa3bcf4f7674719df078e61cc8062e5b7f752031", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "conflict": { - "symfony/deprecation-contracts": "<2.5" + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" }, "require-dev": { "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0" + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^5.4|^6.0|^7.0" }, "bin": [ "Resources/bin/patch-type-declarations" @@ -7989,7 +9137,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.3.2" + "source": "https://github.com/symfony/error-handler/tree/v6.4.20" }, "funding": [ { @@ -8005,20 +9153,20 @@ "type": "tidelift" } ], - "time": "2023-07-16T17:05:46+00:00" + "time": "2025-03-01T13:00:38+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.3.2", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e" + "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/adb01fe097a4ee930db9258a3cc906b5beb5cf2e", - "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", + "reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e", "shasum": "" }, "require": { @@ -8035,13 +9183,13 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/error-handler": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^5.4|^6.0" + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -8069,7 +9217,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.3.2" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.13" }, "funding": [ { @@ -8085,20 +9233,20 @@ "type": "tidelift" } ], - "time": "2023-07-06T06:56:43+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.3.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", - "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", "shasum": "" }, "require": { @@ -8107,12 +9255,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -8145,7 +9293,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.3.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" }, "funding": [ { @@ -8161,25 +9309,25 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/expression-language", - "version": "v6.3.0", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "6d560c4c80e7e328708efd923f93ad67e6a0c1c0" + "reference": "3524904fb026356a5230cd197f9a4e6a61e0e7df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/6d560c4c80e7e328708efd923f93ad67e6a0c1c0", - "reference": "6d560c4c80e7e328708efd923f93ad67e6a0c1c0", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/3524904fb026356a5230cd197f9a4e6a61e0e7df", + "reference": "3524904fb026356a5230cd197f9a4e6a61e0e7df", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/cache": "^5.4|^6.0", + "symfony/cache": "^5.4|^6.0|^7.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3" }, @@ -8209,7 +9357,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v6.3.0" + "source": "https://github.com/symfony/expression-language/tree/v6.4.13" }, "funding": [ { @@ -8225,20 +9373,20 @@ "type": "tidelift" } ], - "time": "2023-04-28T16:05:33+00:00" + "time": "2024-10-09T08:40:40+00:00" }, { "name": "symfony/filesystem", - "version": "v6.3.1", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae" + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", - "reference": "edd36776956f2a6fcf577edb5b05eb0e3bdc52ae", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3", + "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3", "shasum": "" }, "require": { @@ -8246,6 +9394,9 @@ "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, + "require-dev": { + "symfony/process": "^5.4|^6.4|^7.0" + }, "type": "library", "autoload": { "psr-4": { @@ -8272,7 +9423,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.3.1" + "source": "https://github.com/symfony/filesystem/tree/v6.4.13" }, "funding": [ { @@ -8288,27 +9439,27 @@ "type": "tidelift" } ], - "time": "2023-06-01T08:30:39+00:00" + "time": "2024-10-25T15:07:50+00:00" }, { "name": "symfony/finder", - "version": "v6.3.3", + "version": "v6.4.17", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e" + "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9915db259f67d21eefee768c1abcf1cc61b1fc9e", - "reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e", + "url": "https://api.github.com/repos/symfony/finder/zipball/1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", + "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", "shasum": "" }, "require": { "php": ">=8.1" }, "require-dev": { - "symfony/filesystem": "^6.0" + "symfony/filesystem": "^6.0|^7.0" }, "type": "library", "autoload": { @@ -8336,7 +9487,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.3.3" + "source": "https://github.com/symfony/finder/tree/v6.4.17" }, "funding": [ { @@ -8352,26 +9503,29 @@ "type": "tidelift" } ], - "time": "2023-07-31T08:31:44+00:00" + "time": "2024-12-29T13:51:37+00:00" }, { "name": "symfony/flex", - "version": "v2.3.1", + "version": "v2.5.1", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "3c9c3424efdafe33e0e3cfb5e87e50b34711fedf" + "reference": "62d5c38c7af6280d8605b725364680838b475641" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/3c9c3424efdafe33e0e3cfb5e87e50b34711fedf", - "reference": "3c9c3424efdafe33e0e3cfb5e87e50b34711fedf", + "url": "https://api.github.com/repos/symfony/flex/zipball/62d5c38c7af6280d8605b725364680838b475641", + "reference": "62d5c38c7af6280d8605b725364680838b475641", "shasum": "" }, "require": { "composer-plugin-api": "^2.1", "php": ">=8.0" }, + "conflict": { + "composer/semver": "<1.7.2" + }, "require-dev": { "composer/composer": "^2.1", "symfony/dotenv": "^5.4|^6.0", @@ -8401,7 +9555,7 @@ "description": "Composer plugin for Symfony", "support": { "issues": "https://github.com/symfony/flex/issues", - "source": "https://github.com/symfony/flex/tree/v2.3.1" + "source": "https://github.com/symfony/flex/tree/v2.5.1" }, "funding": [ { @@ -8417,31 +9571,31 @@ "type": "tidelift" } ], - "time": "2023-05-27T07:38:25+00:00" + "time": "2025-05-10T14:05:03+00:00" }, { "name": "symfony/form", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "afdadf511e08bc6d4752afb869ce084276aca4e2" + "reference": "44a0e253c16a3187299f07b8f80e23ecb000d360" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/afdadf511e08bc6d4752afb869ce084276aca4e2", - "reference": "afdadf511e08bc6d4752afb869ce084276aca4e2", + "url": "https://api.github.com/repos/symfony/form/zipball/44a0e253c16a3187299f07b8f80e23ecb000d360", + "reference": "44a0e253c16a3187299f07b8f80e23ecb000d360", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/options-resolver": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/options-resolver": "^5.4|^6.0|^7.0", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "^1.21", "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^5.4|^6.0", + "symfony/property-access": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -8451,26 +9605,26 @@ "symfony/error-handler": "<5.4", "symfony/framework-bundle": "<5.4", "symfony/http-kernel": "<5.4", - "symfony/translation": "<5.4", + "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", "symfony/translation-contracts": "<2.5", "symfony/twig-bridge": "<6.3" }, "require-dev": { "doctrine/collections": "^1.0|^2.0", - "symfony/config": "^5.4|^6.0", - "symfony/console": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/html-sanitizer": "^6.1", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/intl": "^5.4|^6.0", - "symfony/security-core": "^6.2", - "symfony/security-csrf": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", - "symfony/uid": "^5.4|^6.0", - "symfony/validator": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/html-sanitizer": "^6.1|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/intl": "^5.4|^6.0|^7.0", + "symfony/security-core": "^6.2|^7.0", + "symfony/security-csrf": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -8498,7 +9652,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v6.3.2" + "source": "https://github.com/symfony/form/tree/v6.4.21" }, "funding": [ { @@ -8514,38 +9668,38 @@ "type": "tidelift" } ], - "time": "2023-07-26T17:39:03+00:00" + "time": "2025-04-27T15:22:02+00:00" }, { "name": "symfony/framework-bundle", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "930fe7ee25a928b9b3627d717873ddd171430a82" + "reference": "d0b06133b00e4dd3df7f47a3188fb7baabcc6b2a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/930fe7ee25a928b9b3627d717873ddd171430a82", - "reference": "930fe7ee25a928b9b3627d717873ddd171430a82", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d0b06133b00e4dd3df7f47a3188fb7baabcc6b2a", + "reference": "d0b06133b00e4dd3df7f47a3188fb7baabcc6b2a", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", "php": ">=8.1", - "symfony/cache": "^5.4|^6.0", - "symfony/config": "^6.1", - "symfony/dependency-injection": "^6.3.1", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^6.1|^7.0", + "symfony/dependency-injection": "^6.4.12|^7.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.1", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/filesystem": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/http-foundation": "^6.3", - "symfony/http-kernel": "^6.3", + "symfony/error-handler": "^6.1|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4", "symfony/polyfill-mbstring": "~1.0", - "symfony/routing": "^5.4|^6.0" + "symfony/routing": "^6.4|^7.0" }, "conflict": { "doctrine/annotations": "<1.13.1", @@ -8553,68 +9707,73 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/asset": "<5.4", + "symfony/asset-mapper": "<6.4", "symfony/clock": "<6.3", - "symfony/console": "<5.4", - "symfony/dom-crawler": "<6.3", + "symfony/console": "<5.4|>=7.0", + "symfony/dom-crawler": "<6.4", "symfony/dotenv": "<5.4", "symfony/form": "<5.4", "symfony/http-client": "<6.3", "symfony/lock": "<5.4", "symfony/mailer": "<5.4", "symfony/messenger": "<6.3", - "symfony/mime": "<6.2", + "symfony/mime": "<6.4", "symfony/property-access": "<5.4", "symfony/property-info": "<5.4", + "symfony/runtime": "<5.4.45|>=6.0,<6.4.13|>=7.0,<7.1.6", + "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", "symfony/security-core": "<5.4", "symfony/security-csrf": "<5.4", - "symfony/serializer": "<6.3", + "symfony/serializer": "<6.4", "symfony/stopwatch": "<5.4", - "symfony/translation": "<6.2.8", + "symfony/translation": "<6.4", "symfony/twig-bridge": "<5.4", "symfony/twig-bundle": "<5.4", - "symfony/validator": "<6.3", - "symfony/web-profiler-bundle": "<5.4", - "symfony/workflow": "<5.4" + "symfony/validator": "<6.4", + "symfony/web-profiler-bundle": "<6.4", + "symfony/workflow": "<6.4" }, "require-dev": { "doctrine/annotations": "^1.13.1|^2", "doctrine/persistence": "^1.3|^2|^3", + "dragonmantank/cron-expression": "^3.1", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/asset": "^5.4|^6.0", - "symfony/asset-mapper": "^6.3", - "symfony/browser-kit": "^5.4|^6.0", - "symfony/clock": "^6.2", - "symfony/console": "^5.4.9|^6.0.9", - "symfony/css-selector": "^5.4|^6.0", - "symfony/dom-crawler": "^6.3", - "symfony/dotenv": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/html-sanitizer": "^6.1", - "symfony/http-client": "^6.3", - "symfony/lock": "^5.4|^6.0", - "symfony/mailer": "^5.4|^6.0", - "symfony/messenger": "^6.3", - "symfony/mime": "^6.2", - "symfony/notifier": "^5.4|^6.0", + "seld/jsonlint": "^1.10", + "symfony/asset": "^5.4|^6.0|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/clock": "^6.2|^7.0", + "symfony/console": "^5.4.9|^6.0.9|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/dotenv": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/html-sanitizer": "^6.1|^7.0", + "symfony/http-client": "^6.3|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/mailer": "^5.4|^6.0|^7.0", + "symfony/messenger": "^6.3|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/notifier": "^5.4|^6.0|^7.0", "symfony/polyfill-intl-icu": "~1.0", - "symfony/process": "^5.4|^6.0", - "symfony/property-info": "^5.4|^6.0", - "symfony/rate-limiter": "^5.4|^6.0", - "symfony/scheduler": "^6.3", - "symfony/security-bundle": "^5.4|^6.0", - "symfony/semaphore": "^5.4|^6.0", - "symfony/serializer": "^6.3", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/string": "^5.4|^6.0", - "symfony/translation": "^6.2.8", - "symfony/twig-bundle": "^5.4|^6.0", - "symfony/uid": "^5.4|^6.0", - "symfony/validator": "^6.3", - "symfony/web-link": "^5.4|^6.0", - "symfony/workflow": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0", - "twig/twig": "^2.10|^3.0" + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0", + "symfony/scheduler": "^6.4.4|^7.0.4", + "symfony/security-bundle": "^5.4|^6.0|^7.0", + "symfony/semaphore": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/string": "^5.4|^6.0|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/web-link": "^5.4|^6.0|^7.0", + "symfony/workflow": "^6.4|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0", + "twig/twig": "^2.10|^3.0.4" }, "type": "symfony-bundle", "autoload": { @@ -8642,7 +9801,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.3.2" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.21" }, "funding": [ { @@ -8658,27 +9817,27 @@ "type": "tidelift" } ], - "time": "2023-07-26T17:39:03+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/http-client", - "version": "v6.3.2", + "version": "v6.4.19", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00" + "reference": "3294a433fc9d12ae58128174896b5b1822c28dad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00", - "reference": "15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00", + "url": "https://api.github.com/repos/symfony/http-client/zipball/3294a433fc9d12ae58128174896b5b1822c28dad", + "reference": "3294a433fc9d12ae58128174896b5b1822c28dad", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "^3", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -8696,14 +9855,15 @@ "amphp/http-client": "^4.2.1", "amphp/http-tunnel": "^1.0", "amphp/socket": "^1.1", - "guzzlehttp/promises": "^1.4", + "guzzlehttp/promises": "^1.4|^2.0", "nyholm/psr7": "^1.0", "php-http/httplug": "^1.0|^2.0", "psr/http-client": "^1.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/stopwatch": "^5.4|^6.0" + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -8734,7 +9894,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.3.2" + "source": "https://github.com/symfony/http-client/tree/v6.4.19" }, "funding": [ { @@ -8750,20 +9910,20 @@ "type": "tidelift" } ], - "time": "2023-07-05T08:41:27+00:00" + "time": "2025-02-13T09:55:13+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v3.3.0", + "version": "v3.5.2", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "3b66325d0176b4ec826bffab57c9037d759c31fb" + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/3b66325d0176b4ec826bffab57c9037d759c31fb", - "reference": "3b66325d0176b4ec826bffab57c9037d759c31fb", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", "shasum": "" }, "require": { @@ -8771,12 +9931,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -8812,7 +9972,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.3.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2" }, "funding": [ { @@ -8828,20 +9988,20 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-12-07T08:49:48+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "43ed99d30f5f466ffa00bdac3f5f7aa9cd7617c3" + "reference": "3f0c7ea41db479383b81d436b836d37168fd5b99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/43ed99d30f5f466ffa00bdac3f5f7aa9cd7617c3", - "reference": "43ed99d30f5f466ffa00bdac3f5f7aa9cd7617c3", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3f0c7ea41db479383b81d436b836d37168fd5b99", + "reference": "3f0c7ea41db479383b81d436b836d37168fd5b99", "shasum": "" }, "require": { @@ -8851,17 +10011,17 @@ "symfony/polyfill-php83": "^1.27" }, "conflict": { - "symfony/cache": "<6.2" + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" }, "require-dev": { - "doctrine/dbal": "^2.13.1|^3.0", + "doctrine/dbal": "^2.13.1|^3|^4", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", - "symfony/mime": "^5.4|^6.0", - "symfony/rate-limiter": "^5.2|^6.0" + "symfony/cache": "^6.4.12|^7.1.5", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -8889,7 +10049,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.3.2" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.21" }, "funding": [ { @@ -8905,29 +10065,29 @@ "type": "tidelift" } ], - "time": "2023-07-23T21:58:39+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.3.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "d3b567f0addf695e10b0c6d57564a9bea2e058ee" + "reference": "983ca05eec6623920d24ec0f1005f487d3734a0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/d3b567f0addf695e10b0c6d57564a9bea2e058ee", - "reference": "d3b567f0addf695e10b0c6d57564a9bea2e058ee", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/983ca05eec6623920d24ec0f1005f487d3734a0c", + "reference": "983ca05eec6623920d24ec0f1005f487d3734a0c", "shasum": "" }, "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.3", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/http-foundation": "^6.2.7", + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { @@ -8935,7 +10095,7 @@ "symfony/cache": "<5.4", "symfony/config": "<6.1", "symfony/console": "<5.4", - "symfony/dependency-injection": "<6.3", + "symfony/dependency-injection": "<6.4", "symfony/doctrine-bridge": "<5.4", "symfony/form": "<5.4", "symfony/http-client": "<5.4", @@ -8945,7 +10105,7 @@ "symfony/translation": "<5.4", "symfony/translation-contracts": "<2.5", "symfony/twig-bridge": "<5.4", - "symfony/validator": "<5.4", + "symfony/validator": "<6.4", "symfony/var-dumper": "<6.3", "twig/twig": "<2.13" }, @@ -8954,26 +10114,27 @@ }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^5.4|^6.0", - "symfony/clock": "^6.2", - "symfony/config": "^6.1", - "symfony/console": "^5.4|^6.0", - "symfony/css-selector": "^5.4|^6.0", - "symfony/dependency-injection": "^6.3", - "symfony/dom-crawler": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/clock": "^6.2|^7.0", + "symfony/config": "^6.1|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^5.4|^6.0", - "symfony/property-access": "^5.4.5|^6.0.5", - "symfony/routing": "^5.4|^6.0", - "symfony/serializer": "^6.3", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4.5|^6.0.5|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4.4|^7.0.4", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^5.4|^6.0", - "symfony/validator": "^6.3", - "symfony/var-exporter": "^6.2", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.4|^7.0", + "symfony/var-exporter": "^6.2|^7.0", "twig/twig": "^2.13|^3.0.4" }, "type": "library", @@ -9002,7 +10163,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.3.3" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.21" }, "funding": [ { @@ -9018,29 +10179,29 @@ "type": "tidelift" } ], - "time": "2023-07-31T10:33:00+00:00" + "time": "2025-05-02T08:46:38+00:00" }, { "name": "symfony/intl", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "1f8cb145c869ed089a8531c51a6a4b31ed0b3c69" + "reference": "b248d227fa10fd6345efd4c1c74efaa1c1de6f76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/1f8cb145c869ed089a8531c51a6a4b31ed0b3c69", - "reference": "1f8cb145c869ed089a8531c51a6a4b31ed0b3c69", + "url": "https://api.github.com/repos/symfony/intl/zipball/b248d227fa10fd6345efd4c1c74efaa1c1de6f76", + "reference": "b248d227fa10fd6345efd4c1c74efaa1c1de6f76", "shasum": "" }, "require": { "php": ">=8.1" }, "require-dev": { - "symfony/filesystem": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -9048,7 +10209,8 @@ "Symfony\\Component\\Intl\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Tests/", + "/Resources/data/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -9084,7 +10246,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v6.3.2" + "source": "https://github.com/symfony/intl/tree/v6.4.21" }, "funding": [ { @@ -9100,20 +10262,20 @@ "type": "tidelift" } ], - "time": "2023-07-20T07:43:09+00:00" + "time": "2025-04-07T19:02:30+00:00" }, { "name": "symfony/mailer", - "version": "v6.3.0", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "7b03d9be1dea29bfec0a6c7b603f5072a4c97435" + "reference": "ada2809ccd4ec27aba9fc344e3efdaec624c6438" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/7b03d9be1dea29bfec0a6c7b603f5072a4c97435", - "reference": "7b03d9be1dea29bfec0a6c7b603f5072a4c97435", + "url": "https://api.github.com/repos/symfony/mailer/zipball/ada2809ccd4ec27aba9fc344e3efdaec624c6438", + "reference": "ada2809ccd4ec27aba9fc344e3efdaec624c6438", "shasum": "" }, "require": { @@ -9121,8 +10283,8 @@ "php": ">=8.1", "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/mime": "^6.2", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/mime": "^6.2|^7.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -9133,10 +10295,10 @@ "symfony/twig-bridge": "<6.2.1" }, "require-dev": { - "symfony/console": "^5.4|^6.0", - "symfony/http-client": "^5.4|^6.0", - "symfony/messenger": "^6.2", - "symfony/twig-bridge": "^6.2" + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/messenger": "^6.2|^7.0", + "symfony/twig-bridge": "^6.2|^7.0" }, "type": "library", "autoload": { @@ -9164,7 +10326,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.3.0" + "source": "https://github.com/symfony/mailer/tree/v6.4.21" }, "funding": [ { @@ -9180,20 +10342,20 @@ "type": "tidelift" } ], - "time": "2023-05-29T12:49:39+00:00" + "time": "2025-04-26T23:47:35+00:00" }, { "name": "symfony/mime", - "version": "v6.3.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "9a0cbd52baa5ba5a5b1f0cacc59466f194730f98" + "reference": "fec8aa5231f3904754955fad33c2db50594d22d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/9a0cbd52baa5ba5a5b1f0cacc59466f194730f98", - "reference": "9a0cbd52baa5ba5a5b1f0cacc59466f194730f98", + "url": "https://api.github.com/repos/symfony/mime/zipball/fec8aa5231f3904754955fad33c2db50594d22d1", + "reference": "fec8aa5231f3904754955fad33c2db50594d22d1", "shasum": "" }, "require": { @@ -9207,16 +10369,17 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/mailer": "<5.4", - "symfony/serializer": "<6.2.13|>=6.3,<6.3.2" + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/property-info": "^5.4|^6.0", - "symfony/serializer": "~6.2.13|^6.3.2" + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.4|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" }, "type": "library", "autoload": { @@ -9248,7 +10411,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.3.3" + "source": "https://github.com/symfony/mime/tree/v6.4.21" }, "funding": [ { @@ -9264,41 +10427,42 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v6.3.1", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "04b04b8e465e0fa84940e5609b6796a8b4e51bf1" + "reference": "9d14621e59f22c2b6d030d92d37ffe5ae1e60452" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/04b04b8e465e0fa84940e5609b6796a8b4e51bf1", - "reference": "04b04b8e465e0fa84940e5609b6796a8b4e51bf1", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/9d14621e59f22c2b6d030d92d37ffe5ae1e60452", + "reference": "9d14621e59f22c2b6d030d92d37ffe5ae1e60452", "shasum": "" }, "require": { "monolog/monolog": "^1.25.1|^2|^3", "php": ">=8.1", - "symfony/http-kernel": "^5.4|^6.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { "symfony/console": "<5.4", "symfony/http-foundation": "<5.4", - "symfony/security-core": "<6.0" + "symfony/security-core": "<5.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0", - "symfony/http-client": "^5.4|^6.0", - "symfony/mailer": "^5.4|^6.0", - "symfony/messenger": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", - "symfony/security-core": "^6.0", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/mailer": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/security-core": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "symfony-bridge", "autoload": { @@ -9326,7 +10490,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v6.3.1" + "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.13" }, "funding": [ { @@ -9342,34 +10506,34 @@ "type": "tidelift" } ], - "time": "2023-06-08T11:13:32+00:00" + "time": "2024-10-14T08:49:08+00:00" }, { "name": "symfony/monolog-bundle", - "version": "v3.8.0", + "version": "v3.10.0", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bundle.git", - "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + "reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", - "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181", + "reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181", "shasum": "" }, "require": { - "monolog/monolog": "^1.22 || ^2.0 || ^3.0", - "php": ">=7.1.3", - "symfony/config": "~4.4 || ^5.0 || ^6.0", - "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", - "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", - "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + "monolog/monolog": "^1.25.1 || ^2.0 || ^3.0", + "php": ">=7.2.5", + "symfony/config": "^5.4 || ^6.0 || ^7.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "symfony/monolog-bridge": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { - "symfony/console": "~4.4 || ^5.0 || ^6.0", - "symfony/phpunit-bridge": "^5.2 || ^6.0", - "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/phpunit-bridge": "^6.3 || ^7.0", + "symfony/yaml": "^5.4 || ^6.0 || ^7.0" }, "type": "symfony-bundle", "extra": { @@ -9407,7 +10571,7 @@ ], "support": { "issues": "https://github.com/symfony/monolog-bundle/issues", - "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" + "source": "https://github.com/symfony/monolog-bundle/tree/v3.10.0" }, "funding": [ { @@ -9423,20 +10587,20 @@ "type": "tidelift" } ], - "time": "2022-05-10T14:24:36+00:00" + "time": "2023-11-06T17:08:13+00:00" }, { "name": "symfony/options-resolver", - "version": "v6.3.0", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd" + "reference": "368128ad168f20e22c32159b9f761e456cec0c78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/a10f19f5198d589d5c33333cffe98dc9820332dd", - "reference": "a10f19f5198d589d5c33333cffe98dc9820332dd", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/368128ad168f20e22c32159b9f761e456cec0c78", + "reference": "368128ad168f20e22c32159b9f761e456cec0c78", "shasum": "" }, "require": { @@ -9474,7 +10638,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.3.0" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.16" }, "funding": [ { @@ -9490,20 +10654,20 @@ "type": "tidelift" } ], - "time": "2023-05-12T14:21:09+00:00" + "time": "2024-11-20T10:57:02+00:00" }, { "name": "symfony/password-hasher", - "version": "v6.3.0", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "d23ad221989e6b8278d050cabfd7b569eee84590" + "reference": "e97a1b31f60b8bdfc1fdedab4398538da9441d47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/d23ad221989e6b8278d050cabfd7b569eee84590", - "reference": "d23ad221989e6b8278d050cabfd7b569eee84590", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/e97a1b31f60b8bdfc1fdedab4398538da9441d47", + "reference": "e97a1b31f60b8bdfc1fdedab4398538da9441d47", "shasum": "" }, "require": { @@ -9513,8 +10677,8 @@ "symfony/security-core": "<5.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0", - "symfony/security-core": "^5.4|^6.0" + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/security-core": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -9546,7 +10710,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.3.0" + "source": "https://github.com/symfony/password-hasher/tree/v6.4.13" }, "funding": [ { @@ -9562,24 +10726,24 @@ "type": "tidelift" } ], - "time": "2023-02-14T09:04:20+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -9589,12 +10753,9 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9628,7 +10789,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -9644,36 +10805,33 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.27.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9709,7 +10867,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -9725,36 +10883,33 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-icu", - "version": "v1.27.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c" + "reference": "763d2a91fea5681509ca01acbc1c5e450d127811" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/a3d9148e2c363588e05abbdd4ee4f971f0a5330c", - "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/763d2a91fea5681509ca01acbc1c5e450d127811", + "reference": "763d2a91fea5681509ca01acbc1c5e450d127811", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance and support of other locales than \"en\"" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9796,7 +10951,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.32.0" }, "funding": [ { @@ -9812,38 +10967,34 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-12-21T18:38:29+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.27.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da" + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", - "reference": "639084e360537a19f9ee352433b84ce831f3d2da", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-intl-normalizer": "^1.10", - "symfony/polyfill-php72": "^1.10" + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9883,7 +11034,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" }, "funding": [ { @@ -9899,36 +11050,33 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-09-10T14:38:51+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.27.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -9967,7 +11115,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -9983,24 +11131,25 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-iconv": "*", + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -10010,12 +11159,9 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -10050,7 +11196,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -10066,33 +11212,30 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { - "name": "symfony/polyfill-php72", - "version": "v1.27.0", + "name": "symfony/polyfill-php82", + "version": "v1.32.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" + "url": "https://github.com/symfony/polyfill-php82.git", + "reference": "5d2ed36f7734637dacc025f179698031951b1692" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", - "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", + "url": "https://api.github.com/repos/symfony/polyfill-php82/zipball/5d2ed36f7734637dacc025f179698031951b1692", + "reference": "5d2ed36f7734637dacc025f179698031951b1692", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -10100,83 +11243,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" - } - }, - "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.2+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.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": "2022-11-03T14:55:06+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Polyfill\\Php82\\": "" }, "classmap": [ "Resources/stubs" @@ -10187,10 +11254,6 @@ "MIT" ], "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -10200,7 +11263,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.2+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -10209,7 +11272,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php82/tree/v1.32.0" }, "funding": [ { @@ -10225,34 +11288,30 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.27.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "508c652ba3ccf69f8c97f251534f229791b52a57" + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/508c652ba3ccf69f8c97f251534f229791b52a57", - "reference": "508c652ba3ccf69f8c97f251534f229791b52a57", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-php80": "^1.14" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -10261,7 +11320,10 @@ ], "psr-4": { "Symfony\\Polyfill\\Php83\\": "" - } + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -10286,7 +11348,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" }, "funding": [ { @@ -10302,24 +11364,100 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/polyfill-uuid", - "version": "v1.27.0", + "name": "symfony/polyfill-php84", + "version": "v1.32.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-uuid.git", - "reference": "f3cf1a645c2734236ed1e2e671e273eeb3586166" + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "000df7860439609837bbe28670b0be15783b7fbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/f3cf1a645c2734236ed1e2e671e273eeb3586166", - "reference": "f3cf1a645c2734236ed1e2e671e273eeb3586166", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/000df7860439609837bbe28670b0be15783b7fbf", + "reference": "000df7860439609837bbe28670b0be15783b7fbf", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php84\\": "" + }, + "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.4+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php84/tree/v1.32.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": "2025-02-20T12:04:08+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" }, "provide": { "ext-uuid": "*" @@ -10329,12 +11467,9 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -10368,7 +11503,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" }, "funding": [ { @@ -10384,20 +11519,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/process", - "version": "v6.3.2", + "version": "v6.4.20", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "c5ce962db0d9b6e80247ca5eb9af6472bd4d7b5d" + "reference": "e2a61c16af36c9a07e5c9906498b73e091949a20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/c5ce962db0d9b6e80247ca5eb9af6472bd4d7b5d", - "reference": "c5ce962db0d9b6e80247ca5eb9af6472bd4d7b5d", + "url": "https://api.github.com/repos/symfony/process/zipball/e2a61c16af36c9a07e5c9906498b73e091949a20", + "reference": "e2a61c16af36c9a07e5c9906498b73e091949a20", "shasum": "" }, "require": { @@ -10429,7 +11564,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.3.2" + "source": "https://github.com/symfony/process/tree/v6.4.20" }, "funding": [ { @@ -10445,29 +11580,29 @@ "type": "tidelift" } ], - "time": "2023-07-12T16:00:22+00:00" + "time": "2025-03-10T17:11:00+00:00" }, { "name": "symfony/property-access", - "version": "v6.3.2", + "version": "v6.4.18", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "2dc4f9da444b8f8ff592e95d570caad67924f1d0" + "reference": "80e0378f2f058b60d87dedc3c760caec882e992c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/2dc4f9da444b8f8ff592e95d570caad67924f1d0", - "reference": "2dc4f9da444b8f8ff592e95d570caad67924f1d0", + "url": "https://api.github.com/repos/symfony/property-access/zipball/80e0378f2f058b60d87dedc3c760caec882e992c", + "reference": "80e0378f2f058b60d87dedc3c760caec882e992c", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/property-info": "^5.4|^6.0" + "symfony/property-info": "^5.4|^6.0|^7.0" }, "require-dev": { - "symfony/cache": "^5.4|^6.0" + "symfony/cache": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -10506,7 +11641,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.3.2" + "source": "https://github.com/symfony/property-access/tree/v6.4.18" }, "funding": [ { @@ -10522,38 +11657,41 @@ "type": "tidelift" } ], - "time": "2023-07-13T15:26:11+00:00" + "time": "2024-12-16T14:42:05+00:00" }, { "name": "symfony/property-info", - "version": "v6.3.0", + "version": "v6.4.18", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "7f3a03716112269741fe2a809f8f791a371d1fcd" + "reference": "94d18e5cc11a37fd92856d38b61d9cdf72536a1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/7f3a03716112269741fe2a809f8f791a371d1fcd", - "reference": "7f3a03716112269741fe2a809f8f791a371d1fcd", + "url": "https://api.github.com/repos/symfony/property-info/zipball/94d18e5cc11a37fd92856d38b61d9cdf72536a1e", + "reference": "94d18e5cc11a37fd92856d38b61d9cdf72536a1e", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/string": "^5.4|^6.0" + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { + "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<5.2", "phpdocumentor/type-resolver": "<1.5.1", - "symfony/dependency-injection": "<5.4" + "symfony/cache": "<5.4", + "symfony/dependency-injection": "<5.4|>=6.0,<6.4", + "symfony/serializer": "<5.4" }, "require-dev": { - "doctrine/annotations": "^1.10.4|^2", + "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^5.2", - "phpstan/phpdoc-parser": "^1.0", - "symfony/cache": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0" + "phpstan/phpdoc-parser": "^1.0|^2.0", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/serializer": "^5.4|^6.4|^7.0" }, "type": "library", "autoload": { @@ -10589,7 +11727,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.3.0" + "source": "https://github.com/symfony/property-info/tree/v6.4.18" }, "funding": [ { @@ -10605,114 +11743,42 @@ "type": "tidelift" } ], - "time": "2023-05-19T08:06:44+00:00" - }, - { - "name": "symfony/proxy-manager-bridge", - "version": "v6.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/proxy-manager-bridge.git", - "reference": "7ba2ac62c88d7c3460d41f04ceba5fc3b9071a39" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/proxy-manager-bridge/zipball/7ba2ac62c88d7c3460d41f04ceba5fc3b9071a39", - "reference": "7ba2ac62c88d7c3460d41f04ceba5fc3b9071a39", - "shasum": "" - }, - "require": { - "friendsofphp/proxy-manager-lts": "^1.0.2", - "php": ">=8.1", - "symfony/dependency-injection": "^6.3", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "require-dev": { - "symfony/config": "^6.1" - }, - "type": "symfony-bridge", - "autoload": { - "psr-4": { - "Symfony\\Bridge\\ProxyManager\\": "" - }, - "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 integration for ProxyManager with various Symfony components", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/proxy-manager-bridge/tree/v6.3.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": "2023-05-26T07:49:33+00:00" + "time": "2025-01-21T10:52:27+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v2.3.1", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "581ca6067eb62640de5ff08ee1ba6850a0ee472e" + "reference": "c9cf83326a1074f83a738fc5320945abf7fb7fec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/581ca6067eb62640de5ff08ee1ba6850a0ee472e", - "reference": "581ca6067eb62640de5ff08ee1ba6850a0ee472e", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/c9cf83326a1074f83a738fc5320945abf7fb7fec", + "reference": "c9cf83326a1074f83a738fc5320945abf7fb7fec", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/http-message": "^1.0 || ^2.0", - "symfony/deprecation-contracts": "^2.5 || ^3.0", - "symfony/http-foundation": "^5.4 || ^6.0" + "php": ">=8.1", + "psr/http-message": "^1.0|^2.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0" + }, + "conflict": { + "php-http/discovery": "<1.15", + "symfony/http-kernel": "<6.2" }, "require-dev": { "nyholm/psr7": "^1.1", - "psr/log": "^1.1 || ^2 || ^3", - "symfony/browser-kit": "^5.4 || ^6.0", - "symfony/config": "^5.4 || ^6.0", - "symfony/event-dispatcher": "^5.4 || ^6.0", - "symfony/framework-bundle": "^5.4 || ^6.0", - "symfony/http-kernel": "^5.4 || ^6.0", - "symfony/phpunit-bridge": "^6.2" - }, - "suggest": { - "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" + "php-http/discovery": "^1.15", + "psr/log": "^1.1.4|^2|^3", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^6.2|^7.0", + "symfony/http-kernel": "^6.2|^7.0" }, "type": "symfony-bridge", - "extra": { - "branch-alias": { - "dev-main": "2.3-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Bridge\\PsrHttpMessage\\": "" @@ -10732,11 +11798,11 @@ }, { "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "homepage": "https://symfony.com/contributors" } ], "description": "PSR HTTP message bridge", - "homepage": "http://symfony.com", + "homepage": "https://symfony.com", "keywords": [ "http", "http-message", @@ -10744,8 +11810,7 @@ "psr-7" ], "support": { - "issues": "https://github.com/symfony/psr-http-message-bridge/issues", - "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.3.1" + "source": "https://github.com/symfony/psr-http-message-bridge/tree/v6.4.13" }, "funding": [ { @@ -10761,29 +11826,30 @@ "type": "tidelift" } ], - "time": "2023-07-26T11:53:26+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/rate-limiter", - "version": "v6.3.2", + "version": "v6.4.15", "source": { "type": "git", "url": "https://github.com/symfony/rate-limiter.git", - "reference": "5223387e4017f26c8c61c46d8e39c11fe4d504b7" + "reference": "e250d82fc17b277b97cbce94efef5414aff29bf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/rate-limiter/zipball/5223387e4017f26c8c61c46d8e39c11fe4d504b7", - "reference": "5223387e4017f26c8c61c46d8e39c11fe4d504b7", + "url": "https://api.github.com/repos/symfony/rate-limiter/zipball/e250d82fc17b277b97cbce94efef5414aff29bf9", + "reference": "e250d82fc17b277b97cbce94efef5414aff29bf9", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/options-resolver": "^5.4|^6.0" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/options-resolver": "^5.4|^6.0|^7.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/lock": "^5.4|^6.0" + "symfony/lock": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -10815,7 +11881,7 @@ "rate-limiter" ], "support": { - "source": "https://github.com/symfony/rate-limiter/tree/v6.3.2" + "source": "https://github.com/symfony/rate-limiter/tree/v6.4.15" }, "funding": [ { @@ -10831,20 +11897,20 @@ "type": "tidelift" } ], - "time": "2023-07-13T14:29:38+00:00" + "time": "2024-11-09T07:19:24+00:00" }, { "name": "symfony/routing", - "version": "v6.3.3", + "version": "v6.4.18", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "e7243039ab663822ff134fbc46099b5fdfa16f6a" + "reference": "e9bfc94953019089acdfb9be51c1b9142c4afa68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e7243039ab663822ff134fbc46099b5fdfa16f6a", - "reference": "e7243039ab663822ff134fbc46099b5fdfa16f6a", + "url": "https://api.github.com/repos/symfony/routing/zipball/e9bfc94953019089acdfb9be51c1b9142c4afa68", + "reference": "e9bfc94953019089acdfb9be51c1b9142c4afa68", "shasum": "" }, "require": { @@ -10860,11 +11926,11 @@ "require-dev": { "doctrine/annotations": "^1.12|^2", "psr/log": "^1|^2|^3", - "symfony/config": "^6.2", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" + "symfony/config": "^6.2|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -10898,7 +11964,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.3.3" + "source": "https://github.com/symfony/routing/tree/v6.4.18" }, "funding": [ { @@ -10914,20 +11980,20 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2025-01-09T08:51:02+00:00" }, { "name": "symfony/runtime", - "version": "v6.3.2", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "d5c09493647a0c1a16e6c8da308098e840d1164f" + "reference": "4facd4174f45cd37c65860403412b67c7381136a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/d5c09493647a0c1a16e6c8da308098e840d1164f", - "reference": "d5c09493647a0c1a16e6c8da308098e840d1164f", + "url": "https://api.github.com/repos/symfony/runtime/zipball/4facd4174f45cd37c65860403412b67c7381136a", + "reference": "4facd4174f45cd37c65860403412b67c7381136a", "shasum": "" }, "require": { @@ -10939,10 +12005,10 @@ }, "require-dev": { "composer/composer": "^1.0.2|^2.0", - "symfony/console": "^5.4.9|^6.0.9", - "symfony/dotenv": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0" + "symfony/console": "^5.4.9|^6.0.9|^7.0", + "symfony/dotenv": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0" }, "type": "composer-plugin", "extra": { @@ -10977,7 +12043,7 @@ "runtime" ], "support": { - "source": "https://github.com/symfony/runtime/tree/v6.3.2" + "source": "https://github.com/symfony/runtime/tree/v6.4.14" }, "funding": [ { @@ -10993,66 +12059,68 @@ "type": "tidelift" } ], - "time": "2023-07-16T17:05:46+00:00" + "time": "2024-11-05T16:39:55+00:00" }, { "name": "symfony/security-bundle", - "version": "v6.3.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "b33382ca3034ee691dd0d882f214ae9e037f4427" + "reference": "99b656ff6046ef217d4e3f852940de7e22489849" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/b33382ca3034ee691dd0d882f214ae9e037f4427", - "reference": "b33382ca3034ee691dd0d882f214ae9e037f4427", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/99b656ff6046ef217d4e3f852940de7e22489849", + "reference": "99b656ff6046ef217d4e3f852940de7e22489849", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", "php": ">=8.1", - "symfony/clock": "^6.3", - "symfony/config": "^6.1", - "symfony/dependency-injection": "^6.2", + "symfony/clock": "^6.3|^7.0", + "symfony/config": "^6.1|^7.0", + "symfony/dependency-injection": "^6.4.11|^7.1.4", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/http-foundation": "^6.2", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.2|^7.0", "symfony/http-kernel": "^6.2", - "symfony/password-hasher": "^5.4|^6.0", - "symfony/security-core": "^6.2", - "symfony/security-csrf": "^5.4|^6.0", - "symfony/security-http": "^6.3" + "symfony/password-hasher": "^5.4|^6.0|^7.0", + "symfony/security-core": "^6.2|^7.0", + "symfony/security-csrf": "^5.4|^6.0|^7.0", + "symfony/security-http": "^6.3.6|^7.0", + "symfony/service-contracts": "^2.5|^3" }, "conflict": { "symfony/browser-kit": "<5.4", "symfony/console": "<5.4", - "symfony/framework-bundle": "<6.3", + "symfony/framework-bundle": "<6.4", "symfony/http-client": "<5.4", "symfony/ldap": "<5.4", - "symfony/twig-bundle": "<5.4" + "symfony/serializer": "<6.4", + "symfony/twig-bundle": "<5.4", + "symfony/validator": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.10.4|^2", - "symfony/asset": "^5.4|^6.0", - "symfony/browser-kit": "^5.4|^6.0", - "symfony/console": "^5.4|^6.0", - "symfony/css-selector": "^5.4|^6.0", - "symfony/dom-crawler": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/framework-bundle": "^6.3", - "symfony/http-client": "^5.4|^6.0", - "symfony/ldap": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/rate-limiter": "^5.4|^6.0", - "symfony/serializer": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", - "symfony/twig-bridge": "^5.4|^6.0", - "symfony/twig-bundle": "^5.4|^6.0", - "symfony/validator": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0", + "symfony/asset": "^5.4|^6.0|^7.0", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/ldap": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0", + "symfony/twig-bridge": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0", "twig/twig": "^2.13|^3.0.4", "web-token/jwt-checker": "^3.1", "web-token/jwt-signature-algorithm-ecdsa": "^3.1", @@ -11087,7 +12155,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v6.3.3" + "source": "https://github.com/symfony/security-bundle/tree/v6.4.21" }, "funding": [ { @@ -11103,27 +12171,27 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/security-core", - "version": "v6.3.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "b86ce012cc9a62a15ed43af5037eebc3e6de4d7f" + "reference": "c6e70da38436a9a49ed39d9cbead1ecf760f0fbd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/b86ce012cc9a62a15ed43af5037eebc3e6de4d7f", - "reference": "b86ce012cc9a62a15ed43af5037eebc3e6de4d7f", + "url": "https://api.github.com/repos/symfony/security-core/zipball/c6e70da38436a9a49ed39d9cbead1ecf760f0fbd", + "reference": "c6e70da38436a9a49ed39d9cbead1ecf760f0fbd", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", "symfony/event-dispatcher-contracts": "^2.5|^3", - "symfony/password-hasher": "^5.4|^6.0", + "symfony/password-hasher": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -11131,20 +12199,21 @@ "symfony/http-foundation": "<5.4", "symfony/ldap": "<5.4", "symfony/security-guard": "<5.4", + "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", "symfony/validator": "<5.4" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", "psr/container": "^1.1|^2.0", "psr/log": "^1|^2|^3", - "symfony/cache": "^5.4|^6.0", - "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/ldap": "^5.4|^6.0", - "symfony/string": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", - "symfony/validator": "^5.4|^6.0" + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/ldap": "^5.4|^6.0|^7.0", + "symfony/string": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", + "symfony/validator": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -11172,7 +12241,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.3.3" + "source": "https://github.com/symfony/security-core/tree/v6.4.21" }, "funding": [ { @@ -11188,31 +12257,31 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2025-04-17T07:43:34+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.3.2", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "63d7b098c448cbddb46ea5eda33b68c1ece6eb5b" + "reference": "c34421b7d34efbaef5d611ab2e646a0ec464ffe3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/63d7b098c448cbddb46ea5eda33b68c1ece6eb5b", - "reference": "63d7b098c448cbddb46ea5eda33b68c1ece6eb5b", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/c34421b7d34efbaef5d611ab2e646a0ec464ffe3", + "reference": "c34421b7d34efbaef5d611ab2e646a0ec464ffe3", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/security-core": "^5.4|^6.0" + "symfony/security-core": "^5.4|^6.0|^7.0" }, "conflict": { "symfony/http-foundation": "<5.4" }, "require-dev": { - "symfony/http-foundation": "^5.4|^6.0" + "symfony/http-foundation": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -11240,7 +12309,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.3.2" + "source": "https://github.com/symfony/security-csrf/tree/v6.4.13" }, "funding": [ { @@ -11256,30 +12325,31 @@ "type": "tidelift" } ], - "time": "2023-07-05T08:41:27+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/security-http", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "04d6b868786a56c1fadc52b003fe5a4f9ab3f3d0" + "reference": "67d0edaf6702c3192f27ad483df9a875c9a1f1a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/04d6b868786a56c1fadc52b003fe5a4f9ab3f3d0", - "reference": "04d6b868786a56c1fadc52b003fe5a4f9ab3f3d0", + "url": "https://api.github.com/repos/symfony/security-http/zipball/67d0edaf6702c3192f27ad483df9a875c9a1f1a2", + "reference": "67d0edaf6702c3192f27ad483df9a875c9a1f1a2", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^6.3", + "symfony/http-foundation": "^6.2|^7.0", + "symfony/http-kernel": "^6.3|^7.0", "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/security-core": "^6.3" + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3" }, "conflict": { "symfony/clock": "<6.3", @@ -11290,14 +12360,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/cache": "^5.4|^6.0", - "symfony/clock": "^6.3", - "symfony/expression-language": "^5.4|^6.0", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/clock": "^6.3|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", "symfony/http-client-contracts": "^3.0", - "symfony/rate-limiter": "^5.4|^6.0", - "symfony/routing": "^5.4|^6.0", - "symfony/security-csrf": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/security-csrf": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0", "web-token/jwt-checker": "^3.1", "web-token/jwt-signature-algorithm-ecdsa": "^3.1" }, @@ -11327,7 +12397,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v6.3.2" + "source": "https://github.com/symfony/security-http/tree/v6.4.21" }, "funding": [ { @@ -11343,20 +12413,20 @@ "type": "tidelift" } ], - "time": "2023-07-13T14:29:38+00:00" + "time": "2025-04-27T13:58:34+00:00" }, { "name": "symfony/serializer", - "version": "v6.3.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "33deb86d212893042d7758d452aa39d19ca0efe3" + "reference": "c45f8f7763afb11e85772c0c1debb8f272c17f51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/33deb86d212893042d7758d452aa39d19ca0efe3", - "reference": "33deb86d212893042d7758d452aa39d19ca0efe3", + "url": "https://api.github.com/repos/symfony/serializer/zipball/c45f8f7763afb11e85772c0c1debb8f272c17f51", + "reference": "c45f8f7763afb11e85772c0c1debb8f272c17f51", "shasum": "" }, "require": { @@ -11372,28 +12442,32 @@ "symfony/property-access": "<5.4", "symfony/property-info": "<5.4.24|>=6,<6.2.11", "symfony/uid": "<5.4", + "symfony/validator": "<6.4", "symfony/yaml": "<5.4" }, "require-dev": { "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", - "symfony/cache": "^5.4|^6.0", - "symfony/config": "^5.4|^6.0", - "symfony/console": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/error-handler": "^5.4|^6.0", - "symfony/filesystem": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/property-info": "^5.4.24|^6.2.11", - "symfony/uid": "^5.4|^6.0", - "symfony/validator": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0", - "symfony/var-exporter": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" + "seld/jsonlint": "^1.10", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4.26|^6.3|^7.0", + "symfony/property-info": "^5.4.24|^6.2.11|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -11421,7 +12495,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v6.3.3" + "source": "https://github.com/symfony/serializer/tree/v6.4.21" }, "funding": [ { @@ -11437,37 +12511,38 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.3.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", - "reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -11503,7 +12578,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.3.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" }, "funding": [ { @@ -11519,35 +12594,36 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/stimulus-bundle", - "version": "v2.10.0", + "version": "v2.24.0", "source": { "type": "git", "url": "https://github.com/symfony/stimulus-bundle.git", - "reference": "257ef052bebe491d7c29e9a4a8009edb82269e15" + "reference": "e09840304467cda3324cc116c7f4ee23c8ff227c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/257ef052bebe491d7c29e9a4a8009edb82269e15", - "reference": "257ef052bebe491d7c29e9a4a8009edb82269e15", + "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/e09840304467cda3324cc116c7f4ee23c8ff227c", + "reference": "e09840304467cda3324cc116c7f4ee23c8ff227c", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/config": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "twig/twig": "^2.15.3|^3.4.3" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.0|^3.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "twig/twig": "^2.15.3|^3.8" }, "require-dev": { - "symfony/asset-mapper": "6.3.x-dev", - "symfony/framework-bundle": "^5.4|^6.0", - "symfony/phpunit-bridge": "^5.4|^6.0", - "symfony/twig-bundle": "^5.4|^6.0", + "symfony/asset-mapper": "^6.3|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^5.4|^6.0|^7.0", "zenstruck/browser": "^1.4" }, "type": "symfony-bundle", @@ -11571,7 +12647,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/stimulus-bundle/tree/v2.10.0" + "source": "https://github.com/symfony/stimulus-bundle/tree/v2.24.0" }, "funding": [ { @@ -11587,20 +12663,20 @@ "type": "tidelift" } ], - "time": "2023-06-29T19:46:37+00:00" + "time": "2025-03-09T21:10:04+00:00" }, { "name": "symfony/stopwatch", - "version": "v6.3.0", + "version": "v6.4.19", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2" + "reference": "dfe1481c12c06266d0c3d58c0cb4b09bd497ab9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", - "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/dfe1481c12c06266d0c3d58c0cb4b09bd497ab9c", + "reference": "dfe1481c12c06266d0c3d58c0cb4b09bd497ab9c", "shasum": "" }, "require": { @@ -11633,7 +12709,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.3.0" + "source": "https://github.com/symfony/stopwatch/tree/v6.4.19" }, "funding": [ { @@ -11649,20 +12725,20 @@ "type": "tidelift" } ], - "time": "2023-02-16T10:14:28+00:00" + "time": "2025-02-21T10:06:30+00:00" }, { "name": "symfony/string", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "53d1a83225002635bca3482fcbf963001313fb68" + "reference": "73e2c6966a5aef1d4892873ed5322245295370c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68", - "reference": "53d1a83225002635bca3482fcbf963001313fb68", + "url": "https://api.github.com/repos/symfony/string/zipball/73e2c6966a5aef1d4892873ed5322245295370c6", + "reference": "73e2c6966a5aef1d4892873ed5322245295370c6", "shasum": "" }, "require": { @@ -11676,11 +12752,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0", - "symfony/http-client": "^5.4|^6.0", - "symfony/intl": "^6.2", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/intl": "^6.2|^7.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0" + "symfony/var-exporter": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -11719,7 +12795,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.3.2" + "source": "https://github.com/symfony/string/tree/v6.4.21" }, "funding": [ { @@ -11735,20 +12811,20 @@ "type": "tidelift" } ], - "time": "2023-07-05T08:41:27+00:00" + "time": "2025-04-18T15:23:29+00:00" }, { "name": "symfony/translation", - "version": "v6.3.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd" + "reference": "bb92ea5588396b319ba43283a5a3087a034cb29c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd", - "reference": "3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd", + "url": "https://api.github.com/repos/symfony/translation/zipball/bb92ea5588396b319ba43283a5a3087a034cb29c", + "reference": "bb92ea5588396b319ba43283a5a3087a034cb29c", "shasum": "" }, "require": { @@ -11771,19 +12847,19 @@ "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { - "nikic/php-parser": "^4.13", + "nikic/php-parser": "^4.18|^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0", - "symfony/console": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/intl": "^5.4|^6.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/intl": "^5.4|^6.0|^7.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^5.4|^6.0", + "symfony/routing": "^5.4|^6.0|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0" + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -11814,7 +12890,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.3.3" + "source": "https://github.com/symfony/translation/tree/v6.4.21" }, "funding": [ { @@ -11830,20 +12906,20 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2025-04-07T19:02:30+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.3.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86" + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/02c24deb352fb0d79db5486c0c79905a85e37e86", - "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", "shasum": "" }, "require": { @@ -11851,12 +12927,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -11892,7 +12968,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.3.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" }, "funding": [ { @@ -11908,24 +12984,25 @@ "type": "tidelift" } ], - "time": "2023-05-30T17:17:10+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/twig-bridge", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "6f8435db76a2d79917489a19a82679276c1b4e32" + "reference": "0457b7944bf1cc9c846c98d4923b5379ec6afc09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/6f8435db76a2d79917489a19a82679276c1b4e32", - "reference": "6f8435db76a2d79917489a19a82679276c1b4e32", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/0457b7944bf1cc9c846c98d4923b5379ec6afc09", + "reference": "0457b7944bf1cc9c846c98d4923b5379ec6afc09", "shasum": "" }, "require": { "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/translation-contracts": "^2.5|^3", "twig/twig": "^2.13|^3.0.4" }, @@ -11935,41 +13012,41 @@ "symfony/console": "<5.4", "symfony/form": "<6.3", "symfony/http-foundation": "<5.4", - "symfony/http-kernel": "<6.2", + "symfony/http-kernel": "<6.4", "symfony/mime": "<6.2", + "symfony/serializer": "<6.4", "symfony/translation": "<5.4", "symfony/workflow": "<5.4" }, "require-dev": { - "doctrine/annotations": "^1.12|^2", "egulias/email-validator": "^2.1.10|^3|^4", "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/asset": "^5.4|^6.0", - "symfony/asset-mapper": "^6.3", - "symfony/console": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/form": "^6.3", - "symfony/html-sanitizer": "^6.1", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^6.2", - "symfony/intl": "^5.4|^6.0", - "symfony/mime": "^6.2", + "symfony/asset": "^5.4|^6.0|^7.0", + "symfony/asset-mapper": "^6.3|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/form": "^6.4.20|^7.2.5", + "symfony/html-sanitizer": "^6.1|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^5.4|^6.0|^7.0", + "symfony/mime": "^6.2|^7.0", "symfony/polyfill-intl-icu": "~1.0", - "symfony/property-info": "^5.4|^6.0", - "symfony/routing": "^5.4|^6.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0", "symfony/security-acl": "^2.8|^3.0", - "symfony/security-core": "^5.4|^6.0", - "symfony/security-csrf": "^5.4|^6.0", - "symfony/security-http": "^5.4|^6.0", - "symfony/serializer": "^6.2", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/translation": "^6.1", - "symfony/web-link": "^5.4|^6.0", - "symfony/workflow": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0", + "symfony/security-core": "^5.4|^6.0|^7.0", + "symfony/security-csrf": "^5.4|^6.0|^7.0", + "symfony/security-http": "^5.4|^6.0|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/translation": "^6.1|^7.0", + "symfony/web-link": "^5.4|^6.0|^7.0", + "symfony/workflow": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0", "twig/cssinliner-extra": "^2.12|^3", "twig/inky-extra": "^2.12|^3", "twig/markdown-extra": "^2.12|^3" @@ -12000,7 +13077,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.3.2" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.21" }, "funding": [ { @@ -12016,30 +13093,30 @@ "type": "tidelift" } ], - "time": "2023-07-20T16:42:33+00:00" + "time": "2025-04-27T13:27:38+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.3.0", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea" + "reference": "c3beeb5336aba1ea03c37e526968c2fde3ef25c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea", - "reference": "d0cd4d1675c0582d27c2e8bb0dc27c0303d8e3ea", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/c3beeb5336aba1ea03c37e526968c2fde3ef25c4", + "reference": "c3beeb5336aba1ea03c37e526968c2fde3ef25c4", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "php": ">=8.1", - "symfony/config": "^6.1", - "symfony/dependency-injection": "^6.1", - "symfony/http-foundation": "^5.4|^6.0", + "symfony/config": "^6.1|^7.0", + "symfony/dependency-injection": "^6.1|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/http-kernel": "^6.2", - "symfony/twig-bridge": "^6.3", + "symfony/twig-bridge": "^6.4", "twig/twig": "^2.13|^3.0.4" }, "conflict": { @@ -12047,17 +13124,16 @@ "symfony/translation": "<5.4" }, "require-dev": { - "doctrine/annotations": "^1.10.4|^2", - "symfony/asset": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/framework-bundle": "^5.4|^6.0", - "symfony/routing": "^5.4|^6.0", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", - "symfony/web-link": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" + "symfony/asset": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0", + "symfony/web-link": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "symfony-bundle", "autoload": { @@ -12085,7 +13161,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.3.0" + "source": "https://github.com/symfony/twig-bundle/tree/v6.4.13" }, "funding": [ { @@ -12101,20 +13177,20 @@ "type": "tidelift" } ], - "time": "2023-05-06T09:53:41+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/uid", - "version": "v6.3.0", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "01b0f20b1351d997711c56f1638f7a8c3061e384" + "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/01b0f20b1351d997711c56f1638f7a8c3061e384", - "reference": "01b0f20b1351d997711c56f1638f7a8c3061e384", + "url": "https://api.github.com/repos/symfony/uid/zipball/18eb207f0436a993fffbdd811b5b8fa35fa5e007", + "reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007", "shasum": "" }, "require": { @@ -12122,7 +13198,7 @@ "symfony/polyfill-uuid": "^1.15" }, "require-dev": { - "symfony/console": "^5.4|^6.0" + "symfony/console": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -12159,7 +13235,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v6.3.0" + "source": "https://github.com/symfony/uid/tree/v6.4.13" }, "funding": [ { @@ -12175,39 +13251,39 @@ "type": "tidelift" } ], - "time": "2023-04-08T07:25:02+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/ux-translator", - "version": "v2.10.0", + "version": "v2.24.0", "source": { "type": "git", "url": "https://github.com/symfony/ux-translator.git", - "reference": "9f49e121558d7c1fab134031b878dfc884775da0" + "reference": "a829b5c83ed676a8e848dce90dd6d42f12e90be6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-translator/zipball/9f49e121558d7c1fab134031b878dfc884775da0", - "reference": "9f49e121558d7c1fab134031b878dfc884775da0", + "url": "https://api.github.com/repos/symfony/ux-translator/zipball/a829b5c83ed676a8e848dce90dd6d42f12e90be6", + "reference": "a829b5c83ed676a8e848dce90dd6d42f12e90be6", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/console": "^5.4|^6.0", - "symfony/filesystem": "^5.4|^6.0", - "symfony/string": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0" + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/string": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4|^6.0|^7.0" }, "require-dev": { - "symfony/framework-bundle": "^5.4|^6.0", - "symfony/phpunit-bridge": "^5.2|^6.0", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^5.2|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "symfony-bundle", "extra": { "thanks": { - "name": "symfony/ux", - "url": "https://github.com/symfony/ux" + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" } }, "autoload": { @@ -12235,7 +13311,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/ux-translator/tree/v2.10.0" + "source": "https://github.com/symfony/ux-translator/tree/v2.24.0" }, "funding": [ { @@ -12251,20 +13327,20 @@ "type": "tidelift" } ], - "time": "2023-06-19T18:55:23+00:00" + "time": "2025-03-09T21:10:04+00:00" }, { "name": "symfony/ux-turbo", - "version": "v2.10.0", + "version": "v2.24.0", "source": { "type": "git", "url": "https://github.com/symfony/ux-turbo.git", - "reference": "9762c373ed54c3642a4ae64b9254bc1c454f7da0" + "reference": "22954300bd0b01ca46f17c7890ea15138d9cf67f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/9762c373ed54c3642a4ae64b9254bc1c454f7da0", - "reference": "9762c373ed54c3642a4ae64b9254bc1c454f7da0", + "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/22954300bd0b01ca46f17c7890ea15138d9cf67f", + "reference": "22954300bd0b01ca46f17c7890ea15138d9cf67f", "shasum": "" }, "require": { @@ -12275,30 +13351,32 @@ "symfony/flex": "<1.13" }, "require-dev": { - "doctrine/annotations": "^1.12", + "dbrekelmans/bdi": "dev-main", "doctrine/doctrine-bundle": "^2.4.3", "doctrine/orm": "^2.8 | 3.0", "phpstan/phpstan": "^1.10", - "symfony/debug-bundle": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/form": "^5.4|^6.0", - "symfony/framework-bundle": "^5.4|^6.0", - "symfony/mercure-bundle": "^0.3.4", - "symfony/messenger": "^5.4|^6.0", - "symfony/panther": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/security-core": "^5.4|^6.0", - "symfony/stopwatch": "^5.4|^6.0", - "symfony/twig-bundle": "^5.4|^6.0", - "symfony/web-profiler-bundle": "^5.4|^6.0", - "symfony/webpack-encore-bundle": "^1.11" + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/debug-bundle": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/mercure-bundle": "^0.3.7", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/panther": "^2.1", + "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|6.3.*|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/security-core": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/twig-bundle": "^6.4|^7.0", + "symfony/ux-twig-component": "^2.21", + "symfony/web-profiler-bundle": "^5.4|^6.0|^7.0" }, "type": "symfony-bundle", "extra": { "thanks": { - "name": "symfony/ux", - "url": "https://github.com/symfony/ux" + "url": "https://github.com/symfony/ux", + "name": "symfony/ux" } }, "autoload": { @@ -12331,7 +13409,7 @@ "turbo-stream" ], "support": { - "source": "https://github.com/symfony/ux-turbo/tree/v2.10.0" + "source": "https://github.com/symfony/ux-turbo/tree/v2.24.0" }, "funding": [ { @@ -12347,20 +13425,20 @@ "type": "tidelift" } ], - "time": "2023-06-19T13:59:38+00:00" + "time": "2025-04-04T17:29:20+00:00" }, { "name": "symfony/validator", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "b0c4ecf17d39eee1edfecc92299a03b9f5d5220b" + "reference": "47610116f476595b90c368ff2a22514050712785" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/b0c4ecf17d39eee1edfecc92299a03b9f5d5220b", - "reference": "b0c4ecf17d39eee1edfecc92299a03b9f5d5220b", + "url": "https://api.github.com/repos/symfony/validator/zipball/47610116f476595b90c368ff2a22514050712785", + "reference": "47610116f476595b90c368ff2a22514050712785", "shasum": "" }, "require": { @@ -12379,27 +13457,27 @@ "symfony/http-kernel": "<5.4", "symfony/intl": "<5.4", "symfony/property-info": "<5.4", - "symfony/translation": "<5.4", + "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", "symfony/yaml": "<5.4" }, "require-dev": { "doctrine/annotations": "^1.13|^2", "egulias/email-validator": "^2.1.10|^3|^4", - "symfony/cache": "^5.4|^6.0", - "symfony/config": "^5.4|^6.0", - "symfony/console": "^5.4|^6.0", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/expression-language": "^5.4|^6.0", - "symfony/finder": "^5.4|^6.0", - "symfony/http-client": "^5.4|^6.0", - "symfony/http-foundation": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/intl": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", - "symfony/property-access": "^5.4|^6.0", - "symfony/property-info": "^5.4|^6.0", - "symfony/translation": "^5.4|^6.0", - "symfony/yaml": "^5.4|^6.0" + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/intl": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", + "symfony/yaml": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -12407,7 +13485,8 @@ "Symfony\\Component\\Validator\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Tests/", + "/Resources/bin/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -12427,7 +13506,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.3.2" + "source": "https://github.com/symfony/validator/tree/v6.4.21" }, "funding": [ { @@ -12443,20 +13522,20 @@ "type": "tidelift" } ], - "time": "2023-07-26T17:39:03+00:00" + "time": "2025-04-30T18:50:04+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.3.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "77fb4f2927f6991a9843633925d111147449ee7a" + "reference": "22560f80c0c5cd58cc0bcaf73455ffd81eb380d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/77fb4f2927f6991a9843633925d111147449ee7a", - "reference": "77fb4f2927f6991a9843633925d111147449ee7a", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/22560f80c0c5cd58cc0bcaf73455ffd81eb380d5", + "reference": "22560f80c0c5cd58cc0bcaf73455ffd81eb380d5", "shasum": "" }, "require": { @@ -12469,10 +13548,11 @@ }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0", - "symfony/uid": "^5.4|^6.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^6.3|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", "twig/twig": "^2.13|^3.0.4" }, "bin": [ @@ -12511,7 +13591,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.3.3" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.21" }, "funding": [ { @@ -12527,27 +13607,30 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2025-04-09T07:34:50+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.3.2", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "3400949782c0cb5b3e73aa64cfd71dde000beccc" + "reference": "717e7544aa99752c54ecba5c0e17459c48317472" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/3400949782c0cb5b3e73aa64cfd71dde000beccc", - "reference": "3400949782c0cb5b3e73aa64cfd71dde000beccc", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/717e7544aa99752c54ecba5c0e17459c48317472", + "reference": "717e7544aa99752c54ecba5c0e17459c48317472", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { - "symfony/var-dumper": "^5.4|^6.0" + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -12585,7 +13668,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.3.2" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.21" }, "funding": [ { @@ -12601,20 +13684,20 @@ "type": "tidelift" } ], - "time": "2023-07-26T17:39:03+00:00" + "time": "2025-04-27T21:06:26+00:00" }, { "name": "symfony/web-link", - "version": "v6.3.0", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/web-link.git", - "reference": "0989ca617d0703cdca501a245f10e194ff22315b" + "reference": "4d188b64bb9a9c5e2e4d20c8d5fdce6bbbb32c94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-link/zipball/0989ca617d0703cdca501a245f10e194ff22315b", - "reference": "0989ca617d0703cdca501a245f10e194ff22315b", + "url": "https://api.github.com/repos/symfony/web-link/zipball/4d188b64bb9a9c5e2e4d20c8d5fdce6bbbb32c94", + "reference": "4d188b64bb9a9c5e2e4d20c8d5fdce6bbbb32c94", "shasum": "" }, "require": { @@ -12628,7 +13711,7 @@ "psr/link-implementation": "1.0|2.0" }, "require-dev": { - "symfony/http-kernel": "^5.4|^6.0" + "symfony/http-kernel": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -12668,7 +13751,7 @@ "push" ], "support": { - "source": "https://github.com/symfony/web-link/tree/v6.3.0" + "source": "https://github.com/symfony/web-link/tree/v6.4.13" }, "funding": [ { @@ -12684,41 +13767,42 @@ "type": "tidelift" } ], - "time": "2023-04-21T14:41:17+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/webpack-encore-bundle", - "version": "v2.0.1", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/symfony/webpack-encore-bundle.git", - "reference": "150fe022740fef908f4ca3d5950ce85ab040ec76" + "reference": "e335394b68a775a9b2bd173a8ba4fd2001f3870c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/webpack-encore-bundle/zipball/150fe022740fef908f4ca3d5950ce85ab040ec76", - "reference": "150fe022740fef908f4ca3d5950ce85ab040ec76", + "url": "https://api.github.com/repos/symfony/webpack-encore-bundle/zipball/e335394b68a775a9b2bd173a8ba4fd2001f3870c", + "reference": "e335394b68a775a9b2bd173a8ba4fd2001f3870c", "shasum": "" }, "require": { "php": ">=8.1.0", - "symfony/asset": "^5.4 || ^6.2", - "symfony/config": "^5.4 || ^6.2", - "symfony/dependency-injection": "^5.4 || ^6.2", - "symfony/http-kernel": "^5.4 || ^6.2", + "symfony/asset": "^5.4 || ^6.2 || ^7.0", + "symfony/config": "^5.4 || ^6.2 || ^7.0", + "symfony/dependency-injection": "^5.4 || ^6.2 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.2 || ^7.0", "symfony/service-contracts": "^1.1.9 || ^2.1.3 || ^3.0" }, "require-dev": { - "symfony/framework-bundle": "^5.4 || ^6.2", - "symfony/phpunit-bridge": "^5.4 || ^6.2", - "symfony/twig-bundle": "^5.4 || ^6.2", - "symfony/web-link": "^5.4 || ^6.2" + "symfony/framework-bundle": "^5.4 || ^6.2 || ^7.0", + "symfony/http-client": "^5.4 || ^6.2 || ^7.0", + "symfony/phpunit-bridge": "^5.4 || ^6.2 || ^7.0", + "symfony/twig-bundle": "^5.4 || ^6.2 || ^7.0", + "symfony/web-link": "^5.4 || ^6.2 || ^7.0" }, "type": "symfony-bundle", "extra": { "thanks": { - "name": "symfony/webpack-encore", - "url": "https://github.com/symfony/webpack-encore" + "url": "https://github.com/symfony/webpack-encore", + "name": "symfony/webpack-encore" } }, "autoload": { @@ -12736,10 +13820,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Integration with your Symfony app & Webpack Encore!", + "description": "Integration of your Symfony app with Webpack Encore", "support": { "issues": "https://github.com/symfony/webpack-encore-bundle/issues", - "source": "https://github.com/symfony/webpack-encore-bundle/tree/v2.0.1" + "source": "https://github.com/symfony/webpack-encore-bundle/tree/v2.2.0" }, "funding": [ { @@ -12755,20 +13839,20 @@ "type": "tidelift" } ], - "time": "2023-05-31T14:28:33+00:00" + "time": "2024-10-02T07:27:19+00:00" }, { "name": "symfony/yaml", - "version": "v6.3.3", + "version": "v6.4.21", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e23292e8c07c85b971b44c1c4b87af52133e2add" + "reference": "f01987f45676778b474468aa266fe2eda1f2bc7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e23292e8c07c85b971b44c1c4b87af52133e2add", - "reference": "e23292e8c07c85b971b44c1c4b87af52133e2add", + "url": "https://api.github.com/repos/symfony/yaml/zipball/f01987f45676778b474468aa266fe2eda1f2bc7e", + "reference": "f01987f45676778b474468aa266fe2eda1f2bc7e", "shasum": "" }, "require": { @@ -12780,7 +13864,7 @@ "symfony/console": "<5.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0" + "symfony/console": "^5.4|^6.0|^7.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -12811,7 +13895,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.3.3" + "source": "https://github.com/symfony/yaml/tree/v6.4.21" }, "funding": [ { @@ -12827,20 +13911,20 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2025-04-04T09:48:44+00:00" }, { "name": "tecnickcom/tc-lib-barcode", - "version": "1.17.25", + "version": "2.4.6", "source": { "type": "git", "url": "https://github.com/tecnickcom/tc-lib-barcode.git", - "reference": "2b87f7c63dfd05000445a202c1779aeb9eb4549d" + "reference": "c6130222fdc02a2d7c90682b5c2ca24a059c16f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/tc-lib-barcode/zipball/2b87f7c63dfd05000445a202c1779aeb9eb4549d", - "reference": "2b87f7c63dfd05000445a202c1779aeb9eb4549d", + "url": "https://api.github.com/repos/tecnickcom/tc-lib-barcode/zipball/c6130222fdc02a2d7c90682b5c2ca24a059c16f4", + "reference": "c6130222fdc02a2d7c90682b5c2ca24a059c16f4", "shasum": "" }, "require": { @@ -12848,16 +13932,14 @@ "ext-date": "*", "ext-gd": "*", "ext-pcre": "*", - "php": ">=5.4", - "tecnickcom/tc-lib-color": "^1.14" + "php": ">=8.1", + "tecnickcom/tc-lib-color": "^2.2" }, "require-dev": { - "pdepend/pdepend": "2.13.0", - "phploc/phploc": "7.0.2 || 6.0.2 || 5.0.0 || 4.0.1 || 3.0.1 || 2.1.5", - "phpmd/phpmd": "2.13.0", - "phpunit/phpunit": "10.1.2 || 9.6.7 || 8.5.31 || 7.5.20 || 6.5.14 || 5.7.27 || 4.8.36", - "sebastian/phpcpd": "6.0.3 || 5.0.2 || 4.1.0 || 3.0.1 || 2.0.4", - "squizlabs/php_codesniffer": "3.7.2 || 2.9.2" + "pdepend/pdepend": "2.16.2", + "phpmd/phpmd": "2.15.0", + "phpunit/phpunit": "12.1.3 || 11.5.7 || 10.5.40", + "squizlabs/php_codesniffer": "3.12.2" }, "type": "library", "autoload": { @@ -12867,7 +13949,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-3.0" + "LGPL-3.0-or-later" ], "authors": [ { @@ -12890,6 +13972,9 @@ "EAN 13", "EAN 8", "ECC200", + "ISO IEC 15438 2006", + "ISO IEC 16022", + "ISO IEC 24778 2008", "Intelligent Mail Barcode", "Interleaved 2 of 5", "KIX", @@ -12906,6 +13991,7 @@ "USD-3", "USPS-B-3200", "USS-93", + "aztec", "barcode", "datamatrix", "pdf417", @@ -12917,41 +14003,39 @@ ], "support": { "issues": "https://github.com/tecnickcom/tc-lib-barcode/issues", - "source": "https://github.com/tecnickcom/tc-lib-barcode/tree/1.17.25" + "source": "https://github.com/tecnickcom/tc-lib-barcode/tree/2.4.6" }, "funding": [ { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tc-lib-barcode%20project", + "url": "https://www.paypal.com/donate/?hosted_button_id=NZUEC5XS8MFBJ", "type": "custom" } ], - "time": "2023-05-18T08:10:11+00:00" + "time": "2025-05-13T05:49:21+00:00" }, { "name": "tecnickcom/tc-lib-color", - "version": "1.14.24", + "version": "2.2.11", "source": { "type": "git", "url": "https://github.com/tecnickcom/tc-lib-color.git", - "reference": "6207533413f6edc3fea373d0e54041661d2bd905" + "reference": "ead45d76932d936e065062194032bf87f7ea45f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/tc-lib-color/zipball/6207533413f6edc3fea373d0e54041661d2bd905", - "reference": "6207533413f6edc3fea373d0e54041661d2bd905", + "url": "https://api.github.com/repos/tecnickcom/tc-lib-color/zipball/ead45d76932d936e065062194032bf87f7ea45f8", + "reference": "ead45d76932d936e065062194032bf87f7ea45f8", "shasum": "" }, "require": { "ext-pcre": "*", - "php": ">=5.3" + "php": ">=8.1" }, "require-dev": { - "pdepend/pdepend": "2.13.0", - "phploc/phploc": "7.0.2 || 6.0.2 || 5.0.0 || 4.0.1 || 3.0.1 || 2.1.5", - "phpmd/phpmd": "2.13.0", - "phpunit/phpunit": "10.1.2 || 9.6.7 || 8.5.31 || 7.5.20 || 6.5.14 || 5.7.27 || 4.8.36", - "sebastian/phpcpd": "6.0.3 || 5.0.2 || 4.1.0 || 3.0.1 || 2.0.4", - "squizlabs/php_codesniffer": "3.7.2 || 2.9.2" + "pdepend/pdepend": "2.16.2", + "phpmd/phpmd": "2.15.0", + "phpunit/phpunit": "12.1.3 || 11.5.7 || 10.5.40", + "squizlabs/php_codesniffer": "3.12.2" }, "type": "library", "autoload": { @@ -12961,7 +14045,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL-3.0" + "LGPL-3.0-or-later" ], "authors": [ { @@ -12988,43 +14072,45 @@ ], "support": { "issues": "https://github.com/tecnickcom/tc-lib-color/issues", - "source": "https://github.com/tecnickcom/tc-lib-color/tree/1.14.24" + "source": "https://github.com/tecnickcom/tc-lib-color/tree/2.2.11" }, "funding": [ { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tc-lib-color%20project", + "url": "https://www.paypal.com/donate/?hosted_button_id=NZUEC5XS8MFBJ", "type": "custom" } ], - "time": "2023-05-18T08:09:02+00:00" + "time": "2025-05-13T05:47:44+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "2.2.6", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c" + "reference": "0d72ac1c00084279c1816675284073c5a337c20d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/c42125b83a4fa63b187fdf29f9c93cb7733da30c", - "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", - "php": "^5.5 || ^7.0 || ^8.0", - "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0" + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10" + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { @@ -13047,34 +14133,38 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.6" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" }, - "time": "2023-01-03T09:29:04+00:00" + "time": "2024-12-21T16:25:41+00:00" }, { "name": "twig/cssinliner-extra", - "version": "v3.7.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/cssinliner-extra.git", - "reference": "85c8f3d7712bab57f6162f9637613df0511f207b" + "reference": "378d29b61d6406c456e3a4afbd15bbeea0b72ea8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/cssinliner-extra/zipball/85c8f3d7712bab57f6162f9637613df0511f207b", - "reference": "85c8f3d7712bab57f6162f9637613df0511f207b", + "url": "https://api.github.com/repos/twigphp/cssinliner-extra/zipball/378d29b61d6406c456e3a4afbd15bbeea0b72ea8", + "reference": "378d29b61d6406c456e3a4afbd15bbeea0b72ea8", "shasum": "" }, "require": { - "php": ">=7.1.3", + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", "tijsverkoyen/css-to-inline-styles": "^2.0", - "twig/twig": "^2.7|^3.0" + "twig/twig": "^3.13|^4.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" + "symfony/phpunit-bridge": "^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { "Twig\\Extra\\CssInliner\\": "" }, @@ -13102,7 +14192,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/cssinliner-extra/tree/v3.7.0" + "source": "https://github.com/twigphp/cssinliner-extra/tree/v3.21.0" }, "funding": [ { @@ -13114,38 +14204,38 @@ "type": "tidelift" } ], - "time": "2023-02-09T06:45:16+00:00" + "time": "2025-01-31T20:45:36+00:00" }, { "name": "twig/extra-bundle", - "version": "v3.7.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/twig-extra-bundle.git", - "reference": "802cc2dd46ec88285d6c7fa85c26ab7f2cd5bc49" + "reference": "62d1cf47a1aa009cbd07b21045b97d3d5cb79896" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/802cc2dd46ec88285d6c7fa85c26ab7f2cd5bc49", - "reference": "802cc2dd46ec88285d6c7fa85c26ab7f2cd5bc49", + "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/62d1cf47a1aa009cbd07b21045b97d3d5cb79896", + "reference": "62d1cf47a1aa009cbd07b21045b97d3d5cb79896", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/framework-bundle": "^4.4|^5.0|^6.0", - "symfony/twig-bundle": "^4.4|^5.0|^6.0", - "twig/twig": "^2.7|^3.0" + "php": ">=8.1.0", + "symfony/framework-bundle": "^5.4|^6.4|^7.0", + "symfony/twig-bundle": "^5.4|^6.4|^7.0", + "twig/twig": "^3.2|^4.0" }, "require-dev": { "league/commonmark": "^1.0|^2.0", - "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0", + "symfony/phpunit-bridge": "^6.4|^7.0", "twig/cache-extra": "^3.0", - "twig/cssinliner-extra": "^2.12|^3.0", - "twig/html-extra": "^2.12|^3.0", - "twig/inky-extra": "^2.12|^3.0", - "twig/intl-extra": "^2.12|^3.0", - "twig/markdown-extra": "^2.12|^3.0", - "twig/string-extra": "^2.12|^3.0" + "twig/cssinliner-extra": "^3.0", + "twig/html-extra": "^3.0", + "twig/inky-extra": "^3.0", + "twig/intl-extra": "^3.0", + "twig/markdown-extra": "^3.0", + "twig/string-extra": "^3.0" }, "type": "symfony-bundle", "autoload": { @@ -13176,7 +14266,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.7.0" + "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.21.0" }, "funding": [ { @@ -13188,32 +14278,36 @@ "type": "tidelift" } ], - "time": "2023-05-06T11:11:46+00:00" + "time": "2025-02-19T14:29:33+00:00" }, { "name": "twig/html-extra", - "version": "v3.7.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/html-extra.git", - "reference": "af5b336a13122d28d405714b6f2abe840632251b" + "reference": "5442dd707601c83b8cd4233e37bb10ab8489a90f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/html-extra/zipball/af5b336a13122d28d405714b6f2abe840632251b", - "reference": "af5b336a13122d28d405714b6f2abe840632251b", + "url": "https://api.github.com/repos/twigphp/html-extra/zipball/5442dd707601c83b8cd4233e37bb10ab8489a90f", + "reference": "5442dd707601c83b8cd4233e37bb10ab8489a90f", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/mime": "^4.4|^5.0|^6.0", - "twig/twig": "^2.7|^3.0" + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/mime": "^5.4|^6.4|^7.0", + "twig/twig": "^3.13|^4.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" + "symfony/phpunit-bridge": "^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { "Twig\\Extra\\Html\\": "" }, @@ -13240,7 +14334,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/html-extra/tree/v3.7.0" + "source": "https://github.com/twigphp/html-extra/tree/v3.21.0" }, "funding": [ { @@ -13252,32 +14346,36 @@ "type": "tidelift" } ], - "time": "2023-02-09T06:45:16+00:00" + "time": "2025-02-19T14:29:33+00:00" }, { "name": "twig/inky-extra", - "version": "v3.7.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/inky-extra.git", - "reference": "907abf7046082cc151a3ee01f268dbf5f5f28eab" + "reference": "aacd79d94534b4a7fd6533cb5c33c4ee97239a0d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/inky-extra/zipball/907abf7046082cc151a3ee01f268dbf5f5f28eab", - "reference": "907abf7046082cc151a3ee01f268dbf5f5f28eab", + "url": "https://api.github.com/repos/twigphp/inky-extra/zipball/aacd79d94534b4a7fd6533cb5c33c4ee97239a0d", + "reference": "aacd79d94534b4a7fd6533cb5c33c4ee97239a0d", "shasum": "" }, "require": { "lorenzo/pinky": "^1.0.5", - "php": ">=7.1.3", - "twig/twig": "^2.7|^3.0" + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "twig/twig": "^3.13|^4.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" + "symfony/phpunit-bridge": "^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { "Twig\\Extra\\Inky\\": "" }, @@ -13306,7 +14404,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/inky-extra/tree/v3.7.0" + "source": "https://github.com/twigphp/inky-extra/tree/v3.21.0" }, "funding": [ { @@ -13318,29 +14416,29 @@ "type": "tidelift" } ], - "time": "2023-02-09T06:45:16+00:00" + "time": "2025-01-31T20:45:36+00:00" }, { "name": "twig/intl-extra", - "version": "v3.7.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/intl-extra.git", - "reference": "a97c323bebfca009d02994a5a8568c0b412a49ab" + "reference": "05bc5d46b9df9e62399eae53e7c0b0633298b146" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/a97c323bebfca009d02994a5a8568c0b412a49ab", - "reference": "a97c323bebfca009d02994a5a8568c0b412a49ab", + "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/05bc5d46b9df9e62399eae53e7c0b0633298b146", + "reference": "05bc5d46b9df9e62399eae53e7c0b0633298b146", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/intl": "^4.4|^5.0|^6.0", - "twig/twig": "^2.7|^3.0" + "php": ">=8.1.0", + "symfony/intl": "^5.4|^6.4|^7.0", + "twig/twig": "^3.13|^4.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" + "symfony/phpunit-bridge": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -13370,7 +14468,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/intl-extra/tree/v3.7.0" + "source": "https://github.com/twigphp/intl-extra/tree/v3.21.0" }, "funding": [ { @@ -13382,35 +14480,39 @@ "type": "tidelift" } ], - "time": "2023-02-09T06:45:16+00:00" + "time": "2025-01-31T20:45:36+00:00" }, { "name": "twig/markdown-extra", - "version": "v3.7.0", + "version": "v3.21.0", "source": { "type": "git", "url": "https://github.com/twigphp/markdown-extra.git", - "reference": "8f1179e279cea6ef14066a4560b859df58acd5d8" + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/8f1179e279cea6ef14066a4560b859df58acd5d8", - "reference": "8f1179e279cea6ef14066a4560b859df58acd5d8", + "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/f4616e1dd375209dacf6026f846e6b537d036ce4", + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4", "shasum": "" }, "require": { - "php": ">=7.1.3", - "twig/twig": "^2.7|^3.0" + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "twig/twig": "^3.13|^4.0" }, "require-dev": { - "erusev/parsedown": "^1.7", + "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": "^4.4.9|^5.0.9|^6.0" + "symfony/phpunit-bridge": "^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { "Twig\\Extra\\Markdown\\": "" }, @@ -13438,7 +14540,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/markdown-extra/tree/v3.7.0" + "source": "https://github.com/twigphp/markdown-extra/tree/v3.21.0" }, "funding": [ { @@ -13450,33 +14552,108 @@ "type": "tidelift" } ], - "time": "2023-02-09T06:45:16+00:00" + "time": "2025-01-31T20:45:36+00:00" }, { - "name": "twig/twig", - "version": "v3.7.0", + "name": "twig/string-extra", + "version": "v3.21.0", "source": { "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "5cf942bbab3df42afa918caeba947f1b690af64b" + "url": "https://github.com/twigphp/string-extra.git", + "reference": "4b3337544ac8f76c280def94e32b53acfaec0589" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/5cf942bbab3df42afa918caeba947f1b690af64b", - "reference": "5cf942bbab3df42afa918caeba947f1b690af64b", + "url": "https://api.github.com/repos/twigphp/string-extra/zipball/4b3337544ac8f76c280def94e32b53acfaec0589", + "reference": "4b3337544ac8f76c280def94e32b53acfaec0589", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1.0", + "symfony/string": "^5.4|^6.4|^7.0", + "symfony/translation-contracts": "^1.1|^2|^3", + "twig/twig": "^3.13|^4.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Twig\\Extra\\String\\": "" + }, + "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 Symfony String", + "homepage": "https://twig.symfony.com", + "keywords": [ + "html", + "string", + "twig", + "unicode" + ], + "support": { + "source": "https://github.com/twigphp/string-extra/tree/v3.21.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.21.1", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "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": "^4.4.9|^5.0.9|^6.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/" } @@ -13509,7 +14686,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.7.0" + "source": "https://github.com/twigphp/Twig/tree/v3.21.1" }, "funding": [ { @@ -13521,7 +14698,7 @@ "type": "tidelift" } ], - "time": "2023-07-26T07:16:09+00:00" + "time": "2025-05-03T07:21:55+00:00" }, { "name": "ua-parser/uap-php", @@ -13588,39 +14765,38 @@ }, { "name": "web-auth/cose-lib", - "version": "4.2.3", + "version": "4.4.0", "source": { "type": "git", "url": "https://github.com/web-auth/cose-lib.git", - "reference": "0ecad86d2d034ea22e2205d81c8cdec13d93a991" + "reference": "2166016e48e0214f4f63320a7758a9386d14c92a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/0ecad86d2d034ea22e2205d81c8cdec13d93a991", - "reference": "0ecad86d2d034ea22e2205d81c8cdec13d93a991", + "url": "https://api.github.com/repos/web-auth/cose-lib/zipball/2166016e48e0214f4f63320a7758a9386d14c92a", + "reference": "2166016e48e0214f4f63320a7758a9386d14c92a", "shasum": "" }, "require": { - "brick/math": "^0.9|^0.10|^0.11", + "brick/math": "^0.9|^0.10|^0.11|^0.12", "ext-json": "*", - "ext-mbstring": "*", "ext-openssl": "*", "php": ">=8.1", "spomky-labs/pki-framework": "^1.0" }, "require-dev": { "ekino/phpstan-banned-code": "^1.0", - "infection/infection": "^0.27", + "infection/infection": "^0.29", "php-parallel-lint/php-parallel-lint": "^1.3", "phpstan/extension-installer": "^1.3", "phpstan/phpstan": "^1.7", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.2", - "phpunit/phpunit": "^10.1", - "qossmic/deptrac-shim": "^1.0", - "rector/rector": "^0.17", - "symfony/phpunit-bridge": "^6.1", + "phpunit/phpunit": "^10.1|^11.0", + "qossmic/deptrac": "^2.0", + "rector/rector": "^1.0", + "symfony/phpunit-bridge": "^6.4|^7.0", "symplify/easy-coding-standard": "^12.0" }, "suggest": { @@ -13655,7 +14831,7 @@ ], "support": { "issues": "https://github.com/web-auth/cose-lib/issues", - "source": "https://github.com/web-auth/cose-lib/tree/4.2.3" + "source": "https://github.com/web-auth/cose-lib/tree/4.4.0" }, "funding": [ { @@ -13667,134 +14843,55 @@ "type": "patreon" } ], - "time": "2023-07-26T13:32:03+00:00" - }, - { - "name": "web-auth/metadata-service", - "version": "4.6.4", - "source": { - "type": "git", - "url": "https://github.com/web-auth/webauthn-metadata-service.git", - "reference": "b58fbb0df46450acc426329bd87b60d794859da0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-metadata-service/zipball/b58fbb0df46450acc426329bd87b60d794859da0", - "reference": "b58fbb0df46450acc426329bd87b60d794859da0", - "shasum": "" - }, - "require": { - "ext-json": "*", - "lcobucci/clock": "^2.2|^3.0", - "paragonie/constant_time_encoding": "^2.6", - "php": ">=8.1", - "psr/clock": "^1.0", - "psr/event-dispatcher": "^1.0", - "psr/http-client": "^1.0", - "psr/http-factory": "^1.0", - "psr/log": "^1.0|^2.0|^3.0", - "spomky-labs/pki-framework": "^1.0", - "symfony/deprecation-contracts": "^3.2" - }, - "suggest": { - "psr/clock-implementation": "As of 4.5.x, the PSR Clock implementation will replace lcobucci/clock", - "psr/log-implementation": "Recommended to receive logs from the library", - "web-token/jwt-key-mgmt": "Mandatory for fetching Metadata Statement from distant sources", - "web-token/jwt-signature-algorithm-ecdsa": "Mandatory for fetching Metadata Statement from distant sources" - }, - "type": "library", - "extra": { - "thanks": { - "name": "web-auth/webauthn-framework", - "url": "https://github.com/web-auth/webauthn-framework" - } - }, - "autoload": { - "psr-4": { - "Webauthn\\MetadataService\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" - }, - { - "name": "All contributors", - "homepage": "https://github.com/web-auth/metadata-service/contributors" - } - ], - "description": "Metadata Service for FIDO2/Webauthn", - "homepage": "https://github.com/web-auth", - "keywords": [ - "FIDO2", - "fido", - "webauthn" - ], - "support": { - "source": "https://github.com/web-auth/webauthn-metadata-service/tree/4.6.4" - }, - "funding": [ - { - "url": "https://github.com/Spomky", - "type": "github" - }, - { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" - } - ], - "time": "2023-06-01T19:06:30+00:00" + "time": "2024-07-18T08:47:32+00:00" }, { "name": "web-auth/webauthn-lib", - "version": "4.6.4", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/web-auth/webauthn-lib.git", - "reference": "8cb4949d81ef8414c82f334fb3514141aa013340" + "reference": "008b25171c27cf4813420d0de31cc059bcc71f1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/8cb4949d81ef8414c82f334fb3514141aa013340", - "reference": "8cb4949d81ef8414c82f334fb3514141aa013340", + "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/008b25171c27cf4813420d0de31cc059bcc71f1a", + "reference": "008b25171c27cf4813420d0de31cc059bcc71f1a", "shasum": "" }, "require": { "ext-json": "*", "ext-mbstring": "*", "ext-openssl": "*", - "paragonie/constant_time_encoding": "^2.6", + "lcobucci/clock": "^2.2|^3.0", + "paragonie/constant_time_encoding": "^2.6|^3.0", "php": ">=8.1", + "psr/clock": "^1.0", "psr/event-dispatcher": "^1.0", "psr/http-client": "^1.0", "psr/http-factory": "^1.0", "psr/log": "^1.0|^2.0|^3.0", "spomky-labs/cbor-php": "^3.0", - "symfony/uid": "^6.1", - "web-auth/cose-lib": "^4.0.12", - "web-auth/metadata-service": "self.version" - }, - "require-dev": { - "symfony/event-dispatcher": "^6.1" + "spomky-labs/pki-framework": "^1.0", + "symfony/deprecation-contracts": "^3.2", + "symfony/uid": "^6.1|^7.0", + "web-auth/cose-lib": "^4.2.3" }, "suggest": { + "phpdocumentor/reflection-docblock": "As of 4.5.x, the phpdocumentor/reflection-docblock component will become mandatory for converting objects such as the Metadata Statement", + "psr/clock-implementation": "As of 4.5.x, the PSR Clock implementation will replace lcobucci/clock", "psr/log-implementation": "Recommended to receive logs from the library", "symfony/event-dispatcher": "Recommended to use dispatched events", - "web-token/jwt-key-mgmt": "Mandatory for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-ecdsa": "Recommended for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-eddsa": "Recommended for the AndroidSafetyNet Attestation Statement support", - "web-token/jwt-signature-algorithm-rsa": "Mandatory for the AndroidSafetyNet Attestation Statement support" + "symfony/property-access": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/property-info": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/serializer": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "web-token/jwt-library": "Mandatory for fetching Metadata Statement from distant sources" }, "type": "library", "extra": { "thanks": { - "name": "web-auth/webauthn-framework", - "url": "https://github.com/web-auth/webauthn-framework" + "url": "https://github.com/web-auth/webauthn-framework", + "name": "web-auth/webauthn-framework" } }, "autoload": { @@ -13824,7 +14921,7 @@ "webauthn" ], "support": { - "source": "https://github.com/web-auth/webauthn-lib/tree/4.6.4" + "source": "https://github.com/web-auth/webauthn-lib/tree/4.9.2" }, "funding": [ { @@ -13836,45 +14933,47 @@ "type": "patreon" } ], - "time": "2023-07-15T14:53:06+00:00" + "time": "2025-01-04T09:47:58+00:00" }, { "name": "web-auth/webauthn-symfony-bundle", - "version": "4.6.4", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/web-auth/webauthn-symfony-bundle.git", - "reference": "04bd26182e26c8bf218bdca3d8b0f569ff983ff8" + "reference": "80aa16fa6f16ab8f017a4108ffcd2ecc12264c07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-symfony-bundle/zipball/04bd26182e26c8bf218bdca3d8b0f569ff983ff8", - "reference": "04bd26182e26c8bf218bdca3d8b0f569ff983ff8", + "url": "https://api.github.com/repos/web-auth/webauthn-symfony-bundle/zipball/80aa16fa6f16ab8f017a4108ffcd2ecc12264c07", + "reference": "80aa16fa6f16ab8f017a4108ffcd2ecc12264c07", "shasum": "" }, "require": { "nyholm/psr7": "^1.5", "php": ">=8.1", + "phpdocumentor/reflection-docblock": "^5.3", "psr/event-dispatcher": "^1.0", - "spomky-labs/cbor-bundle": "^3.0", - "symfony/config": "^6.1", - "symfony/dependency-injection": "^6.1", - "symfony/framework-bundle": "^6.1", - "symfony/http-client": "^6.1", - "symfony/psr-http-message-bridge": "^2.1", - "symfony/security-bundle": "^6.1", - "symfony/security-core": "^6.1", - "symfony/security-http": "^6.1", - "symfony/serializer": "^6.1", - "symfony/validator": "^6.1", + "symfony/config": "^6.1|^7.0", + "symfony/dependency-injection": "^6.1|^7.0", + "symfony/framework-bundle": "^6.1|^7.0", + "symfony/http-client": "^6.1|^7.0", + "symfony/property-access": "^6.1|^7.0", + "symfony/property-info": "^6.1|^7.0", + "symfony/psr-http-message-bridge": "^2.1|^6.1|^7.0", + "symfony/security-bundle": "^6.1|^7.0", + "symfony/security-core": "^6.1|^7.0", + "symfony/security-http": "^6.1|^7.0", + "symfony/serializer": "^6.1|^7.0", + "symfony/validator": "^6.1|^7.0", "web-auth/webauthn-lib": "self.version", - "web-token/jwt-signature": "^3.1" + "web-token/jwt-library": "^3.3|^4.0" }, "type": "symfony-bundle", "extra": { "thanks": { - "name": "web-auth/webauthn-framework", - "url": "https://github.com/web-auth/webauthn-framework" + "url": "https://github.com/web-auth/webauthn-framework", + "name": "web-auth/webauthn-framework" } }, "autoload": { @@ -13900,11 +14999,14 @@ "homepage": "https://github.com/web-auth", "keywords": [ "FIDO2", + "bundle", "fido", + "symfony", + "symfony-bundle", "webauthn" ], "support": { - "source": "https://github.com/web-auth/webauthn-symfony-bundle/tree/4.6.4" + "source": "https://github.com/web-auth/webauthn-symfony-bundle/tree/4.9.2" }, "funding": [ { @@ -13916,37 +15018,54 @@ "type": "patreon" } ], - "time": "2023-06-12T14:32:32+00:00" + "time": "2025-01-04T09:38:56+00:00" }, { - "name": "web-token/jwt-core", - "version": "3.2.7", + "name": "web-token/jwt-library", + "version": "3.4.8", "source": { "type": "git", - "url": "https://github.com/web-token/jwt-core.git", - "reference": "db58b6ebbe1a7d5869688e989b1cf110c6ab888f" + "url": "https://github.com/web-token/jwt-library.git", + "reference": "92445671cc788fa5f639898a67c06f9fd0bf491f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-core/zipball/db58b6ebbe1a7d5869688e989b1cf110c6ab888f", - "reference": "db58b6ebbe1a7d5869688e989b1cf110c6ab888f", + "url": "https://api.github.com/repos/web-token/jwt-library/zipball/92445671cc788fa5f639898a67c06f9fd0bf491f", + "reference": "92445671cc788fa5f639898a67c06f9fd0bf491f", "shasum": "" }, "require": { - "brick/math": "^0.9|^0.10|^0.11", + "brick/math": "^0.9|^0.10|^0.11|^0.12", "ext-json": "*", "ext-mbstring": "*", - "paragonie/constant_time_encoding": "^2.4", + "paragonie/constant_time_encoding": "^2.6|^3.0", + "paragonie/sodium_compat": "^1.20|^2.0", "php": ">=8.1", - "spomky-labs/pki-framework": "^1.0" + "psr/cache": "^2.0|^3.0", + "psr/clock": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "spomky-labs/pki-framework": "^1.2.1", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/polyfill-mbstring": "^1.12" }, "conflict": { "spomky-labs/jose": "*" }, + "suggest": { + "ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance", + "ext-gmp": "GMP or BCMath is highly recommended to improve the library performance", + "ext-openssl": "For key management (creation, optimization, etc.) and some algorithms (AES, RSA, ECDSA, etc.)", + "ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", + "paragonie/sodium_compat": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys", + "spomky-labs/aes-key-wrap": "For all Key Wrapping algorithms (A128KW, A192KW, A256KW, A128GCMKW, A192GCMKW, A256GCMKW, PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW...)", + "symfony/http-client": "To enable JKU/X5U support." + }, "type": "library", "autoload": { "psr-4": { - "Jose\\Component\\Core\\": "" + "Jose\\Component\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -13963,7 +15082,7 @@ "homepage": "https://github.com/web-token/jwt-framework/contributors" } ], - "description": "Core component of the JWT Framework.", + "description": "JWT library", "homepage": "https://github.com/web-token", "keywords": [ "JOSE", @@ -13984,92 +15103,20 @@ "symfony" ], "support": { - "source": "https://github.com/web-token/jwt-core/tree/3.2.7" + "issues": "https://github.com/web-token/jwt-library/issues", + "source": "https://github.com/web-token/jwt-library/tree/3.4.8" }, "funding": [ { - "url": "https://www.patreon.com/FlorentMorselli", - "type": "patreon" - } - ], - "time": "2023-02-02T17:35:17+00:00" - }, - { - "name": "web-token/jwt-signature", - "version": "3.2.7", - "source": { - "type": "git", - "url": "https://github.com/web-token/jwt-signature.git", - "reference": "156e0b0ef534e53eecf23a32a92ee6d8cb4fdac4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/web-token/jwt-signature/zipball/156e0b0ef534e53eecf23a32a92ee6d8cb4fdac4", - "reference": "156e0b0ef534e53eecf23a32a92ee6d8cb4fdac4", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "web-token/jwt-core": "^3.2" - }, - "suggest": { - "web-token/jwt-signature-algorithm-ecdsa": "ECDSA Based Signature Algorithms", - "web-token/jwt-signature-algorithm-eddsa": "EdDSA Based Signature Algorithms", - "web-token/jwt-signature-algorithm-experimental": "Experimental Signature Algorithms", - "web-token/jwt-signature-algorithm-hmac": "HMAC Based Signature Algorithms", - "web-token/jwt-signature-algorithm-none": "None Signature Algorithm", - "web-token/jwt-signature-algorithm-rsa": "RSA Based Signature Algorithms" - }, - "type": "library", - "autoload": { - "psr-4": { - "Jose\\Component\\Signature\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Florent Morselli", - "homepage": "https://github.com/Spomky" + "url": "https://github.com/Spomky", + "type": "github" }, - { - "name": "All contributors", - "homepage": "https://github.com/web-token/jwt-signature/contributors" - } - ], - "description": "Signature component of the JWT Framework.", - "homepage": "https://github.com/web-token", - "keywords": [ - "JOSE", - "JWE", - "JWK", - "JWKSet", - "JWS", - "Jot", - "RFC7515", - "RFC7516", - "RFC7517", - "RFC7518", - "RFC7519", - "RFC7520", - "bundle", - "jwa", - "jwt", - "symfony" - ], - "support": { - "source": "https://github.com/web-token/jwt-signature/tree/3.2.7" - }, - "funding": [ { "url": "https://www.patreon.com/FlorentMorselli", "type": "patreon" } ], - "time": "2023-05-18T16:20:51+00:00" + "time": "2025-05-07T09:11:18+00:00" }, { "name": "webmozart/assert", @@ -14128,429 +15175,100 @@ "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, "time": "2022-06-03T18:03:27+00:00" + }, + { + "name": "willdurand/negotiation", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/willdurand/Negotiation.git", + "reference": "68e9ea0553ef6e2ee8db5c1d98829f111e623ec2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/68e9ea0553ef6e2ee8db5c1d98829f111e623ec2", + "reference": "68e9ea0553ef6e2ee8db5c1d98829f111e623ec2", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Negotiation\\": "src/Negotiation" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "William Durand", + "email": "will+git@drnd.me" + } + ], + "description": "Content Negotiation tools for PHP provided as a standalone library.", + "homepage": "http://williamdurand.fr/Negotiation/", + "keywords": [ + "accept", + "content", + "format", + "header", + "negotiation" + ], + "support": { + "issues": "https://github.com/willdurand/Negotiation/issues", + "source": "https://github.com/willdurand/Negotiation/tree/3.1.0" + }, + "time": "2022-01-30T20:08:53+00:00" } ], "packages-dev": [ - { - "name": "amphp/amp", - "version": "v2.6.2", - "source": { - "type": "git", - "url": "https://github.com/amphp/amp.git", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "dev-master", - "amphp/phpunit-util": "^1", - "ext-json": "*", - "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^7 | ^8 | ^9", - "psalm/phar": "^3.11@dev", - "react/promise": "^2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "files": [ - "lib/functions.php", - "lib/Internal/functions.php" - ], - "psr-4": { - "Amp\\": "lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A non-blocking concurrency framework for PHP applications.", - "homepage": "https://amphp.org/amp", - "keywords": [ - "async", - "asynchronous", - "awaitable", - "concurrency", - "event", - "event-loop", - "future", - "non-blocking", - "promise" - ], - "support": { - "irc": "irc://irc.freenode.org/amphp", - "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.6.2" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2022-02-20T17:52:18+00:00" - }, - { - "name": "amphp/byte-stream", - "version": "v1.8.1", - "source": { - "type": "git", - "url": "https://github.com/amphp/byte-stream.git", - "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd", - "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd", - "shasum": "" - }, - "require": { - "amphp/amp": "^2", - "php": ">=7.1" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "dev-master", - "amphp/phpunit-util": "^1.4", - "friendsofphp/php-cs-fixer": "^2.3", - "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^6 || ^7 || ^8", - "psalm/phar": "^3.11.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "files": [ - "lib/functions.php" - ], - "psr-4": { - "Amp\\ByteStream\\": "lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A stream abstraction to make working with non-blocking I/O simple.", - "homepage": "http://amphp.org/byte-stream", - "keywords": [ - "amp", - "amphp", - "async", - "io", - "non-blocking", - "stream" - ], - "support": { - "irc": "irc://irc.freenode.org/amphp", - "issues": "https://github.com/amphp/byte-stream/issues", - "source": "https://github.com/amphp/byte-stream/tree/v1.8.1" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2021-03-30T17:13:30+00:00" - }, - { - "name": "composer/pcre", - "version": "3.1.0", - "source": { - "type": "git", - "url": "https://github.com/composer/pcre.git", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", - "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" - }, - "type": "library", - "extra": { - "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.1.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": "2022-11-17T09:50:14+00:00" - }, - { - "name": "composer/semver", - "version": "3.3.2", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "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": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/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": "2022-04-01T19:23:25+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", - "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", - "symfony/phpunit-bridge": "^6.0" - }, - "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": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.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": "2022-02-25T21:32:43+00:00" - }, { "name": "dama/doctrine-test-bundle", - "version": "v7.2.1", + "version": "v8.2.2", "source": { "type": "git", "url": "https://github.com/dmaicher/doctrine-test-bundle.git", - "reference": "175b47153609a369117d97d36049b8a8c3b69dc1" + "reference": "eefe54fdf00d910f808efea9cfce9cc261064a0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/175b47153609a369117d97d36049b8a8c3b69dc1", - "reference": "175b47153609a369117d97d36049b8a8c3b69dc1", + "url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/eefe54fdf00d910f808efea9cfce9cc261064a0a", + "reference": "eefe54fdf00d910f808efea9cfce9cc261064a0a", "shasum": "" }, "require": { - "doctrine/dbal": "^3.3", - "doctrine/doctrine-bundle": "^2.2.2", - "ext-json": "*", - "php": "^7.3 || ^8.0", + "doctrine/dbal": "^3.3 || ^4.0", + "doctrine/doctrine-bundle": "^2.11.0", + "php": "^7.4 || ^8.0", "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/cache": "^5.4 || ^6.0", - "symfony/framework-bundle": "^5.4 || ^6.0" + "symfony/cache": "^5.4 || ^6.3 || ^7.0", + "symfony/framework-bundle": "^5.4 || ^6.3 || ^7.0" }, "require-dev": { "behat/behat": "^3.0", - "doctrine/cache": "^1.12", - "phpstan/phpstan": "^1.2", - "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0", - "symfony/phpunit-bridge": "^6.0", - "symfony/process": "^5.4 || ^6.0", - "symfony/yaml": "^5.4 || ^6.0" + "friendsofphp/php-cs-fixer": "^3.27", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^8.0 || ^9.0 || ^10.0 || ^11.0", + "symfony/phpunit-bridge": "^7.2", + "symfony/process": "^5.4 || ^6.3 || ^7.0", + "symfony/yaml": "^5.4 || ^6.3 || ^7.0" }, "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-master": "8.x-dev" } }, "autoload": { @@ -14574,88 +15292,55 @@ "isolation", "performance", "symfony", + "testing", "tests" ], "support": { "issues": "https://github.com/dmaicher/doctrine-test-bundle/issues", - "source": "https://github.com/dmaicher/doctrine-test-bundle/tree/v7.2.1" + "source": "https://github.com/dmaicher/doctrine-test-bundle/tree/v8.2.2" }, - "time": "2023-02-07T10:02:27+00:00" - }, - { - "name": "dnoegel/php-xdg-base-dir", - "version": "v0.1.1", - "source": { - "type": "git", - "url": "https://github.com/dnoegel/php-xdg-base-dir.git", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" - }, - "type": "library", - "autoload": { - "psr-4": { - "XdgBaseDir\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "implementation of xdg base directory specification for php", - "support": { - "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", - "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" - }, - "time": "2019-12-04T15:06:13+00:00" + "time": "2025-02-04T14:37:36+00:00" }, { "name": "doctrine/doctrine-fixtures-bundle", - "version": "3.4.4", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineFixturesBundle.git", - "reference": "9ec3139c52a42e94c9fd1e95f8d2bca94326edfb" + "reference": "a06db6b81ff20a2980bf92063d80c013bb8b4b7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/9ec3139c52a42e94c9fd1e95f8d2bca94326edfb", - "reference": "9ec3139c52a42e94c9fd1e95f8d2bca94326edfb", + "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/a06db6b81ff20a2980bf92063d80c013bb8b4b7c", + "reference": "a06db6b81ff20a2980bf92063d80c013bb8b4b7c", "shasum": "" }, "require": { - "doctrine/data-fixtures": "^1.3", - "doctrine/doctrine-bundle": "^1.11|^2.0", - "doctrine/orm": "^2.6.0", - "doctrine/persistence": "^1.3.7|^2.0|^3.0", - "php": "^7.1 || ^8.0", - "symfony/config": "^3.4|^4.3|^5.0|^6.0", - "symfony/console": "^3.4|^4.3|^5.0|^6.0", - "symfony/dependency-injection": "^3.4.47|^4.3|^5.0|^6.0", - "symfony/doctrine-bridge": "^3.4|^4.1|^5.0|^6.0", - "symfony/http-kernel": "^3.4|^4.3|^5.0|^6.0" + "doctrine/data-fixtures": "^2.0", + "doctrine/doctrine-bundle": "^2.2", + "doctrine/orm": "^2.14.0 || ^3.0", + "doctrine/persistence": "^2.4 || ^3.0 || ^4.0", + "php": "^8.1", + "psr/log": "^2 || ^3", + "symfony/config": "^6.4 || ^7.0", + "symfony/console": "^6.4 || ^7.0", + "symfony/dependency-injection": "^6.4 || ^7.0", + "symfony/deprecation-contracts": "^2.1 || ^3", + "symfony/doctrine-bridge": "^6.4.16 || ^7.1.9", + "symfony/http-kernel": "^6.4 || ^7.0" + }, + "conflict": { + "doctrine/dbal": "< 3" }, "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "^1.4.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", - "symfony/phpunit-bridge": "^6.0.8", - "vimeo/psalm": "^4.22" + "doctrine/coding-standard": "13.0.0", + "phpstan/phpstan": "2.1.11", + "phpunit/phpunit": "^10.5.38 || 11.4.14" }, "type": "symfony-bundle", "autoload": { "psr-4": { - "Doctrine\\Bundle\\FixturesBundle\\": "" + "Doctrine\\Bundle\\FixturesBundle\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -14684,7 +15369,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues", - "source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/3.4.4" + "source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/4.1.0" }, "funding": [ { @@ -14700,43 +15385,43 @@ "type": "tidelift" } ], - "time": "2023-05-02T15:12:16+00:00" + "time": "2025-03-26T10:56:26+00:00" }, { "name": "ekino/phpstan-banned-code", - "version": "v1.0.0", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/ekino/phpstan-banned-code.git", - "reference": "4f0d7c8a0c9f5d222ffc24234aa6c5b3b71bf4c3" + "reference": "27122aa1783d6521e500c0c397c53244cfbde26f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ekino/phpstan-banned-code/zipball/4f0d7c8a0c9f5d222ffc24234aa6c5b3b71bf4c3", - "reference": "4f0d7c8a0c9f5d222ffc24234aa6c5b3b71bf4c3", + "url": "https://api.github.com/repos/ekino/phpstan-banned-code/zipball/27122aa1783d6521e500c0c397c53244cfbde26f", + "reference": "27122aa1783d6521e500c0c397c53244cfbde26f", "shasum": "" }, "require": { - "php": "^7.3 || ^8.0", - "phpstan/phpstan": "^1.0" + "php": "^8.1", + "phpstan/phpstan": "^2.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.6", "friendsofphp/php-cs-fixer": "^3.0", "nikic/php-parser": "^4.3", - "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpunit": "^9.5", "symfony/var-dumper": "^5.0" }, "type": "phpstan-extension", "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - }, "phpstan": { "includes": [ "extension.neon" ] + }, + "branch-alias": { + "dev-master": "1.0-dev" } }, "autoload": { @@ -14759,147 +15444,50 @@ "homepage": "https://github.com/ekino/phpstan-banned-code", "keywords": [ "PHPStan", - "code quality" + "code quality", + "static analysis" ], "support": { "issues": "https://github.com/ekino/phpstan-banned-code/issues", - "source": "https://github.com/ekino/phpstan-banned-code/tree/v1.0.0" + "source": "https://github.com/ekino/phpstan-banned-code/tree/v3.0.0" }, - "time": "2021-11-02T08:37:34+00:00" + "time": "2024-11-13T09:57:22+00:00" }, { - "name": "felixfbecker/advanced-json-rpc", - "version": "v3.2.1", + "name": "jbtronics/translation-editor-bundle", + "version": "v1.1.1", "source": { "type": "git", - "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", - "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447" + "url": "https://github.com/jbtronics/translation-editor-bundle.git", + "reference": "fa003c38f3f61060a368734b91aeb40d788b0825" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447", - "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447", + "url": "https://api.github.com/repos/jbtronics/translation-editor-bundle/zipball/fa003c38f3f61060a368734b91aeb40d788b0825", + "reference": "fa003c38f3f61060a368734b91aeb40d788b0825", "shasum": "" }, "require": { - "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "php": "^7.1 || ^8.0", - "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0" + "ext-json": "*", + "php": "^8.1", + "symfony/deprecation-contracts": "^3.4", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/translation": "^7.0|^6.4", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/twig-bundle": "^7.0|^6.4", + "symfony/web-profiler-bundle": "^7.0|^6.4" }, "require-dev": { - "phpunit/phpunit": "^7.0 || ^8.0" + "ekino/phpstan-banned-code": "^1.0", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-strict-rules": "^1.5", + "roave/security-advisories": "dev-latest" }, - "type": "library", + "type": "symfony-bundle", "autoload": { "psr-4": { - "AdvancedJsonRpc\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Felix Becker", - "email": "felix.b@outlook.com" - } - ], - "description": "A more advanced JSONRPC implementation", - "support": { - "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", - "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1" - }, - "time": "2021-06-11T22:34:44+00:00" - }, - { - "name": "felixfbecker/language-server-protocol", - "version": "v1.5.2", - "source": { - "type": "git", - "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpstan/phpstan": "*", - "squizlabs/php_codesniffer": "^3.1", - "vimeo/psalm": "^4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "LanguageServerProtocol\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Felix Becker", - "email": "felix.b@outlook.com" - } - ], - "description": "PHP classes for the Language Server Protocol", - "keywords": [ - "language", - "microsoft", - "php", - "server" - ], - "support": { - "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" - }, - "time": "2022-03-02T22:36:06+00:00" - }, - { - "name": "fidry/cpu-core-counter", - "version": "0.5.1", - "source": { - "type": "git", - "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/b58e5a3933e541dc286cc91fc4f3898bbc6f1623", - "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "fidry/makefile": "^0.2.0", - "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.9.2", - "phpstan/phpstan-deprecation-rules": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.2.2", - "phpstan/phpstan-strict-rules": "^1.4.4", - "phpunit/phpunit": "^9.5.26 || ^8.5.31", - "theofidry/php-cs-fixer-config": "^1.0", - "webmozarts/strict-phpunit": "^7.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Fidry\\CpuCoreCounter\\": "src/" + "Jbtronics\\TranslationEditorBundle\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -14908,96 +15496,287 @@ ], "authors": [ { - "name": "Théo FIDRY", - "email": "theo.fidry@gmail.com" + "name": "Jan Böhmer", + "email": "mail@jan-boehmer.de" } ], - "description": "Tiny utility to get the number of CPU cores.", + "description": "A symfony bundle to allow editing translations in the symfony profiler", "keywords": [ - "CPU", - "core" + "profiler", + "symfony", + "symfony-bundle", + "translations" ], "support": { - "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/0.5.1" + "issues": "https://github.com/jbtronics/translation-editor-bundle/issues", + "source": "https://github.com/jbtronics/translation-editor-bundle/tree/v1.1.1" }, "funding": [ { - "url": "https://github.com/theofidry", + "url": "https://www.paypal.me/do9jhb", + "type": "custom" + }, + { + "url": "https://github.com/jbtronics", "type": "github" } ], - "time": "2022-12-24T12:35:10+00:00" + "time": "2025-03-29T15:14:31+00:00" }, { - "name": "netresearch/jsonmapper", - "version": "v4.2.0", + "name": "myclabs/deep-copy", + "version": "1.13.1", "source": { "type": "git", - "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956" + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/f60565f8c0566a31acf06884cdaa591867ecc956", - "reference": "f60565f8c0566a31acf06884cdaa591867ecc956", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", "shasum": "" }, "require": { - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=7.1" + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { - "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", - "squizlabs/php_codesniffer": "~3.5" + "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": { - "psr-0": { - "JsonMapper": "src/" + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "OSL-3.0" + "MIT" ], - "authors": [ + "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.1" + }, + "funding": [ { - "name": "Christian Weiske", - "email": "cweiske@cweiske.de", - "homepage": "http://github.com/cweiske/jsonmapper/", - "role": "Developer" + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" } ], - "description": "Map nested JSON structures onto PHP classes", - "support": { - "email": "cweiske@cweiske.de", - "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.2.0" - }, - "time": "2023-04-09T17:37:40+00:00" + "time": "2025-04-29T12:36:36+00:00" }, { - "name": "phpstan/extension-installer", - "version": "1.3.1", + "name": "nikic/php-parser", + "version": "v5.4.0", "source": { "type": "git", - "url": "https://github.com/phpstan/extension-installer.git", - "reference": "f45734bfb9984c6c56c4486b71230355f066a58a" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/f45734bfb9984c6c56c4486b71230355f066a58a", - "reference": "f45734bfb9984c6c56c4486b71230355f066a58a", + "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/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", "shasum": "" }, "require": { "composer-plugin-api": "^2.0", "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.9.0" + "phpstan/phpstan": "^1.9.0 || ^2.0" }, "require-dev": { "composer/composer": "^2.0", @@ -15018,28 +15797,32 @@ "MIT" ], "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], "support": { "issues": "https://github.com/phpstan/extension-installer/issues", - "source": "https://github.com/phpstan/extension-installer/tree/1.3.1" + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" }, - "time": "2023-05-24T08:59:17+00:00" + "time": "2024-09-04T20:21:43+00:00" }, { "name": "phpstan/phpstan", - "version": "1.10.26", + "version": "2.1.16", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "5d660cbb7e1b89253a47147ae44044f49832351f" + "reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5d660cbb7e1b89253a47147ae44044f49832351f", - "reference": "5d660cbb7e1b89253a47147ae44044f49832351f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9", + "reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -15078,31 +15861,27 @@ { "url": "https://github.com/phpstan", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" } ], - "time": "2023-07-19T12:44:37+00:00" + "time": "2025-05-16T09:40:10+00:00" }, { "name": "phpstan/phpstan-doctrine", - "version": "1.3.40", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-doctrine.git", - "reference": "f741919a720af6f84249abc62befeb15eee7bc88" + "reference": "4497663eb17b9d29211830df5aceaa3a4d256a35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/f741919a720af6f84249abc62befeb15eee7bc88", - "reference": "f741919a720af6f84249abc62befeb15eee7bc88", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/4497663eb17b9d29211830df5aceaa3a4d256a35", + "reference": "4497663eb17b9d29211830df5aceaa3a4d256a35", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.10.12" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.13" }, "conflict": { "doctrine/collections": "<1.0", @@ -15112,24 +15891,26 @@ "doctrine/persistence": "<1.3" }, "require-dev": { + "cache/array-adapter": "^1.1", "composer/semver": "^3.3.2", - "doctrine/annotations": "^1.11.0", - "doctrine/collections": "^1.6", + "cweagans/composer-patches": "^1.7.3", + "doctrine/annotations": "^2.0", + "doctrine/collections": "^1.6 || ^2.1", "doctrine/common": "^2.7 || ^3.0", - "doctrine/dbal": "^2.13.8 || ^3.3.3", - "doctrine/lexer": "^1.2.1", - "doctrine/mongodb-odm": "^1.3 || ^2.1", - "doctrine/orm": "^2.11.0", - "doctrine/persistence": "^1.3.8 || ^2.2.1", + "doctrine/dbal": "^3.3.8", + "doctrine/lexer": "^2.0 || ^3.0", + "doctrine/mongodb-odm": "^2.4.3", + "doctrine/orm": "^2.16.0", + "doctrine/persistence": "^2.2.1 || ^3.2", "gedmo/doctrine-extensions": "^3.8", "nesbot/carbon": "^2.49", - "nikic/php-parser": "^4.13.2", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5.10", - "ramsey/uuid-doctrine": "^1.5.0", - "symfony/cache": "^4.4.35" + "phpstan/phpstan-deprecation-rules": "^2.0.2", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6.20", + "ramsey/uuid": "^4.2", + "symfony/cache": "^5.4" }, "type": "phpstan-extension", "extra": { @@ -15152,34 +15933,33 @@ "description": "Doctrine extensions for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-doctrine/issues", - "source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.40" + "source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.3" }, - "time": "2023-05-11T11:26:04+00:00" + "time": "2025-05-05T15:28:52+00:00" }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.5.1", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "b21c03d4f6f3a446e4311155f4be9d65048218e6" + "reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/b21c03d4f6f3a446e4311155f4be9d65048218e6", - "reference": "b21c03d4f6f3a446e4311155f4be9d65048218e6", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/3e139cbe67fafa3588e1dbe27ca50f31fdb6236a", + "reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.10" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0.4" }, "require-dev": { - "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-deprecation-rules": "^1.1", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -15201,39 +15981,38 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.1" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.4" }, - "time": "2023-03-29T14:47:40+00:00" + "time": "2025-03-18T11:42:40+00:00" }, { "name": "phpstan/phpstan-symfony", - "version": "1.3.2", + "version": "2.0.6", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "7332b90dfc291ac5b4b83fbca2081936faa1e3f9" + "reference": "5005288e07583546ea00b52de4a9ac412eb869d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/7332b90dfc291ac5b4b83fbca2081936faa1e3f9", - "reference": "7332b90dfc291ac5b4b83fbca2081936faa1e3f9", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/5005288e07583546ea00b52de4a9ac412eb869d7", + "reference": "5005288e07583546ea00b52de4a9ac412eb869d7", "shasum": "" }, "require": { "ext-simplexml": "*", - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.9.18" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.13" }, "conflict": { "symfony/framework-bundle": "<3.0" }, "require-dev": { - "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^8.5.29 || ^9.5", - "psr/container": "1.0 || 1.1.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "psr/container": "1.1.2", "symfony/config": "^5.4 || ^6.1", "symfony/console": "^5.4 || ^6.1", "symfony/dependency-injection": "^5.4 || ^6.1", @@ -15242,7 +16021,8 @@ "symfony/http-foundation": "^5.4 || ^6.1", "symfony/messenger": "^5.4", "symfony/polyfill-php80": "^1.24", - "symfony/serializer": "^5.4" + "symfony/serializer": "^5.4", + "symfony/service-contracts": "^2.2.0" }, "type": "phpstan-extension", "extra": { @@ -15272,92 +16052,457 @@ "description": "Symfony Framework extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/1.3.2" + "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.6" }, - "time": "2023-05-16T12:46:15+00:00" + "time": "2025-05-14T07:00:05+00:00" }, { - "name": "psalm/plugin-symfony", - "version": "v5.0.3", + "name": "phpunit/php-code-coverage", + "version": "9.2.32", "source": { "type": "git", - "url": "https://github.com/psalm/psalm-plugin-symfony.git", - "reference": "a6cef9c701686d17d4254b544d05345e9d3e0b88" + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/psalm/psalm-plugin-symfony/zipball/a6cef9c701686d17d4254b544d05345e9d3e0b88", - "reference": "a6cef9c701686d17d4254b544d05345e9d3e0b88", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { - "ext-simplexml": "*", - "php": "^7.4 || ^8.0", - "symfony/framework-bundle": "^5.0 || ^6.0", - "vimeo/psalm": "^5.1" + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.19.1 || ^5.1.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "doctrine/annotations": "^1.8|^2", - "doctrine/orm": "^2.9", - "phpunit/phpunit": "~7.5 || ~9.5", - "symfony/cache-contracts": "^1.0 || ^2.0", - "symfony/console": "*", - "symfony/form": "^5.0 || ^6.0", - "symfony/messenger": "^5.0 || ^6.0", - "symfony/security-guard": "*", - "symfony/serializer": "^5.0 || ^6.0", - "symfony/validator": "*", - "twig/twig": "^2.10 || ^3.0", - "weirdan/codeception-psalm-module": "dev-master" + "phpunit/phpunit": "^9.6" }, "suggest": { - "weirdan/doctrine-psalm-plugin": "If Doctrine is used, it is recommended install this plugin" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, - "type": "psalm-plugin", + "type": "library", "extra": { - "psalm": { - "pluginClass": "Psalm\\SymfonyPsalmPlugin\\Plugin" + "branch-alias": { + "dev-main": "9.2.x-dev" } }, "autoload": { - "psr-4": { - "Psalm\\SymfonyPsalmPlugin\\": "src" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Farhad Safarov", - "email": "farhad.safarov@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Psalm Plugin for Symfony", + "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/psalm/psalm-plugin-symfony/issues", - "source": "https://github.com/psalm/psalm-plugin-symfony/tree/v5.0.3" + "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/9.2.32" }, - "time": "2023-04-21T15:40:12+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-22T04:23:01+00:00" }, { - "name": "rector/rector", - "version": "0.17.7", + "name": "phpunit/php-file-iterator", + "version": "3.0.6", "source": { "type": "git", - "url": "https://github.com/rectorphp/rector.git", - "reference": "0e76101aa329911b7fec43106aac5843a978b209" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/0e76101aa329911b7fec43106aac5843a978b209", - "reference": "0e76101aa329911b7fec43106aac5843a978b209", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { - "php": "^7.2|^8.0", - "phpstan/phpstan": "^1.10.26" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "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", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-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/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.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/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.23", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.5.0 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-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/9.6.23" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-05-02T06:40:34+00:00" + }, + { + "name": "rector/rector", + "version": "2.0.16", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "f1366d1f8c7490541c8f7af6e5c7cef7cca1b5a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/f1366d1f8c7490541c8f7af6e5c7cef7cca1b5a2", + "reference": "f1366d1f8c7490541c8f7af6e5c7cef7cca1b5a2", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.14" }, "conflict": { "rector/rector-doctrine": "*", @@ -15365,15 +16510,13 @@ "rector/rector-phpunit": "*", "rector/rector-symfony": "*" }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, "bin": [ "bin/rector" ], "type": "library", - "extra": { - "branch-alias": { - "dev-main": "0.15-dev" - } - }, "autoload": { "files": [ "bootstrap.php" @@ -15392,7 +16535,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/0.17.7" + "source": "https://github.com/rectorphp/rector/tree/2.0.16" }, "funding": [ { @@ -15400,7 +16543,7 @@ "type": "github" } ], - "time": "2023-07-23T20:44:23+00:00" + "time": "2025-05-12T16:37:16+00:00" }, { "name": "roave/security-advisories", @@ -15408,199 +16551,298 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "69dafab8a5dffa4d6a4d6dab1ebadf48aca449c7" + "reference": "0cc529f6cf08a858fcb7a2c5617780fcdc20d1fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/69dafab8a5dffa4d6a4d6dab1ebadf48aca449c7", - "reference": "69dafab8a5dffa4d6a4d6dab1ebadf48aca449c7", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/0cc529f6cf08a858fcb7a2c5617780fcdc20d1fe", + "reference": "0cc529f6cf08a858fcb7a2c5617780fcdc20d1fe", "shasum": "" }, "conflict": { "3f/pygmentize": "<1.2", - "admidio/admidio": "<4.2.10", - "adodb/adodb-php": "<=5.20.20|>=5.21,<=5.21.3", + "adaptcms/adaptcms": "<=1.3", + "admidio/admidio": "<4.3.12", + "adodb/adodb-php": "<=5.22.8", "aheinze/cockpit": "<2.2", + "aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2", + "aimeos/ai-admin-jsonadm": "<2020.10.13|>=2021.04.1,<2021.10.6|>=2022.04.1,<2022.10.3|>=2023.04.1,<2023.10.4|==2024.04.1", + "aimeos/ai-client-html": ">=2020.04.1,<2020.10.27|>=2021.04.1,<2021.10.22|>=2022.04.1,<2022.10.13|>=2023.04.1,<2023.10.15|>=2024.04.1,<2024.04.7", + "aimeos/ai-controller-frontend": "<2020.10.15|>=2021.04.1,<2021.10.8|>=2022.04.1,<2022.10.8|>=2023.04.1,<2023.10.9|==2024.04.1", + "aimeos/aimeos-core": ">=2022.04.1,<2022.10.17|>=2023.04.1,<2023.10.17|>=2024.04.1,<2024.04.7", "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", + "airesvsg/acf-to-rest-api": "<=3.1", "akaunting/akaunting": "<2.1.13", "akeneo/pim-community-dev": "<5.0.119|>=6,<6.0.53", - "alextselegidis/easyappointments": "<1.5", + "alextselegidis/easyappointments": "<=1.5.1", "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", "amazing/media2click": ">=1,<1.3.3", + "ameos/ameos_tarteaucitron": "<1.2.23", "amphp/artax": "<1.0.6|>=2,<2.0.6", - "amphp/http": "<1.0.1", + "amphp/http": "<=1.7.2|>=2,<=2.1", "amphp/http-client": ">=4,<4.4", "anchorcms/anchor-cms": "<=0.12.7", "andreapollastri/cipi": "<=3.1.15", "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5", + "aoe/restler": "<1.7.1", + "apache-solr-for-typo3/solr": "<2.8.3", "apereo/phpcas": "<1.6", - "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6|>=2.6,<2.7.10|>=3,<3.0.12|>=3.1,<3.1.3", + "api-platform/core": "<3.4.17|>=4.0.0.0-alpha1,<4.0.22", + "api-platform/graphql": "<3.4.17|>=4.0.0.0-alpha1,<4.0.22", "appwrite/server-ce": "<=1.2.1", "arc/web": "<3", "area17/twill": "<1.2.5|>=2,<2.5.3", "artesaos/seotools": "<0.17.2", - "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", + "asymmetricrypt/asymmetricrypt": "<9.9.99", "athlon1600/php-proxy": "<=5.1", "athlon1600/php-proxy-app": "<=3", - "automad/automad": "<1.8", + "athlon1600/youtube-downloader": "<=4", + "austintoddj/canvas": "<=3.4.2", + "auth0/auth0-php": ">=8.0.0.0-beta1,<8.14", + "auth0/login": "<7.17", + "auth0/symfony": "<5.4", + "auth0/wordpress": "<5.3", + "automad/automad": "<2.0.0.0-alpha5", + "automattic/jetpack": "<9.8", "awesome-support/awesome-support": "<=6.0.7", - "aws/aws-sdk-php": ">=3,<3.2.1", + "aws/aws-sdk-php": "<3.288.1", "azuracast/azuracast": "<0.18.3", - "backdrop/backdrop": "<1.24.2", + "b13/seo_basics": "<0.8.2", + "backdrop/backdrop": "<1.27.3|>=1.28,<1.28.2", "backpack/crud": "<3.4.9", + "backpack/filemanager": "<2.0.2|>=3,<3.0.9", + "bacula-web/bacula-web": "<8.0.0.0-RC2-dev", "badaso/core": "<2.7", - "bagisto/bagisto": "<0.1.5", + "bagisto/bagisto": "<2.1", "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", "barryvdh/laravel-translation-manager": "<0.6.2", "barzahlen/barzahlen-php": "<2.0.1", - "baserproject/basercms": "<4.7.5", + "baserproject/basercms": "<=5.1.1", "bassjobsen/bootstrap-3-typeahead": ">4.0.2", + "bbpress/bbpress": "<2.6.5", + "bcosca/fatfree": "<3.7.2", + "bedita/bedita": "<4", + "bednee/cooluri": "<1.0.30", "bigfork/silverstripe-form-capture": ">=3,<3.1.1", - "billz/raspap-webgui": "<2.8.9", + "billz/raspap-webgui": "<=3.1.4", "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", + "blueimp/jquery-file-upload": "==6.4.4", "bmarshall511/wordpress_zero_spam": "<5.2.13", "bolt/bolt": "<3.7.2", "bolt/core": "<=4.2", + "born05/craft-twofactorauthentication": "<3.3.4", "bottelet/flarepoint": "<2.2.1", + "bref/bref": "<2.1.17", "brightlocal/phpwhois": "<=4.2.5", "brotkrueml/codehighlight": "<2.7", "brotkrueml/schema": "<1.13.1|>=2,<2.5.1", "brotkrueml/typo3-matomo-integration": "<1.3.2", "buddypress/buddypress": "<7.2.1", "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "bvbmedia/multishop": "<2.0.39", "bytefury/crater": "<6.0.2", "cachethq/cachet": "<2.5.1", - "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10|= 1.3.7|>=4.1,<4.1.4", + "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.1,<4.1.4|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", "cardgate/magento2": "<2.0.33", "cardgate/woocommerce": "<=3.1.15", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", + "cart2quote/module-quotation-encoded": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "catfan/medoo": "<1.7.5", - "centreon/centreon": "<22.10-beta.1", + "causal/oidc": "<4", + "cecil/cecil": "<7.47.1", + "centreon/centreon": "<22.10.15", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "cockpit-hq/cockpit": "<2.6", + "chriskacerguis/codeigniter-restserver": "<=2.7.1", + "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", + "ckeditor/ckeditor": "<4.25", + "clickstorm/cs-seo": ">=6,<6.7|>=7,<7.4|>=8,<8.3|>=9,<9.2", + "co-stack/fal_sftp": "<0.2.6", + "cockpit-hq/cockpit": "<2.7|==2.7", "codeception/codeception": "<3.1.3|>=4,<4.1.22", - "codeigniter/framework": "<=3.0.6", - "codeigniter4/framework": "<4.3.5", - "codeigniter4/shield": "<1-beta.4|= 1.0.0-beta", + "codeigniter/framework": "<3.1.9", + "codeigniter4/framework": "<4.5.8", + "codeigniter4/shield": "<1.0.0.0-beta8", "codiad/codiad": "<=2.8.4", - "composer/composer": "<1.10.26|>=2-alpha.1,<2.2.12|>=2.3,<2.3.5", - "concrete5/concrete5": "<9.2|>= 9.0.0RC1, < 9.1.3", + "codingms/additional-tca": ">=1.7,<1.15.17|>=1.16,<1.16.9", + "commerceteam/commerce": ">=0.9.6,<0.9.9", + "components/jquery": ">=1.0.3,<3.5", + "composer/composer": "<1.10.27|>=2,<2.2.24|>=2.3,<2.7.7", + "concrete5/concrete5": "<9.4.0.0-RC2-dev", "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/contao": ">=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4", - "contao/core": ">=2,<3.5.39", - "contao/core-bundle": "<4.9.42|>=4.10,<4.13.28|>=5,<5.1.10|= 4.10.0", - "contao/listing-bundle": ">=4,<4.4.8", + "contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4", + "contao/contao": ">=3,<3.5.37|>=4,<4.4.56|>=4.5,<4.9.40|>=4.10,<4.11.7|>=4.13,<4.13.21|>=5.1,<5.1.4", + "contao/core": "<3.5.39", + "contao/core-bundle": "<4.13.54|>=5,<5.3.30|>=5.4,<5.5.6", + "contao/listing-bundle": ">=3,<=3.5.30|>=4,<4.4.8", "contao/managed-edition": "<=1.5", + "corveda/phpsandbox": "<1.3.5", "cosenary/instagram": "<=2.3", - "craftcms/cms": "<=4.4.9|>= 4.0.0-RC1, < 4.4.12|>= 4.0.0-RC1, <= 4.4.5|>= 4.0.0-RC1, <= 4.4.6|>= 4.0.0-RC1, < 4.4.6|>= 4.0.0-RC1, < 4.3.7|>= 4.0.0-RC1, < 4.2.1", - "croogo/croogo": "<3.0.7", + "craftcms/cms": "<4.15.3|>=5,<5.7.5", + "croogo/croogo": "<4", "cuyz/valinor": "<0.12", + "czim/file-handling": "<1.5|>=2,<2.3", "czproject/git-php": "<4.0.3", + "damienharper/auditor-bundle": "<5.2.6", + "dapphp/securimage": "<3.6.6", "darylldoyle/safe-svg": "<1.9.10", "datadog/dd-trace": ">=0.30,<0.30.2", + "datatables/datatables": "<1.10.10", "david-garcia/phpwhois": "<=4.3.1", "dbrisinajumi/d2files": "<1", - "dcat/laravel-admin": "<=2.1.3-beta", + "dcat/laravel-admin": "<=2.1.3|==2.2.0.0-beta|==2.2.2.0-beta", "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", - "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", + "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1|>=7,<7.4", "desperado/xml-bundle": "<=0.1.7", - "directmailteam/direct-mail": "<5.2.4", - "doctrine/annotations": ">=1,<1.2.7", + "dev-lancer/minecraft-motd-parser": "<=1.0.5", + "devgroup/dotplant": "<2020.09.14-dev", + "digimix/wp-svg-upload": "<=1", + "directmailteam/direct-mail": "<6.0.3|>=7,<7.0.3|>=8,<9.5.2", + "dl/yag": "<3.0.1", + "dmk/webkitpdf": "<1.1.4", + "dnadesign/silverstripe-elemental": "<5.3.12", + "doctrine/annotations": "<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", + "doctrine/common": "<2.4.3|>=2.5,<2.5.1", "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2|>=3,<3.1.4", "doctrine/doctrine-bundle": "<1.5.2", - "doctrine/doctrine-module": "<=0.7.1", - "doctrine/mongodb-odm": ">=1,<1.0.2", - "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", - "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<17.0.1|= 12.0.5|>= 3.3.beta1, < 13.0.2", - "dompdf/dompdf": "<2.0.2|= 2.0.2", - "drupal/core": ">=7,<7.96|>=8,<9.4.14|>=9.5,<9.5.8|>=10,<10.0.8", - "drupal/drupal": ">=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", + "doctrine/doctrine-module": "<0.7.2", + "doctrine/mongodb-odm": "<1.0.2", + "doctrine/mongodb-odm-bundle": "<3.0.1", + "doctrine/orm": ">=1,<1.2.4|>=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", + "dolibarr/dolibarr": "<19.0.2|==21.0.0.0-beta", + "dompdf/dompdf": "<2.0.4", + "doublethreedigital/guest-entries": "<3.1.2", + "drupal/ai": "<1.0.5", + "drupal/alogin": "<2.0.6", + "drupal/cache_utility": "<1.2.1", + "drupal/config_split": "<1.10|>=2,<2.0.2", + "drupal/core": ">=6,<6.38|>=7,<7.102|>=8,<10.3.14|>=10.4,<10.4.5|>=11,<11.0.13|>=11.1,<11.1.5", + "drupal/core-recommended": ">=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", + "drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", + "drupal/formatter_suite": "<2.1", + "drupal/gdpr": "<3.0.1|>=3.1,<3.1.2", + "drupal/google_tag": "<1.8|>=2,<2.0.8", + "drupal/ignition": "<1.0.4", + "drupal/link_field_display_mode_formatter": "<1.6", + "drupal/matomo": "<1.24", + "drupal/oauth2_client": "<4.1.3", + "drupal/oauth2_server": "<2.1", + "drupal/obfuscate": "<2.0.1", + "drupal/rapidoc_elements_field_formatter": "<1.0.1", + "drupal/spamspan": "<3.2.1", + "drupal/tfa": "<1.10", + "duncanmcclean/guest-entries": "<3.1.2", "dweeves/magmi": "<=0.7.24", + "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.1.2", "ecodev/newsletter": "<=4", "ectouch/ectouch": "<=2.7.2", - "elefant/cms": "<1.3.13", + "egroupware/egroupware": "<23.1.20240624", + "elefant/cms": "<2.0.7", "elgg/elgg": "<3.3.24|>=4,<4.0.5", + "elijaa/phpmemcacheadmin": "<=1.3", "encore/laravel-admin": "<=1.8.19", "endroid/qr-code-bundle": "<3.4.2", + "enhavo/enhavo-app": "<=0.13.1", "enshrined/svg-sanitize": "<0.15", "erusev/parsedown": "<1.7.2", "ether/logs": "<3.0.4", + "evolutioncms/evolution": "<=3.2.3", "exceedone/exment": "<4.4.3|>=5,<5.0.3", - "exceedone/laravel-admin": "= 3.0.0|<2.2.3", - "ezsystems/demobundle": ">=5.4,<5.4.6.1", + "exceedone/laravel-admin": "<2.2.3|==3", + "ezsystems/demobundle": ">=5.4,<5.4.6.1-dev", "ezsystems/ez-support-tools": ">=2.2,<2.2.3", - "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", - "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", + "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1-dev", + "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1-dev|>=5.4,<5.4.11.1-dev|>=2017.12,<2017.12.0.1-dev", "ezsystems/ezplatform": "<=1.13.6|>=2,<=2.5.24", - "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<1.5.29|>=2.3,<2.3.26", + "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<1.5.29|>=2.3,<2.3.26|>=3.3,<3.3.39", "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", - "ezsystems/ezplatform-graphql": ">=1-rc.1,<1.0.13|>=2-beta.1,<2.3.12", - "ezsystems/ezplatform-kernel": "<1.2.5.1|>=1.3,<1.3.26", + "ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12", + "ezsystems/ezplatform-http-cache": "<2.3.16", + "ezsystems/ezplatform-kernel": "<1.2.5.1-dev|>=1.3,<1.3.35", "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", - "ezsystems/ezplatform-richtext": ">=2.3,<2.3.7.1", + "ezsystems/ezplatform-richtext": ">=2.3,<2.3.26|>=3.3,<3.3.40", + "ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15", "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": "<6.13.8.2|>=7,<7.5.30", - "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.3.5.1", + "ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.31", + "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.03.5.1", "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1|>=2.5,<2.5.15", - "ezyang/htmlpurifier": "<4.1.1", + "ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15", + "ezyang/htmlpurifier": "<=4.2", "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", - "facturascripts/facturascripts": "<=2022.8", + "facturascripts/facturascripts": "<=2022.08", + "fastly/magento2": "<1.2.26", "feehi/cms": "<=2.1.1", "feehi/feehicms": "<=2.1.1", "fenom/fenom": "<=2.12.1", + "filament/actions": ">=3.2,<3.2.123", + "filament/infolists": ">=3,<3.2.115", + "filament/tables": ">=3,<3.2.115", "filegator/filegator": "<7.8", + "filp/whoops": "<2.1.13", + "fineuploader/php-traditional-server": "<=1.2.2", "firebase/php-jwt": "<6", + "fisharebest/webtrees": "<=2.1.18", "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", - "fixpunkt/fp-newsletter": "<1.1.1|>=2,<2.1.2|>=2.2,<3.2.6", - "flarum/core": "<1.7", - "flarum/framework": "<=0.1-beta.7.1", + "fixpunkt/fp-newsletter": "<1.1.1|>=1.2,<2.1.2|>=2.2,<3.2.6", + "flarum/core": "<1.8.10", + "flarum/flarum": "<0.1.0.0-beta8", + "flarum/framework": "<1.8.10", "flarum/mentions": "<1.6.3", - "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", - "flarum/tags": "<=0.1-beta.13", + "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", + "flarum/tags": "<=0.1.0.0-beta13", + "floriangaerber/magnesium": "<0.3.1", "fluidtypo3/vhs": "<5.1.1", - "fof/byobu": ">=0.3-beta.2,<1.1.7", + "fof/byobu": ">=0.3.0.0-beta2,<1.1.7", "fof/upload": "<1.2.3", + "foodcoopshop/foodcoopshop": ">=3.2,<3.6.1", "fooman/tcpdf": "<6.2.22", "forkcms/forkcms": "<5.11.1", "fossar/tcpdf-parser": "<6.2.22", - "francoisjacquet/rosariosis": "<11", + "francoisjacquet/rosariosis": "<=11.5.1", "frappant/frp-form-answers": "<3.1.2|>=4,<4.0.2", "friendsofsymfony/oauth2-php": "<1.3", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "friendsofsymfony/user-bundle": ">=1,<1.3.5", + "friendsofsymfony1/swiftmailer": ">=4,<5.4.13|>=6,<6.2.5", + "friendsofsymfony1/symfony1": ">=1.1,<1.5.19", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", - "froala/wysiwyg-editor": "<3.2.7", - "froxlor/froxlor": "<2.1", + "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", + "froala/wysiwyg-editor": "<=4.3", + "froxlor/froxlor": "<=2.2.5", + "frozennode/administrator": "<=5.0.12", "fuel/core": "<1.8.1", - "funadmin/funadmin": "<=3.2|>=3.3.2,<=3.3.3", + "funadmin/funadmin": "<=5.0.2", "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", - "getgrav/grav": "<=1.7.42.1", - "getkirby/cms": "= 3.8.0|<3.5.8.2|>=3.6,<3.6.6.2|>=3.7,<3.7.5.1", - "getkirby/kirby": "<=2.5.12", + "georgringer/news": "<1.3.3", + "geshi/geshi": "<1.0.8.11-dev", + "getformwork/formwork": "<1.13.1|>=2.0.0.0-beta1,<2.0.0.0-beta4", + "getgrav/grav": "<1.7.46", + "getkirby/cms": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", + "getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", "getkirby/panel": "<2.5.14", "getkirby/starterkit": "<=3.7.0.2", - "gilacms/gila": "<=1.11.4", + "gilacms/gila": "<=1.15.4", + "gleez/cms": "<=1.3|==2", "globalpayments/php-sdk": "<2", + "goalgorilla/open_social": "<12.3.11|>=12.4,<12.4.10|>=13.0.0.0-alpha1,<13.0.0.0-alpha11", "gogentooss/samlbase": "<1.2.7", "google/protobuf": "<3.15", "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", "gree/jose": "<2.2.1", "gregwar/rst": "<1.0.3", - "grumpydictator/firefly-iii": "<6", + "grumpydictator/firefly-iii": "<6.1.17", + "gugoan/economizzer": "<=0.9.0.0-beta1", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", + "guzzlehttp/oauth-subscriber": "<0.8.1", "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", "harvesthq/chosen": "<1.8.7", - "helloxz/imgurl": "= 2.31|<=2.31", + "helloxz/imgurl": "<=2.31", "hhxsv5/laravel-s": "<3.7.36", "hillelcoren/invoice-ninja": "<5.3.35", "himiklab/yii2-jqgrid-widget": "<1.0.8", @@ -15608,269 +16850,397 @@ "hov/jobfair": "<1.0.13|>=2,<2.0.2", "httpsoft/http-message": "<1.0.12", "hyn/multi-tenant": ">=5.6,<5.7.2", - "ibexa/admin-ui": ">=4.2,<4.2.3", - "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3", + "ibexa/admin-ui": ">=4.2,<4.2.3|>=4.6,<4.6.14", + "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3|>=4.5,<4.5.6|>=4.6,<4.6.2", + "ibexa/fieldtype-richtext": ">=4.6,<4.6.19", "ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3", - "ibexa/post-install": "<=1.0.4", + "ibexa/http-cache": ">=4.6,<4.6.14", + "ibexa/post-install": "<1.0.16|>=4.6,<4.6.14", + "ibexa/solr": ">=4.5,<4.5.4", "ibexa/user": ">=4,<4.4.3", "icecoder/icecoder": "<=8.1", "idno/known": "<=1.3.1", - "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", - "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", + "ilicmiljan/secure-props": ">=1.2,<1.2.2", + "illuminate/auth": "<5.5.10", + "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<6.18.31|>=7,<7.22.4", "illuminate/database": "<6.20.26|>=7,<7.30.5|>=8,<8.40", "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", + "imdbphp/imdbphp": "<=5.1.1", "impresscms/impresscms": "<=1.4.5", - "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.1", + "impresspages/impresspages": "<1.0.13", + "in2code/femanager": "<5.5.3|>=6,<6.3.4|>=7,<7.2.3", "in2code/ipandlanguageredirect": "<5.1.2", "in2code/lux": "<17.6.1|>=18,<24.0.2", + "in2code/powermail": "<7.5.1|>=8,<8.5.1|>=9,<10.9.1|>=11,<12.4.1", "innologi/typo3-appointments": "<2.0.6", - "intelliants/subrion": "<=4.2.1", + "intelliants/subrion": "<4.2.2", + "inter-mediator/inter-mediator": "==5.5", + "ipl/web": "<0.10.1", + "islandora/crayfish": "<4.1", "islandora/islandora": ">=2,<2.4.1", "ivankristianto/phpwhois": "<=4.3", "jackalope/jackalope-doctrine-dbal": "<1.7.4", + "jambagecom/div2007": "<0.10.2", "james-heinrich/getid3": "<1.9.21", + "james-heinrich/phpthumb": "<1.7.12", "jasig/phpcas": "<1.3.3", + "jbartels/wec-map": "<3.0.3", + "jcbrand/converse.js": "<3.3.3", + "joelbutcher/socialstream": "<5.6|>=6,<6.2", + "johnbillion/wp-crontrol": "<1.16.2", + "joomla/application": "<1.0.13", "joomla/archive": "<1.1.12|>=2,<2.0.1", + "joomla/database": ">=1,<2.2|>=3,<3.4", "joomla/filesystem": "<1.6.2|>=2,<2.0.1", "joomla/filter": "<1.4.4|>=2,<2.0.1", - "joomla/framework": ">=2.5.4,<=3.8.12", + "joomla/framework": "<1.5.7|>=2.5.4,<=3.8.12", "joomla/input": ">=2,<2.0.2", - "joomla/joomla-cms": ">=3,<3.9.12", + "joomla/joomla-cms": "<3.9.12|>=4,<4.4.13|>=5,<5.2.6", + "joomla/joomla-platform": "<1.5.4", "joomla/session": "<1.3.1", "joyqi/hyper-down": "<=2.4.27", "jsdecena/laracom": "<2.0.9", "jsmitty12/phpwhois": "<5.1", + "juzaweb/cms": "<=3.4", + "jweiland/events2": "<8.3.8|>=9,<9.0.6", + "jweiland/kk-downloader": "<1.2.2", "kazist/phpwhois": "<=4.2.6", "kelvinmo/simplexrd": "<3.1.1", "kevinpapst/kimai2": "<1.16.7", "khodakhah/nodcms": "<=3", - "kimai/kimai": "<1.1", + "kimai/kimai": "<=2.20.1", "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "klaviyo/magento2-extension": ">=1,<3", - "knplabs/knp-snappy": "<1.4.2", - "krayin/laravel-crm": "<1.2.2", + "knplabs/knp-snappy": "<=1.4.2", + "kohana/core": "<3.3.3", + "koillection/koillection": "<1.6.12", + "krayin/laravel-crm": "<=1.3", "kreait/firebase-php": ">=3.2,<3.8.1", + "kumbiaphp/kumbiapp": "<=1.1.1", "la-haute-societe/tcpdf": "<6.2.22", - "laminas/laminas-diactoros": "<2.18.1|>=2.24,<2.24.2|>=2.25,<2.25.2|= 2.23.0|= 2.22.0|= 2.21.0|= 2.20.0|= 2.19.0", + "laminas/laminas-diactoros": "<2.18.1|==2.19|==2.20|==2.21|==2.22|==2.23|>=2.24,<2.24.2|>=2.25,<2.25.2", "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", "laminas/laminas-http": "<2.14.2", + "lara-zeus/artemis": ">=1,<=1.0.6", + "lara-zeus/dynamic-dashboard": ">=3,<=3.0.1", "laravel/fortify": "<1.11.1", - "laravel/framework": "<6.20.44|>=7,<7.30.6|>=8,<8.75", - "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", + "laravel/framework": "<10.48.29|>=11,<11.44.1|>=12,<12.1.1", + "laravel/laravel": ">=5.4,<5.4.22", + "laravel/pulse": "<1.3.1", + "laravel/reverb": "<1.4", + "laravel/socialite": ">=1,<2.0.10", "latte/latte": "<2.10.8", - "lavalite/cms": "= 9.0.0|<=9", + "lavalite/cms": "<=9|==10.1", "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", - "league/commonmark": "<0.18.3", + "league/commonmark": "<2.7", "league/flysystem": "<1.1.4|>=2,<2.1.1", - "league/oauth2-server": ">=8.3.2,<8.5.3", + "league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3", + "leantime/leantime": "<3.3", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", - "librenms/librenms": "<22.10", + "libreform/libreform": ">=2,<=2.0.8", + "librenms/librenms": "<2017.08.18", "liftkit/database": "<2.13.2", - "limesurvey/limesurvey": "<3.27.19", + "lightsaml/lightsaml": "<1.3.5", + "limesurvey/limesurvey": "<6.5.12", "livehelperchat/livehelperchat": "<=3.91", - "livewire/livewire": ">2.2.4,<2.2.6", + "livewire/livewire": "<2.12.7|>=3.0.0.0-beta1,<3.5.2", + "livewire/volt": "<1.7", "lms/routes": "<2.1.1", "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", + "luracast/restler": "<3.1", "luyadev/yii-helpers": "<1.2.1", - "magento/community-edition": "= 2.4.0|<=2.4", - "magento/magento1ce": "<1.9.4.3", - "magento/magento1ee": ">=1,<1.14.4.3", - "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", + "macropay-solutions/laravel-crud-wizard-free": "<3.4.17", + "maestroerror/php-heic-to-jpg": "<1.0.5", + "magento/community-edition": "<2.4.5|==2.4.5|>=2.4.5.0-patch1,<2.4.5.0-patch12|==2.4.6|>=2.4.6.0-patch1,<2.4.6.0-patch10|>=2.4.7.0-beta1,<2.4.7.0-patch5|>=2.4.8.0-beta1,<2.4.8.0-beta2", + "magento/core": "<=1.9.4.5", + "magento/magento1ce": "<1.9.4.3-dev", + "magento/magento1ee": ">=1,<1.14.4.3-dev", + "magento/product-community-edition": "<2.4.4.0-patch9|>=2.4.5,<2.4.5.0-patch8|>=2.4.6,<2.4.6.0-patch6|>=2.4.7,<2.4.7.0-patch1", + "magento/project-community-edition": "<=2.0.2", + "magneto/core": "<1.9.4.4-dev", "maikuolan/phpmussel": ">=1,<1.6", - "mantisbt/mantisbt": "<=2.25.5", + "mainwp/mainwp": "<=4.4.3.3", + "mantisbt/mantisbt": "<=2.26.3", "marcwillmann/turn": "<0.3.3", + "matomo/matomo": "<1.11", "matyhtf/framework": "<3.0.6", - "mautic/core": "<4.3|= 2.13.1", - "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", + "mautic/core": "<5.2.3", + "mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1", + "maximebf/debugbar": "<1.19", + "mdanter/ecc": "<2", + "mediawiki/abuse-filter": "<1.39.9|>=1.40,<1.41.3|>=1.42,<1.42.2", + "mediawiki/cargo": "<3.6.1", + "mediawiki/core": "<1.39.5|==1.40", + "mediawiki/data-transfer": ">=1.39,<1.39.11|>=1.41,<1.41.3|>=1.42,<1.42.2", "mediawiki/matomo": "<2.4.3", + "mediawiki/semantic-media-wiki": "<4.0.2", + "mehrwert/phpmyadmin": "<3.2", "melisplatform/melis-asset-manager": "<5.0.1", "melisplatform/melis-cms": "<5.0.1", "melisplatform/melis-front": "<5.0.1", "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", "mgallegos/laravel-jqgrid": "<=1.3", - "microweber/microweber": "<=1.3.4|= 1.1.18", + "microsoft/microsoft-graph": ">=1.16,<1.109.1|>=2,<2.0.1", + "microsoft/microsoft-graph-beta": "<2.0.1", + "microsoft/microsoft-graph-core": "<2.0.2", + "microweber/microweber": "<=2.0.16", + "mikehaertl/php-shellcommand": "<1.6.1", "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", "mobiledetect/mobiledetectlib": "<2.8.32", - "modx/revolution": "<2.8|<= 2.8.3-pl", + "modx/revolution": "<=3.1", "mojo42/jirafeau": "<4.4", + "mongodb/mongodb": ">=1,<1.9.2", "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.2-rc.2|= 3.4.3|= 3.5|= 3.7|= 3.9|= 3.8|= 4.2.0|= 3.11", + "moodle/moodle": "<4.3.12|>=4.4,<4.4.8|>=4.5.0.0-beta,<4.5.4", + "mos/cimage": "<0.7.19", "movim/moxl": ">=0.8,<=0.10", + "movingbytes/social-network": "<=1.2.1", "mpdf/mpdf": "<=7.1.7", + "munkireport/comment": "<4.1", + "munkireport/managedinstalls": "<2.6", + "munkireport/munki_facts": "<1.5", + "munkireport/munkireport": ">=2.5.3,<5.6.3", + "munkireport/reportdata": "<3.5", + "munkireport/softwareupdate": "<1.6", "mustache/mustache": ">=2,<2.14.1", + "mwdelaney/wp-enable-svg": "<=0.2", "namshi/jose": "<2.2", + "nasirkhan/laravel-starter": "<11.11", + "nategood/httpful": "<1", "neoan3-apps/template": "<1.1.1", - "neorazorx/facturascripts": "<2022.4", + "neorazorx/facturascripts": "<2022.04", "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", - "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", - "neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", + "neos/media-browser": "<7.3.19|>=8,<8.0.16|>=8.1,<8.1.11|>=8.2,<8.2.11|>=8.3,<8.3.9", + "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", + "neos/swiftmailer": "<5.4.5", + "nesbot/carbon": "<2.72.6|>=3,<3.8.4", + "netcarver/textile": "<=4.1.2", "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "nilsteampassnet/teampass": "<3.0.10", + "nilsteampassnet/teampass": "<3.1.3.1-dev", + "nonfiction/nterchange": "<4.1.1", "notrinos/notrinos-erp": "<=0.7", "noumo/easyii": "<=0.9", - "nukeviet/nukeviet": "<4.5.2", + "novaksolutions/infusionsoft-php-sdk": "<1", + "nukeviet/nukeviet": "<4.5.02", "nyholm/psr7": "<1.6.1", "nystudio107/craft-seomatic": "<3.4.12", + "nzedb/nzedb": "<0.8", "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", "october/backend": "<1.1.2", - "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", - "october/october": "<1.0.466|>=2.1,<2.1.12", + "october/cms": "<1.0.469|==1.0.469|==1.0.471|==1.1.1", + "october/october": "<3.7.5", "october/rain": "<1.0.472|>=1.1,<1.1.2", - "october/system": "<1.0.476|>=1.1,<1.1.12|>=2,<2.2.34|>=3,<3.0.66", + "october/system": "<3.7.5", + "oliverklee/phpunit": "<3.5.15", + "omeka/omeka-s": "<4.0.3", "onelogin/php-saml": "<2.10.4", - "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", + "oneup/uploader-bundle": ">=1,<1.9.3|>=2,<2.1.5", "open-web-analytics/open-web-analytics": "<1.7.4", - "opencart/opencart": "<=3.0.3.7", + "opencart/opencart": ">=0", "openid/php-openid": "<2.3", - "openmage/magento-lts": "<19.4.22|>=20,<20.0.19", - "opensource-workshop/connect-cms": "<1.7.2|>=2,<2.3.2", - "orchid/platform": ">=9,<9.4.4|>=14-alpha.4,<14.5", - "oro/commerce": ">=4.1,<5.0.6", + "openmage/magento-lts": "<20.12.3", + "opensolutions/vimbadmin": "<=3.0.15", + "opensource-workshop/connect-cms": "<1.8.7|>=2,<2.4.7", + "orchid/platform": ">=8,<14.43", + "oro/calendar-bundle": ">=4.2,<=4.2.6|>=5,<=5.0.6|>=5.1,<5.1.1", + "oro/commerce": ">=4.1,<5.0.11|>=5.1,<5.1.1", "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", - "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<4.2.8", + "oro/crm-call-bundle": ">=4.2,<=4.2.5|>=5,<5.0.4|>=5.1,<5.1.1", + "oro/customer-portal": ">=4.1,<=4.1.13|>=4.2,<=4.2.10|>=5,<=5.0.11|>=5.1,<=5.1.3", + "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<=4.2.10|>=5,<=5.0.12|>=5.1,<=5.1.3", + "oveleon/contao-cookiebar": "<1.16.3|>=2,<2.1.3", + "oxid-esales/oxideshop-ce": "<=7.0.5", + "oxid-esales/paymorrow-module": ">=1,<1.0.2|>=2,<2.0.1", "packbackbooks/lti-1-3-php-library": "<5", "padraic/humbug_get_contents": "<1.1.2", - "pagarme/pagarme-php": ">=0,<3", + "pagarme/pagarme-php": "<3", "pagekit/pagekit": "<=1.0.18", + "paragonie/ecc": "<2.0.1", "paragonie/random_compat": "<2", - "passbolt/passbolt_api": "<2.11", + "passbolt/passbolt_api": "<4.6.2", + "paypal/adaptivepayments-sdk-php": "<=3.9.2", + "paypal/invoice-sdk-php": "<=3.9", "paypal/merchant-sdk-php": "<3.12", + "paypal/permissions-sdk-php": "<=3.9.1", "pear/archive_tar": "<1.4.14", + "pear/auth": "<1.2.4", "pear/crypt_gpg": "<1.6.7", + "pear/http_request2": "<2.7", "pear/pear": "<=1.10.1", "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", "personnummer/personnummer": "<3.0.2", "phanan/koel": "<5.1.4", + "phenx/php-svg-lib": "<0.5.2", + "php-censor/php-censor": "<2.0.13|>=2.1,<2.1.5", "php-mod/curl": "<2.3.2", - "phpbb/phpbb": "<3.2.10|>=3.3,<3.3.1", + "phpbb/phpbb": "<3.3.11", + "phpems/phpems": ">=6,<=6.1.3", "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", - "phpmyadmin/phpmyadmin": "<5.2.1", - "phpmyfaq/phpmyfaq": "<=3.1.7", - "phpoffice/phpexcel": "<1.8", - "phpoffice/phpspreadsheet": "<1.16", - "phpseclib/phpseclib": "<2.0.31|>=3,<3.0.19", + "phpmyadmin/phpmyadmin": "<5.2.2", + "phpmyfaq/phpmyfaq": "<3.2.5|==3.2.5|>=3.2.10,<=4.0.1", + "phpoffice/common": "<0.2.9", + "phpoffice/phpexcel": "<=1.8.2", + "phpoffice/phpspreadsheet": "<1.29.9|>=2,<2.1.8|>=2.2,<2.3.7|>=3,<3.9", + "phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36", "phpservermon/phpservermon": "<3.6", - "phpsysinfo/phpsysinfo": "<3.2.5", - "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5,<5.6.3", + "phpsysinfo/phpsysinfo": "<3.4.3", + "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "phpxmlrpc/phpxmlrpc": "<4.9.2", "pi/pi": "<=2.5", - "pimcore/admin-ui-classic-bundle": "<1.0.3", - "pimcore/customer-management-framework-bundle": "<3.4.1", + "pimcore/admin-ui-classic-bundle": "<1.7.6", + "pimcore/customer-management-framework-bundle": "<4.2.1", "pimcore/data-hub": "<1.2.4", + "pimcore/data-importer": "<1.8.9|>=1.9,<1.9.3", + "pimcore/demo": "<10.3", + "pimcore/ecommerce-framework-bundle": "<1.0.10", "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<10.6.4", - "pixelfed/pixelfed": "<=0.11.4", + "pimcore/pimcore": "<11.5.4", + "piwik/piwik": "<1.11", + "pixelfed/pixelfed": "<0.12.5", + "plotly/plotly.js": "<2.25.2", "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": "<4.22.3|>=5,<5.2.1|< 4.18.0-ALPHA2|>= 4.0.0-BETA5, < 4.4.2", + "pocketmine/pocketmine-mp": "<5.25.2", + "pocketmine/raklib": ">=0.14,<0.14.6|>=0.15,<0.15.1", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", + "prestashop/blockreassurance": "<=5.1.3", "prestashop/blockwishlist": ">=2,<2.1.1", "prestashop/contactform": ">=1.0.1,<4.3", "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": "<8.0.4", + "prestashop/prestashop": "<8.1.6", "prestashop/productcomments": "<5.0.2", + "prestashop/ps_contactinfo": "<=3.3.2", "prestashop/ps_emailsubscription": "<2.6.1", "prestashop/ps_facetedsearch": "<3.4.1", "prestashop/ps_linklist": "<3.1", - "privatebin/privatebin": "<1.4", - "processwire/processwire": "<=3.0.200", - "propel/propel": ">=2-alpha.1,<=2-alpha.7", + "privatebin/privatebin": "<1.4|>=1.5,<1.7.4", + "processwire/processwire": "<=3.0.229", + "propel/propel": ">=2.0.0.0-alpha1,<=2.0.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", - "pterodactyl/panel": "<1.7", + "pterodactyl/panel": "<1.11.8", + "ptheofan/yii2-statemachine": ">=2.0.0.0-RC1-dev,<=2", "ptrofimov/beanstalk_console": "<1.7.14", + "pubnub/pubnub": "<6.1", + "punktde/pt_extbase": "<1.5.1", "pusher/pusher-php-server": "<2.2.1", - "pwweb/laravel-core": "<=0.3.6-beta", + "pwweb/laravel-core": "<=0.3.6.0-beta", + "pxlrbt/filament-excel": "<1.1.14|>=2.0.0.0-alpha,<2.3.3", "pyrocms/pyrocms": "<=3.9.1", + "qcubed/qcubed": "<=3.1.1", + "quickapps/cms": "<=2.0.0.0-beta2", + "rainlab/blog-plugin": "<1.4.1", "rainlab/debugbar-plugin": "<3.1", + "rainlab/user-plugin": "<=1.4.5", "rankmath/seo-by-rank-math": "<=1.0.95", "rap2hpoutre/laravel-log-viewer": "<0.13", "react/http": ">=0.7,<1.9", "really-simple-plugins/complianz-gdpr": "<6.4.2", - "remdex/livehelperchat": "<3.99", + "redaxo/source": "<5.18.3", + "remdex/livehelperchat": "<4.29", + "reportico-web/reportico": "<=8.1", + "rhukster/dom-sanitizer": "<1.0.7", "rmccue/requests": ">=1.6,<1.8", - "robrichards/xmlseclibs": "<3.0.4", + "robrichards/xmlseclibs": ">=1,<3.0.4", "roots/soil": "<4.1", "rudloff/alltube": "<3.0.3", + "rudloff/rtmpdump-bin": "<=2.3.1", "s-cart/core": "<6.9", "s-cart/s-cart": "<6.9", "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", - "sabre/dav": "<1.7.11|>=1.8,<1.8.9", - "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", + "sabre/dav": ">=1.6,<1.7.11|>=1.8,<1.8.9", + "samwilson/unlinked-wikibase": "<1.42", + "scheb/two-factor-bundle": "<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", "sfroemken/url_redirect": "<=1.2.1", - "sheng/yiicms": "<=1.2", - "shopware/core": "<=6.4.20", - "shopware/platform": "<=6.4.20", + "sheng/yiicms": "<1.2.1", + "shopware/core": "<6.5.8.18-dev|>=6.6,<6.6.10.3-dev|>=6.7.0.0-RC1-dev,<6.7.0.0-RC2-dev", + "shopware/platform": "<6.5.8.18-dev|>=6.6,<6.6.10.3-dev|>=6.7.0.0-RC1-dev,<6.7.0.0-RC2-dev", "shopware/production": "<=6.3.5.2", "shopware/shopware": "<=5.7.17", - "shopware/storefront": "<=6.4.8.1", - "shopxo/shopxo": "<2.2.6", + "shopware/storefront": "<=6.4.8.1|>=6.5.8,<6.5.8.7-dev", + "shopxo/shopxo": "<=6.4", "showdoc/showdoc": "<2.10.4", + "shuchkin/simplexlsx": ">=1.0.12,<1.1.13", "silverstripe-australia/advancedreports": ">=1,<=2", - "silverstripe/admin": "<1.12.7", + "silverstripe/admin": "<1.13.19|>=2,<2.1.8", "silverstripe/assets": ">=1,<1.11.1", "silverstripe/cms": "<4.11.3", - "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", + "silverstripe/comments": ">=1.3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.12.5", - "silverstripe/graphql": "<3.5.2|>=4-alpha.1,<4-alpha.2|>=4.1.1,<4.1.2|>=4.2.2,<4.2.3|= 4.0.0-alpha1", + "silverstripe/framework": "<5.3.23", + "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.8.2|>=4,<4.3.7|>=5,<5.1.3", "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", "silverstripe/recipe-cms": ">=4.5,<4.5.3", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", - "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", + "silverstripe/reports": "<5.2.3", + "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4|>=2.1,<2.1.2", "silverstripe/silverstripe-omnipay": "<2.5.2|>=3,<3.0.2|>=3.1,<3.1.4|>=3.2,<3.2.1", "silverstripe/subsites": ">=2,<2.6.1", "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", - "silverstripe/userforms": "<3", + "silverstripe/userforms": "<3|>=5,<5.4.2", "silverstripe/versioned-admin": ">=1,<1.11.1", "simple-updates/phpwhois": "<=1", - "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", + "simplesamlphp/saml2": "<=4.16.15|>=5.0.0.0-alpha1,<=5.0.0.0-alpha19", + "simplesamlphp/saml2-legacy": "<=4.16.15", "simplesamlphp/simplesamlphp": "<1.18.6", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "simplesamlphp/simplesamlphp-module-openid": "<1", "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", + "simplesamlphp/xml-common": "<1.20", + "simplesamlphp/xml-security": "==1.6.11", "simplito/elliptic-php": "<1.0.6", "sitegeist/fluid-components": "<3.5", - "sjbr/sr-freecap": "<=2.5.2", + "sjbr/sr-feuser-register": "<2.6.2", + "sjbr/sr-freecap": "<2.4.6|>=2.5,<2.5.3", + "sjbr/static-info-tables": "<2.3.1", "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1", "slim/slim": "<2.6", - "smarty/smarty": "<3.1.48|>=4,<4.3.1", - "snipe/snipe-it": "<=6.0.14|>= 6.0.0-RC-1, <= 6.0.0-RC-5", + "slub/slub-events": "<3.0.3", + "smarty/smarty": "<4.5.3|>=5,<5.1.1", + "snipe/snipe-it": "<8.1", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", - "spatie/browsershot": "<3.57.4", - "spipu/html2pdf": "<5.2.4", + "spatie/browsershot": "<5.0.5", + "spatie/image-optimizer": "<1.7.3", + "spencer14420/sp-php-email-handler": "<1", + "spipu/html2pdf": "<5.2.8", "spoon/library": "<1.4.1", "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<22.2.3", - "statamic/cms": "<4.10", - "stormpath/sdk": ">=0,<9.9.99", - "studio-42/elfinder": "<2.1.62", + "ssddanbrown/bookstack": "<24.05.1", + "starcitizentools/citizen-skin": ">=2.6.3,<2.31", + "starcitizentools/tabber-neue": ">=1.9.1,<2.7.2", + "statamic/cms": "<=5.16", + "stormpath/sdk": "<9.9.99", + "studio-42/elfinder": "<=2.1.64", + "studiomitte/friendlycaptcha": "<0.1.4", "subhh/libconnect": "<7.0.8|>=8,<8.1", - "subrion/cms": "<=4.2.1", "sukohi/surpass": "<1", - "sulu/sulu": "= 2.4.0-RC1|<1.6.44|>=2,<2.2.18|>=2.3,<2.3.8", + "sulu/form-bundle": ">=2,<2.5.3", + "sulu/sulu": "<1.6.44|>=2,<2.5.25|>=2.6,<2.6.9|>=3.0.0.0-alpha1,<3.0.0.0-alpha3", "sumocoders/framework-user-bundle": "<1.4", + "superbig/craft-audit": "<3.0.2", + "svewap/a21glossary": "<=0.4.10", "swag/paypal": "<5.4.4", - "swiftmailer/swiftmailer": ">=4,<5.4.5", + "swiftmailer/swiftmailer": "<6.2.5", + "swiftyedit/swiftyedit": "<1.2", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", "sylius/grid-bundle": "<1.10.1", - "sylius/paypal-plugin": ">=1,<1.2.4|>=1.3,<1.3.1", - "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", - "sylius/sylius": "<1.9.10|>=1.10,<1.10.11|>=1.11,<1.11.2", - "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", + "sylius/paypal-plugin": "<1.6.2|>=1.7,<1.7.2|>=2,<2.0.2", + "sylius/resource-bundle": ">=1,<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", + "sylius/sylius": "<1.12.19|>=1.13.0.0-alpha1,<1.13.4", + "symbiote/silverstripe-multivaluefield": ">=3,<3.1", "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", "symbiote/silverstripe-seed": "<6.0.3", "symbiote/silverstripe-versionedfiles": "<=2.0.3", @@ -15879,8 +17249,9 @@ "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<=5.3.14|>=5.4.3,<=5.4.3|>=6.0.3,<=6.0.3|= 6.0.3|= 5.4.3|= 5.3.14", - "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<5.3.15|>=5.4.3,<5.4.4|>=6.0.3,<6.0.4", + "symfony/http-client": ">=4.3,<5.4.47|>=6,<6.4.15|>=7,<7.1.8", + "symfony/http-foundation": "<5.4.46|>=6,<6.4.14|>=7,<7.1.7", "symfony/http-kernel": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", "symfony/maker-bundle": ">=1.27,<1.29.2|>=1.30,<1.31.1", @@ -15888,67 +17259,108 @@ "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/polyfill": ">=1,<1.10", "symfony/polyfill-php55": ">=1,<1.10", + "symfony/process": "<5.4.46|>=6,<6.4.14|>=7,<7.1.7", "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/routing": ">=2,<2.0.19", + "symfony/runtime": ">=5.3,<5.4.46|>=6,<6.4.14|>=7,<7.1.7", "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.8", - "symfony/security-bundle": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", + "symfony/security-bundle": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.4.10|>=7,<7.0.10|>=7.1,<7.1.3", "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7|>=5.1,<5.2.8|>=5.3,<5.3.2", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7|>=5.1,<5.2.8|>=5.3,<5.4.47|>=6,<6.4.15|>=7,<7.1.8", "symfony/serializer": ">=2,<2.0.11|>=4.1,<4.4.35|>=5,<5.3.12", - "symfony/symfony": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", + "symfony/symfony": "<5.4.47|>=6,<6.4.15|>=7,<7.1.8", "symfony/translation": ">=2,<2.0.17", - "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", + "symfony/twig-bridge": ">=2,<4.4.51|>=5,<5.4.31|>=6,<6.3.8", + "symfony/ux-autocomplete": "<2.11.2", + "symfony/validator": "<5.4.43|>=6,<6.4.11|>=7,<7.1.4", "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", - "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", - "t3/dce": ">=2.2,<2.6.2", + "symfony/webhook": ">=6.3,<6.3.8", + "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7|>=2.2.0.0-beta1,<2.2.0.0-beta2", + "symphonycms/symphony-2": "<2.6.4", + "t3/dce": "<0.11.5|>=2.2,<2.6.2", "t3g/svg-sanitizer": "<1.0.3", - "tastyigniter/tastyigniter": "<3.3", - "tcg/voyager": "<=1.4", - "tecnickcom/tcpdf": "<6.2.22", + "t3s/content-consent": "<1.0.3|>=2,<2.0.2", + "tastyigniter/tastyigniter": "<4", + "tcg/voyager": "<=1.8", + "tecnickcom/tc-lib-pdf-font": "<2.6.4", + "tecnickcom/tcpdf": "<6.8", "terminal42/contao-tablelookupwizard": "<3.3.5", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1-beta.1,<2.1.3", + "thelia/thelia": ">=2.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", - "thinkcmf/thinkcmf": "<=5.1.7", - "thorsten/phpmyfaq": "<3.2-beta.2", - "tinymce/tinymce": "<5.10.7|>=6,<6.3.1", + "thinkcmf/thinkcmf": "<6.0.8", + "thorsten/phpmyfaq": "<=4.0.1", + "tikiwiki/tiki-manager": "<=17.1", + "timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1", + "tinymce/tinymce": "<7.2", "tinymighty/wiki-seo": "<1.2.2", - "titon/framework": ">=0,<9.9.99", - "tobiasbg/tablepress": "<= 2.0-RC1", - "topthink/framework": "<6.0.14", + "titon/framework": "<9.9.99", + "tltneon/lgsl": "<7", + "tobiasbg/tablepress": "<=2.0.0.0-RC1", + "topthink/framework": "<6.0.17|>=6.1,<=8.0.4", "topthink/think": "<=6.1.1", - "topthink/thinkphp": "<=3.2.3", + "topthink/thinkphp": "<=3.2.3|>=6.1.3,<=8.0.4", + "torrentpier/torrentpier": "<=2.4.3", "tpwd/ke_search": "<4.0.3|>=4.1,<4.6.6|>=5,<5.0.2", - "tribalsystems/zenario": "<=9.3.57595", + "tribalsystems/zenario": "<=9.7.61188", "truckersmp/phpwhois": "<=4.3.1", "ttskch/pagination-service-provider": "<1", - "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", - "typo3/cms": "<2.0.5|>=3,<3.0.3|>=6.2,<=6.2.38|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", - "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", - "typo3/cms-core": "<8.7.51|>=9,<9.5.42|>=10,<10.4.39|>=11,<11.5.30|>=12,<12.4.4", - "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", + "twbs/bootstrap": "<=3.4.1|>=4,<=4.6.2", + "twig/twig": "<3.11.2|>=3.12,<3.14.1|>=3.16,<3.19", + "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", + "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<10.4.46|>=11,<11.5.40|>=12,<12.4.21|>=13,<13.3.1", + "typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-beuser": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-core": "<=8.7.56|>=9,<=9.5.48|>=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-dashboard": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", + "typo3/cms-extensionmanager": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-felogin": ">=4.2,<4.2.3", + "typo3/cms-fluid": "<4.3.4|>=4.4,<4.4.1", + "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-frontend": "<4.3.9|>=4.4,<4.4.5", + "typo3/cms-indexed-search": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", + "typo3/cms-install": "<4.1.14|>=4.2,<4.2.16|>=4.3,<4.3.9|>=4.4,<4.4.5|>=12.2,<12.4.8|==13.4.2", + "typo3/cms-lowlevel": ">=11,<=11.5.41", + "typo3/cms-rte-ckeditor": ">=9.5,<9.5.42|>=10,<10.4.39|>=11,<11.5.30", + "typo3/cms-scheduler": ">=11,<=11.5.41", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "typo3/html-sanitizer": ">=1,<1.5.1|>=2,<2.1.2", + "typo3/html-sanitizer": ">=1,<=1.5.2|>=2,<=2.1.3", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", "ua-parser/uap-php": "<3.8", - "unisharp/laravel-filemanager": "<=2.5.1", + "uasoft-indonesia/badaso": "<=2.9.7", + "unisharp/laravel-filemanager": "<2.9.1", + "unopim/unopim": "<0.1.5", "userfrosting/userfrosting": ">=0.3.1,<4.6.3", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", "uvdesk/community-skeleton": "<=1.1.1", + "uvdesk/core-framework": "<=1.1.1", "vanilla/safecurl": "<0.9.2", - "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", + "verbb/comments": "<1.5.5", + "verbb/formie": "<=2.1.43", + "verbb/image-resizer": "<2.0.9", + "verbb/knock-knock": "<1.2.8", + "verot/class.upload.php": "<=2.1.6", + "vertexvaar/falsftp": "<0.2.6", + "villagedefrance/opencart-overclocked": "<=1.11.1", "vova07/yii2-fileapi-widget": "<0.1.9", "vrana/adminer": "<4.8.1", + "vufind/vufind": ">=2,<9.1.1", + "waldhacker/hcaptcha": "<2.1.2", "wallabag/tcpdf": "<6.2.22", - "wallabag/wallabag": "<=2.5.4", + "wallabag/wallabag": "<2.6.11", "wanglelecc/laracms": "<=1.0.3", - "web-auth/webauthn-framework": ">=3.3,<3.3.4", + "wapplersystems/a21glossary": "<=0.4.10", + "web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9", + "web-auth/webauthn-lib": ">=4.5,<4.9", + "web-feet/coastercms": "==5.5", + "web-tp3/wec_map": "<3.0.3", "webbuilders-group/silverstripe-kapost-bridge": "<0.4", "webcoast/deferred-image-processing": "<1.0.2", "webklex/laravel-imap": "<5.3", @@ -15957,23 +17369,32 @@ "wikibase/wikibase": "<=1.39.3", "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", - "wintercms/winter": "<1.2.3", - "woocommerce/woocommerce": "<6.6", - "wp-cli/wp-cli": "<2.5", + "winter/wn-backend-module": "<1.2.4", + "winter/wn-cms-module": "<1.0.476|>=1.1,<1.1.11|>=1.2,<1.2.7", + "winter/wn-dusk-plugin": "<2.1", + "winter/wn-system-module": "<1.2.4", + "wintercms/winter": "<=1.2.3", + "wireui/wireui": "<1.19.3|>=2,<2.1.3", + "woocommerce/woocommerce": "<6.6|>=8.8,<8.8.5|>=8.9,<8.9.3", + "wp-cli/wp-cli": ">=0.12,<2.5", "wp-graphql/wp-graphql": "<=1.14.5", + "wp-premium/gravityforms": "<2.4.21", "wpanel/wpanel4-cms": "<=4.3.1", "wpcloud/wp-stateless": "<3.2", - "wwbn/avideo": "<=12.4", + "wpglobus/wpglobus": "<=1.9.6", + "wwbn/avideo": "<14.3", "xataface/xataface": "<3", "xpressengine/xpressengine": "<3.0.15", - "yeswiki/yeswiki": "<4.1", - "yetiforce/yetiforce-crm": "<=6.4", + "yab/quarx": "<2.4.5", + "yeswiki/yeswiki": "<4.5.4", + "yetiforce/yetiforce-crm": "<6.5", "yidashi/yii2cmf": "<=2", "yii2mod/yii2-cms": "<1.9.2", - "yiisoft/yii": "<1.1.27", - "yiisoft/yii2": "<2.0.38", + "yiisoft/yii": "<1.1.31", + "yiisoft/yii2": "<2.0.52", + "yiisoft/yii2-authclient": "<2.2.15", "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<2.0.43", + "yiisoft/yii2-dev": "<=2.0.45", "yiisoft/yii2-elasticsearch": "<2.0.5", "yiisoft/yii2-gii": "<=2.2.4", "yiisoft/yii2-jui": "<2.0.4", @@ -15981,12 +17402,13 @@ "yikesinc/yikes-inc-easy-mailchimp-extender": "<6.8.6", "yoast-seo-for-typo3/yoast_seo": "<7.2.3", "yourls/yourls": "<=1.8.2", - "zencart/zencart": "<1.5.8", + "yuan1994/tpadmin": "<=1.3.12", + "zencart/zencart": "<=1.5.7.0-beta", "zendesk/zendesk_api_client_php": "<2.2.11", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", + "zendframework/zend-db": "<2.2.10|>=2.3,<2.3.5", "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", "zendframework/zend-diactoros": "<1.8.4", "zendframework/zend-feed": "<2.10.3", @@ -15994,22 +17416,30 @@ "zendframework/zend-http": "<2.8.1", "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", - "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", + "zendframework/zend-mail": "<2.4.11|>=2.5,<2.7.2", "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", + "zendframework/zend-session": ">=2,<2.2.9|>=2.3,<2.3.4", "zendframework/zend-validator": ">=2.3,<2.3.6", "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", "zendframework/zendframework": "<=3", "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": ">=2,<2.0.2", + "zendframework/zendopenid": "<2.0.2", + "zendframework/zendrest": "<2.0.2", + "zendframework/zendservice-amazon": "<2.0.3", + "zendframework/zendservice-api": "<1", + "zendframework/zendservice-audioscrobbler": "<2.0.2", + "zendframework/zendservice-nirvanix": "<2.0.2", + "zendframework/zendservice-slideshare": "<2.0.2", + "zendframework/zendservice-technorati": "<2.0.2", + "zendframework/zendservice-windowsazure": "<2.0.2", "zendframework/zendxml": ">=1,<1.0.1", "zenstruck/collection": "<0.2.1", "zetacomponents/mail": "<1.8.2", "zf-commons/zfc-user": "<1.2.2", "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", "zfr/zfr-oauth2-server-module": "<0.1.2", - "zoujingli/thinkadmin": "<6.0.22" + "zoujingli/thinkadmin": "<=6.1.53" }, "default-branch": true, "type": "metapackage", @@ -16047,33 +17477,331 @@ "type": "tidelift" } ], - "time": "2023-07-25T19:04:12+00:00" + "time": "2025-05-17T16:05:20+00:00" }, { - "name": "sebastian/diff", - "version": "5.0.3", + "name": "sebastian/cli-parser", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/912dc2fbe3e3c1e7873313cc801b100b6c68c87b", - "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^10.0", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:27:43+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.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/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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 calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:19:30+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -16105,8 +17833,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -16114,94 +17841,630 @@ "type": "github" } ], - "time": "2023-05-01T07:48:21+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { - "name": "spatie/array-to-xml", - "version": "3.2.0", + "name": "sebastian/environment", + "version": "5.1.5", "source": { "type": "git", - "url": "https://github.com/spatie/array-to-xml.git", - "reference": "f9ab39c808500c347d5a8b6b13310bd5221e39e7" + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/f9ab39c808500c347d5a8b6b13310bd5221e39e7", - "reference": "f9ab39c808500c347d5a8b6b13310bd5221e39e7", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { - "ext-dom": "*", - "php": "^8.0" + "php": ">=7.3" }, "require-dev": { - "mockery/mockery": "^1.2", - "pestphp/pest": "^1.21", - "spatie/pest-plugin-snapshots": "^1.1" + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", - "autoload": { - "psr-4": { - "Spatie\\ArrayToXml\\": "src" + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://freek.dev", - "role": "Developer" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Convert an array to xml", - "homepage": "https://github.com/spatie/array-to-xml", + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", "keywords": [ - "array", - "convert", - "xml" + "Xdebug", + "environment", + "hhvm" ], "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.2.0" + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" }, "funding": [ { - "url": "https://spatie.be/open-source/support-us", - "type": "custom" - }, - { - "url": "https://github.com/spatie", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2023-07-19T18:30:26+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { - "name": "symfony/browser-kit", - "version": "v6.3.2", + "name": "sebastian/exporter", + "version": "4.0.6", "source": { "type": "git", - "url": "https://github.com/symfony/browser-kit.git", - "reference": "ca4a988488f61ac18f8f845445eabdd36f89aa8d" + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/ca4a988488f61ac18f8f845445eabdd36f89aa8d", - "reference": "ca4a988488f61ac18f8f845445eabdd36f89aa8d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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": "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", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:33:00+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.7", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:35:11+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.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", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:20:34+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.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/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.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/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.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": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-14T16:00:52+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "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/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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": "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/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "symfony/browser-kit", + "version": "v6.4.19", + "source": { + "type": "git", + "url": "https://github.com/symfony/browser-kit.git", + "reference": "ce95f3e3239159e7fa3be7690c6ce95a4714637f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/ce95f3e3239159e7fa3be7690c6ce95a4714637f", + "reference": "ce95f3e3239159e7fa3be7690c6ce95a4714637f", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/dom-crawler": "^5.4|^6.0" + "symfony/dom-crawler": "^5.4|^6.0|^7.0" }, "require-dev": { - "symfony/css-selector": "^5.4|^6.0", - "symfony/http-client": "^5.4|^6.0", - "symfony/mime": "^5.4|^6.0", - "symfony/process": "^5.4|^6.0" + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -16229,7 +18492,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v6.3.2" + "source": "https://github.com/symfony/browser-kit/tree/v6.4.19" }, "funding": [ { @@ -16245,37 +18508,37 @@ "type": "tidelift" } ], - "time": "2023-07-06T06:56:43+00:00" + "time": "2025-02-14T11:23:16+00:00" }, { "name": "symfony/debug-bundle", - "version": "v6.3.2", + "version": "v6.4.13", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "3f04a578e1a9f1d7da84a87b690c03123e5d8c31" + "reference": "7bcfaff39e094cc09455201916d016d9b2ae08ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/3f04a578e1a9f1d7da84a87b690c03123e5d8c31", - "reference": "3f04a578e1a9f1d7da84a87b690c03123e5d8c31", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/7bcfaff39e094cc09455201916d016d9b2ae08ff", + "reference": "7bcfaff39e094cc09455201916d016d9b2ae08ff", "shasum": "" }, "require": { "ext-xml": "*", "php": ">=8.1", - "symfony/dependency-injection": "^5.4|^6.0", - "symfony/http-kernel": "^5.4|^6.0", - "symfony/twig-bridge": "^5.4|^6.0", - "symfony/var-dumper": "^5.4|^6.0" + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/twig-bridge": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "conflict": { "symfony/config": "<5.4", "symfony/dependency-injection": "<5.4" }, "require-dev": { - "symfony/config": "^5.4|^6.0", - "symfony/web-profiler-bundle": "^5.4|^6.0" + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/web-profiler-bundle": "^5.4|^6.0|^7.0" }, "type": "symfony-bundle", "autoload": { @@ -16303,7 +18566,7 @@ "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug-bundle/tree/v6.3.2" + "source": "https://github.com/symfony/debug-bundle/tree/v6.4.13" }, "funding": [ { @@ -16319,123 +18582,54 @@ "type": "tidelift" } ], - "time": "2023-07-13T14:29:38+00:00" - }, - { - "name": "symfony/dom-crawler", - "version": "v6.3.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "8aa333f41f05afc7fc285a976b58272fd90fc212" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/8aa333f41f05afc7fc285a976b58272fd90fc212", - "reference": "8aa333f41f05afc7fc285a976b58272fd90fc212", - "shasum": "" - }, - "require": { - "masterminds/html5": "^2.6", - "php": ">=8.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "symfony/css-selector": "^5.4|^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "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 DOM navigation for HTML and XML documents", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.3.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": "2023-06-05T15:30:22+00:00" + "time": "2024-09-25T14:18:03+00:00" }, { "name": "symfony/maker-bundle", - "version": "v1.50.0", + "version": "v1.63.0", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "a1733f849b999460c308e66f6392fb09b621fa86" + "reference": "69478ab39bc303abfbe3293006a78b09a8512425" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/a1733f849b999460c308e66f6392fb09b621fa86", - "reference": "a1733f849b999460c308e66f6392fb09b621fa86", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/69478ab39bc303abfbe3293006a78b09a8512425", + "reference": "69478ab39bc303abfbe3293006a78b09a8512425", "shasum": "" }, "require": { "doctrine/inflector": "^2.0", - "nikic/php-parser": "^4.11", - "php": ">=8.0", - "symfony/config": "^5.4.7|^6.0", - "symfony/console": "^5.4.7|^6.0", - "symfony/dependency-injection": "^5.4.7|^6.0", + "nikic/php-parser": "^5.0", + "php": ">=8.1", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", "symfony/deprecation-contracts": "^2.2|^3", - "symfony/filesystem": "^5.4.7|^6.0", - "symfony/finder": "^5.4.3|^6.0", - "symfony/framework-bundle": "^5.4.7|^6.0", - "symfony/http-kernel": "^5.4.7|^6.0", - "symfony/process": "^5.4.7|^6.0" + "symfony/filesystem": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0" }, "conflict": { - "doctrine/doctrine-bundle": "<2.4", - "doctrine/orm": "<2.10", - "symfony/doctrine-bridge": "<5.4" + "doctrine/doctrine-bundle": "<2.10", + "doctrine/orm": "<2.15" }, "require-dev": { "composer/semver": "^3.0", - "doctrine/doctrine-bundle": "^2.4", - "doctrine/orm": "^2.10.0", - "symfony/http-client": "^5.4.7|^6.0", - "symfony/phpunit-bridge": "^5.4.17|^6.0", - "symfony/polyfill-php80": "^1.16.0", - "symfony/security-core": "^5.4.7|^6.0", - "symfony/yaml": "^5.4.3|^6.0", - "twig/twig": "^2.0|^3.0" + "doctrine/doctrine-bundle": "^2.5.0", + "doctrine/orm": "^2.15|^3", + "symfony/http-client": "^6.4|^7.0", + "symfony/phpunit-bridge": "^6.4.1|^7.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "twig/twig": "^3.0|^4.x-dev" }, "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-main": "1.0-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -16464,7 +18658,7 @@ ], "support": { "issues": "https://github.com/symfony/maker-bundle/issues", - "source": "https://github.com/symfony/maker-bundle/tree/v1.50.0" + "source": "https://github.com/symfony/maker-bundle/tree/v1.63.0" }, "funding": [ { @@ -16480,20 +18674,20 @@ "type": "tidelift" } ], - "time": "2023-07-10T18:21:57+00:00" + "time": "2025-04-26T01:41:37+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v6.3.2", + "version": "v6.4.16", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "e020e1efbd1b42cb670fcd7d19a25abbddba035d" + "reference": "cebafe2f1ad2d1e745c1015b7c2519592341e4e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/e020e1efbd1b42cb670fcd7d19a25abbddba035d", - "reference": "e020e1efbd1b42cb670fcd7d19a25abbddba035d", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/cebafe2f1ad2d1e745c1015b7c2519592341e4e6", + "reference": "cebafe2f1ad2d1e745c1015b7c2519592341e4e6", "shasum": "" }, "require": { @@ -16504,7 +18698,7 @@ }, "require-dev": { "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/error-handler": "^5.4|^6.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", "symfony/polyfill-php81": "^1.27" }, "bin": [ @@ -16513,8 +18707,8 @@ "type": "symfony-bridge", "extra": { "thanks": { - "name": "phpunit/phpunit", - "url": "https://github.com/sebastianbergmann/phpunit" + "url": "https://github.com/sebastianbergmann/phpunit", + "name": "phpunit/phpunit" } }, "autoload": { @@ -16525,7 +18719,8 @@ "Symfony\\Bridge\\PhpUnit\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Tests/", + "/bin/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -16545,7 +18740,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v6.3.2" + "source": "https://github.com/symfony/phpunit-bridge/tree/v6.4.16" }, "funding": [ { @@ -16561,41 +18756,42 @@ "type": "tidelift" } ], - "time": "2023-07-12T16:00:22+00:00" + "time": "2024-11-13T15:06:22+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v6.3.2", + "version": "v6.4.19", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "6101b5ab7857c373d237e121f9060c68b32e1373" + "reference": "7d1026a8e950d416cb5148ae88ac23db5d264839" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/6101b5ab7857c373d237e121f9060c68b32e1373", - "reference": "6101b5ab7857c373d237e121f9060c68b32e1373", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/7d1026a8e950d416cb5148ae88ac23db5d264839", + "reference": "7d1026a8e950d416cb5148ae88ac23db5d264839", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/config": "^5.4|^6.0", - "symfony/framework-bundle": "^5.4|^6.0", - "symfony/http-kernel": "^6.3", - "symfony/routing": "^5.4|^6.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/routing": "^5.4|^6.0|^7.0", "symfony/twig-bundle": "^5.4|^6.0", "twig/twig": "^2.13|^3.0.4" }, "conflict": { "symfony/form": "<5.4", "symfony/mailer": "<5.4", - "symfony/messenger": "<5.4" + "symfony/messenger": "<5.4", + "symfony/twig-bundle": ">=7.0" }, "require-dev": { - "symfony/browser-kit": "^5.4|^6.0", - "symfony/console": "^5.4|^6.0", - "symfony/css-selector": "^5.4|^6.0", - "symfony/stopwatch": "^5.4|^6.0" + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0" }, "type": "symfony-bundle", "autoload": { @@ -16626,7 +18822,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.3.2" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.19" }, "funding": [ { @@ -16642,29 +18838,32 @@ "type": "tidelift" } ], - "time": "2023-07-19T20:17:28+00:00" + "time": "2025-02-14T12:21:59+00:00" }, { "name": "symplify/easy-coding-standard", - "version": "11.5.0", + "version": "12.5.18", "source": { "type": "git", "url": "https://github.com/easy-coding-standard/easy-coding-standard.git", - "reference": "1d2400f7bfe92e3754ce71f0782f2c0521bade3d" + "reference": "451dfeba3770f2d7476468b891a789c451ae4b34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/easy-coding-standard/easy-coding-standard/zipball/1d2400f7bfe92e3754ce71f0782f2c0521bade3d", - "reference": "1d2400f7bfe92e3754ce71f0782f2c0521bade3d", + "url": "https://api.github.com/repos/easy-coding-standard/easy-coding-standard/zipball/451dfeba3770f2d7476468b891a789c451ae4b34", + "reference": "451dfeba3770f2d7476468b891a789c451ae4b34", "shasum": "" }, "require": { "php": ">=7.2" }, "conflict": { - "friendsofphp/php-cs-fixer": "<3.0", - "squizlabs/php_codesniffer": "<3.6", - "symplify/coding-standard": "<11.3" + "friendsofphp/php-cs-fixer": "<3.46", + "phpcsstandards/php_codesniffer": "<3.8", + "symplify/coding-standard": "<12.1" + }, + "suggest": { + "ext-dom": "Needed to support checkstyle output format in class CheckstyleOutputFormatter" }, "bin": [ "bin/ecs" @@ -16688,7 +18887,7 @@ ], "support": { "issues": "https://github.com/easy-coding-standard/easy-coding-standard/issues", - "source": "https://github.com/easy-coding-standard/easy-coding-standard/tree/11.5.0" + "source": "https://github.com/easy-coding-standard/easy-coding-standard/tree/12.5.18" }, "funding": [ { @@ -16700,133 +18899,69 @@ "type": "github" } ], - "time": "2023-06-21T06:26:15+00:00" + "time": "2025-05-14T09:38:08+00:00" }, { - "name": "vimeo/psalm", - "version": "5.14.0", + "name": "theseer/tokenizer", + "version": "1.2.3", "source": { "type": "git", - "url": "https://github.com/vimeo/psalm.git", - "reference": "b2942cefed8443002bd3f245c4cd0a54193716d8" + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/b2942cefed8443002bd3f245c4cd0a54193716d8", - "reference": "b2942cefed8443002bd3f245c4cd0a54193716d8", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { - "amphp/amp": "^2.4.2", - "amphp/byte-stream": "^1.5", - "composer-runtime-api": "^2", - "composer/semver": "^1.4 || ^2.0 || ^3.0", - "composer/xdebug-handler": "^2.0 || ^3.0", - "dnoegel/php-xdg-base-dir": "^0.1.1", - "ext-ctype": "*", "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-simplexml": "*", "ext-tokenizer": "*", - "felixfbecker/advanced-json-rpc": "^3.1", - "felixfbecker/language-server-protocol": "^1.5.2", - "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", - "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.16", - "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", - "sebastian/diff": "^4.0 || ^5.0", - "spatie/array-to-xml": "^2.17.0 || ^3.0", - "symfony/console": "^4.1.6 || ^5.0 || ^6.0", - "symfony/filesystem": "^5.4 || ^6.0" + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" }, - "provide": { - "psalm/psalm": "self.version" - }, - "require-dev": { - "amphp/phpunit-util": "^2.0", - "bamarni/composer-bin-plugin": "^1.4", - "brianium/paratest": "^6.9", - "ext-curl": "*", - "mockery/mockery": "^1.5", - "nunomaduro/mock-final-classes": "^1.1", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpdoc-parser": "^1.6", - "phpunit/phpunit": "^9.6", - "psalm/plugin-mockery": "^1.1", - "psalm/plugin-phpunit": "^0.18", - "slevomat/coding-standard": "^8.4", - "squizlabs/php_codesniffer": "^3.6", - "symfony/process": "^4.4 || ^5.0 || ^6.0" - }, - "suggest": { - "ext-curl": "In order to send data to shepherd", - "ext-igbinary": "^2.0.5 is required, used to serialize caching data" - }, - "bin": [ - "psalm", - "psalm-language-server", - "psalm-plugin", - "psalm-refactor", - "psalter" - ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev", - "dev-4.x": "4.x-dev", - "dev-3.x": "3.x-dev", - "dev-2.x": "2.x-dev", - "dev-1.x": "1.x-dev" - } - }, "autoload": { - "psr-4": { - "Psalm\\": "src/Psalm/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Matthew Brown" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" } ], - "description": "A static analysis tool for finding errors in PHP applications", - "keywords": [ - "code", - "inspection", - "php", - "static analysis" - ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { - "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/5.14.0" + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, - "time": "2023-07-30T20:18:56+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [ { - "package": "doctrine/orm", - "version": "dev-entity-level-commit-order", - "alias": "2.15.3", - "alias_normalized": "2.15.3.0" - }, - { - "package": "dompdf/dompdf", - "version": "9999999-dev", - "alias": "v2.0.3", - "alias_normalized": "2.0.3.0" + "package": "brick/math", + "version": "0.12.1.0", + "alias": "0.11.0", + "alias_normalized": "0.11.0.0" } ], "minimum-stability": "stable", "stability-flags": { - "doctrine/orm": 20, - "dompdf/dompdf": 20, "florianv/swap-bundle": 20, "roave/security-advisories": 20 }, diff --git a/config/bundles.php b/config/bundles.php index 6545338d..ea066084 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -18,17 +18,18 @@ return [ DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true], Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true], Gregwar\CaptchaBundle\GregwarCaptchaBundle::class => ['all' => true], - Translation\Bundle\TranslationBundle::class => ['all' => true], Florianv\SwapBundle\FlorianvSwapBundle::class => ['all' => true], Nelmio\SecurityBundle\NelmioSecurityBundle::class => ['all' => true], Symfony\UX\Turbo\TurboBundle::class => ['all' => true], Jbtronics\TFAWebauthn\TFAWebauthnBundle::class => ['all' => true], Scheb\TwoFactorBundle\SchebTwoFactorBundle::class => ['all' => true], - SpomkyLabs\CborBundle\SpomkyLabsCborBundle::class => ['all' => true], Webauthn\Bundle\WebauthnBundle::class => ['all' => true], Nbgrp\OneloginSamlBundle\NbgrpOneloginSamlBundle::class => ['all' => true], Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true], Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true], Jbtronics\DompdfFontLoaderBundle\DompdfFontLoaderBundle::class => ['all' => true], KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class => ['all' => true], + Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true], + ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true], + Jbtronics\TranslationEditorBundle\JbtronicsTranslationEditorBundle::class => ['dev' => true], ]; diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml new file mode 100644 index 00000000..d55f91ea --- /dev/null +++ b/config/packages/api_platform.yaml @@ -0,0 +1,41 @@ +api_platform: + title: 'Part-DB API' + description: 'API of Part-DB' + version: '0.1.0' + + formats: + jsonld: ['application/ld+json'] + json: ['application/json'] + jsonapi: ['application/vnd.api+json'] + + docs_formats: + jsonld: ['application/ld+json'] + jsonopenapi: ['application/vnd.openapi+json'] + html: ['text/html'] + json: ['application/vnd.openapi+json'] + + swagger: + api_keys: + # overridden in OpenApiFactoryDecorator + access_token: + name: Authorization + type: header + + defaults: + # TODO: Change this to true later. In the moment it is false, because we use the session in somewhere + stateless: false + cache_headers: + vary: ['Content-Type', 'Authorization', 'Origin'] + extra_properties: + standard_put: true + rfc_7807_compliant_errors: true + + pagination_client_items_per_page: true # Allow clients to override the default items per page + + keep_legacy_inflector: false + # Need to be true, or some tests will fail + use_symfony_listeners: true + + serializer: + # Change this to false later, to remove the hydra prefix on the API + hydra_prefix: true \ No newline at end of file diff --git a/config/packages/dama_doctrine_test_bundle.yaml b/config/packages/dama_doctrine_test_bundle.yaml new file mode 100644 index 00000000..3482cbae --- /dev/null +++ b/config/packages/dama_doctrine_test_bundle.yaml @@ -0,0 +1,5 @@ +when@test: + dama_doctrine_test: + enable_static_connection: true + enable_static_meta_data_cache: true + enable_static_query_cache: true diff --git a/config/packages/datatables.yaml b/config/packages/datatables.yaml index dc116f97..6076a6c7 100644 --- a/config/packages/datatables.yaml +++ b/config/packages/datatables.yaml @@ -8,15 +8,14 @@ datatables: # Set options, as documented at https://datatables.net/reference/option/ options: - lengthMenu : [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]] + lengthMenu : [[10, 25, 50, 100], [10, 25, 50, 100]] # We add the "All" option, when part tables are generated pageLength: '%partdb.table.default_page_size%' # Set to -1 to disable pagination (i.e. show all rows) by default - #dom: "<'row' <'col-sm-12' tr>><'row' <'col-sm-6'l><'col-sm-6 text-right'pif>>" - dom: " <'row'<'col mb-2 input-group' B l> <'col mb-2' <'pull-end' p>>> - <'card' - rt - <'card-footer card-footer-table text-muted' i > - > - <'row'<'col mt-2 input-group' B l> <'col mt-2' <'pull-right' p>>>" + dom: " <'row' <'col mb-2 input-group flex-nowrap' B l > <'col-auto mb-2' < p >>> + <'card' + rt + <'card-footer card-footer-table text-muted' i > + > + <'row' <'col mt-2 input-group flex-nowrap' B l > <'col-auto mt-2' < p >>>" pagingType: 'simple_numbers' searching: true stateSave: true diff --git a/config/packages/dev/php_translation.yaml b/config/packages/dev/php_translation.yaml deleted file mode 100644 index 53398fbc..00000000 --- a/config/packages/dev/php_translation.yaml +++ /dev/null @@ -1,5 +0,0 @@ -translation: - symfony_profiler: - enabled: true - webui: - enabled: true diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 2db28db2..3211fbbe 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -2,18 +2,32 @@ doctrine: dbal: url: '%env(resolve:DATABASE_URL)%' + # Required for DAMA doctrine test bundle + use_savepoints: true + # IMPORTANT: You MUST configure your server version, # either here or in the DATABASE_URL env var (see .env file) types: + # UTC datetimes datetime: class: App\Doctrine\Types\UTCDateTimeType date: class: App\Doctrine\Types\UTCDateTimeType + + datetime_immutable: + class: App\Doctrine\Types\UTCDateTimeImmutableType + date_immutable: + class: App\Doctrine\Types\UTCDateTimeImmutableType + big_decimal: class: App\Doctrine\Types\BigDecimalType tinyint: class: App\Doctrine\Types\TinyIntType + + # This was removed in doctrine/orm 4.0 but we need it for the WebauthnKey entity + array: + class: App\Doctrine\Types\ArrayType schema_filter: ~^(?!internal)~ # Only enable this when needed @@ -26,20 +40,24 @@ doctrine: validate_xml_mapping: true naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware auto_mapping: true + controller_resolver: + auto_mapping: true mappings: App: - is_bundle: false type: attribute + is_bundle: false dir: '%kernel.project_dir%/src/Entity' prefix: 'App\Entity' alias: App dql: string_functions: - regexp: DoctrineExtensions\Query\Mysql\Regexp - ifnull: DoctrineExtensions\Query\Mysql\IfNull + regexp: App\Doctrine\Functions\Regexp field: DoctrineExtensions\Query\Mysql\Field field2: App\Doctrine\Functions\Field2 + natsort: App\Doctrine\Functions\Natsort + array_position: App\Doctrine\Functions\ArrayPosition + ilike: App\Doctrine\Functions\ILike when@test: doctrine: diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index 05dc5d0e..279c51f5 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -2,8 +2,12 @@ framework: secret: '%env(APP_SECRET)%' csrf_protection: true + annotations: false handle_all_throwables: true + # We set this header by ourselves, so we can disable it here + disallow_search_engine_index: false + # Must be set to true, to enable the change of HTTP method via _method parameter, otherwise our delete routines does not work anymore # TODO: Rework delete routines to work without _method parameter as it is not recommended anymore (see https://github.com/symfony/symfony/issues/45278) http_method_override: true @@ -23,7 +27,6 @@ framework: handler_id: null cookie_secure: auto cookie_samesite: lax - storage_factory_id: session.storage.factory.native #esi: true #fragments: true diff --git a/config/packages/monolog.yaml b/config/packages/monolog.yaml index 8938cc13..44a078b8 100644 --- a/config/packages/monolog.yaml +++ b/config/packages/monolog.yaml @@ -50,7 +50,6 @@ when@prod: type: stream path: "%kernel.logs_dir%/%kernel.environment%.log" level: debug - formatter: monolog.formatter.json console: type: console process_psr_3_messages: false @@ -74,7 +73,6 @@ when@docker: type: stream path: "php://stderr" level: debug - formatter: monolog.formatter.json console: type: console process_psr_3_messages: false diff --git a/config/packages/nbgrp_onelogin_saml.yaml b/config/packages/nbgrp_onelogin_saml.yaml index d2f5bae0..2b1974f3 100644 --- a/config/packages/nbgrp_onelogin_saml.yaml +++ b/config/packages/nbgrp_onelogin_saml.yaml @@ -1,6 +1,11 @@ # See https://github.com/SAML-Toolkits/php-saml for more information about the SAML settings +# Define a parameter here, so we can access it later in the default fallback +parameters: + saml.sp.privateKey: '%env(string:SAML_SP_PRIVATE_KEY)%' + nbgrp_onelogin_saml: + use_proxy_vars: '%env(bool:SAML_BEHIND_PROXY)%' onelogin_settings: default: # Basic settings @@ -22,10 +27,12 @@ nbgrp_onelogin_saml: url: '%partdb.default_uri%logout' binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect' x509cert: '%env(string:SAML_SP_X509_CERT)%' - privateKey: '%env(string:SAMLP_SP_PRIVATE_KEY)%' + # Before the env variable was wrongly named "SAMLP_SP_PRIVATE_KEY". + # For compatibility reasons we keep it and only fallback to the new name if the old one is not set. This may be removed in the future. + privateKey: '%env(string:default:saml.sp.privateKey:string:SAMLP_SP_PRIVATE_KEY)%' # Optional settings - #baseurl: 'http://myapp.com' + baseurl: '%partdb.default_uri%saml/' strict: true debug: false security: diff --git a/config/packages/nelmio_cors.yaml b/config/packages/nelmio_cors.yaml new file mode 100644 index 00000000..c7665081 --- /dev/null +++ b/config/packages/nelmio_cors.yaml @@ -0,0 +1,10 @@ +nelmio_cors: + defaults: + origin_regex: true + allow_origin: ['%env(CORS_ALLOW_ORIGIN)%'] + allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE'] + allow_headers: ['Content-Type', 'Authorization'] + expose_headers: ['Link'] + max_age: 3600 + paths: + '^/': null diff --git a/config/packages/nelmio_security.yaml b/config/packages/nelmio_security.yaml index 075ce930..1cb74da7 100644 --- a/config/packages/nelmio_security.yaml +++ b/config/packages/nelmio_security.yaml @@ -51,12 +51,16 @@ nelmio_security: img-src: - '*' - 'data:' + # Required for be able to load pictures in the QR code scanner + - 'blob:' style-src: - 'self' - 'unsafe-inline' - 'data:' script-src: - 'self' + # Required for loading the Wasm for the barcode scanner: + - 'wasm-unsafe-eval' object-src: - 'self' - 'data:' diff --git a/config/packages/php_translation.yaml b/config/packages/php_translation.yaml deleted file mode 100644 index 7c4f6ad9..00000000 --- a/config/packages/php_translation.yaml +++ /dev/null @@ -1,11 +0,0 @@ -translation: - locales: ["en", "de"] - edit_in_place: - enabled: false - config_name: app - configs: - app: - dirs: ["%kernel.project_dir%/templates", "%kernel.project_dir%/src"] - output_dir: "%kernel.project_dir%/translations" - excluded_names: ["*TestCase.php", "*Test.php"] - excluded_dirs: [cache, data, logs] diff --git a/config/packages/scheb_2fa.yaml b/config/packages/scheb_2fa.yaml index 4359d0fb..ad0e7a5a 100644 --- a/config/packages/scheb_2fa.yaml +++ b/config/packages/scheb_2fa.yaml @@ -6,7 +6,7 @@ scheb_two_factor: server_name: '$$DOMAIN$$' # This field is replaced by the domain name of the server in DecoratedGoogleAuthenticator issuer: '%partdb.title%' # Issuer name used in QR code digits: 6 # Number of digits in authentication code - window: 1 # How many codes before/after the current one would be accepted as valid + leeway: 5 # Acceptable time drift in seconds template: security/2fa_form.html.twig backup_codes: diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 92b9f188..95f5c6b1 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -19,11 +19,14 @@ security: provider: app_user_provider lazy: true user_checker: App\Security\UserChecker - entry_point: form_login + entry_point: App\Security\AuthenticationEntryPoint # Enable user impersonation switch_user: { role: CAN_SWITCH_USER } + custom_authenticators: + - App\Security\ApiTokenAuthenticator + two_factor: auth_form_path: 2fa_login check_path: 2fa_login_check @@ -66,3 +69,7 @@ security: # We get into trouble with the U2F authentication, if the calls to the trees trigger an 2FA login # This settings should not do much harm, because a read only access to show available data structures is not really critical - { path: "^/\\w{2}/tree", role: PUBLIC_ACCESS } + # Restrict access to API to users, which has the API access permission + - { path: "^/api", allow_if: 'is_granted("@api.access_api") and is_authenticated()' } + # Restrict access to KICAD to users, which has API access permission + - { path: "^/kicad-api", allow_if: 'is_granted("@api.access_api") and is_authenticated()' } diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 05dec32c..5b2d64e5 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -20,6 +20,7 @@ twig: avatar_helper: '@App\Services\UserSystem\UserAvatarHelper' available_themes: '%partdb.available_themes%' saml_enabled: '%partdb.saml.enabled%' + part_preview_generator: '@App\Services\Attachments\PartPreviewGenerator' when@test: twig: diff --git a/config/parameters.yaml b/config/parameters.yaml index 27d720b0..b2c10893 100644 --- a/config/parameters.yaml +++ b/config/parameters.yaml @@ -11,11 +11,13 @@ parameters: partdb.banner: '%env(trim:string:BANNER)%' # The info text shown in the homepage, if empty config/banner.md is used partdb.default_currency: '%env(string:BASE_CURRENCY)%' # The currency that is used inside the DB (and is assumed when no currency is set). This can not be changed later, so be sure to set it the currency used in your country partdb.global_theme: '' # The theme to use globally (see public/build/themes/ for choices, use name without .css). Set to '' for default bootstrap theme - partdb.locale_menu: ['en', 'de', 'fr', 'ru', 'ja'] # The languages that are shown in user drop down menu + partdb.locale_menu: ['en', 'de', 'it', 'fr', 'ru', 'ja', 'cs', 'da', 'zh', 'pl'] # The languages that are shown in user drop down menu partdb.enforce_change_comments_for: '%env(csv:ENFORCE_CHANGE_COMMENTS_FOR)%' # The actions for which a change comment is required (e.g. "part_edit", "part_create", etc.). If this is empty, change comments are not required at all. partdb.default_uri: '%env(string:DEFAULT_URI)%' # The default URI to use for the Part-DB instance (e.g. https://part-db.example.com/). This is used for generating links in emails + partdb.db.emulate_natural_sort: '%env(bool:DATABASE_EMULATE_NATURAL_SORT)%' # If this is set to true, natural sorting is emulated on platforms that do not support it natively. This can be slow on large datasets. + ###################################################################################################################### # Users and Privacy ###################################################################################################################### @@ -23,6 +25,8 @@ parameters: partdb.users.use_gravatar: '%env(bool:USE_GRAVATAR)%' # Set to false, if no Gravatar images should be used for user profiles. partdb.users.email_pw_reset: '%env(bool:ALLOW_EMAIL_PW_RESET)%' # Config if users are able, to reset their password by email. By default this enabled, when a mail server is configured. + partdb.check_for_updates: '%env(bool:CHECK_FOR_UPDATES)' # Set to false, if Part-DB should not contact the GitHub API to check for updates + ###################################################################################################################### # Mail settings ###################################################################################################################### @@ -33,6 +37,7 @@ parameters: # Attachments and files ###################################################################################################################### partdb.attachments.allow_downloads: '%env(bool:ALLOW_ATTACHMENT_DOWNLOADS)%' # Allow users to download attachments to server. Warning: This can be dangerous, because via that feature attackers maybe can access ressources on your intranet! + partdb.attachments.download_by_default: '%env(bool:ATTACHMENT_DOWNLOAD_BY_DEFAULT)%' # If this is set the 'download external files' checkbox is set by default for new attachments (only if allow_downloads is set to true) partdb.attachments.dir.media: 'public/media/' # The folder where uploaded attachment files are saved (must be in public folder) partdb.attachments.dir.secure: 'uploads/' # The folder where secured attachment files are saved (must not be in public/) partdb.attachments.max_file_size: '%env(string:MAX_ATTACHMENT_FILE_SIZE)%' # The maximum size of an attachment file (in bytes, you can use M for megabytes and G for gigabytes) @@ -51,7 +56,8 @@ parameters: ###################################################################################################################### # Table settings ###################################################################################################################### - partdb.table.default_page_size: '%env(int:TABLE_DEFAULT_PAGE_SIZE)%' # The default number of entries shown per page in tables + partdb.table.default_page_size: '%env(int:TABLE_DEFAULT_PAGE_SIZE)%' # The default number of entries shown per page in tables + partdb.table.parts.default_columns: '%env(trim:string:TABLE_PARTS_DEFAULT_COLUMNS)%' # The default columns in part tables and their order ###################################################################################################################### # Sidebar @@ -111,6 +117,8 @@ parameters: env(USE_GRAVATAR): '0' env(MAX_ATTACHMENT_FILE_SIZE): '100M' + env(REDIRECT_TO_HTTPS): 0 + env(ENFORCE_CHANGE_COMMENTS_FOR): '' env(ERROR_PAGE_ADMIN_EMAIL): '' @@ -138,3 +146,6 @@ parameters: env(HISTORY_SAVE_REMOVED_DATA): 1 env(HISTORY_SAVE_NEW_DATA): 1 + env(EDA_KICAD_CATEGORY_DEPTH): 0 + + env(DATABASE_EMULATE_NATURAL_SORT): 0 diff --git a/config/permissions.yaml b/config/permissions.yaml index d00e1e77..b8970556 100644 --- a/config/permissions.yaml +++ b/config/permissions.yaml @@ -25,27 +25,35 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co # If a part can be read by a user, he can also see all the datastructures (except devices) alsoSet: ['storelocations.read', 'footprints.read', 'categories.read', 'suppliers.read', 'manufacturers.read', 'currencies.read', 'attachment_types.read', 'measurement_units.read'] + apiTokenRole: ROLE_API_READ_ONLY edit: label: "perm.edit" alsoSet: ['read', 'parts_stock.withdraw', 'parts_stock.add', 'parts_stock.move'] + apiTokenRole: ROLE_API_EDIT create: label: "perm.create" alsoSet: ['read', 'edit'] + apiTokenRole: ROLE_API_EDIT delete: label: "perm.delete" alsoSet: ['read', 'edit'] + apiTokenRole: ROLE_API_EDIT change_favorite: label: "perm.part.change_favorite" alsoSet: ['edit'] + apiTokenRole: ROLE_API_EDIT show_history: label: "perm.part.show_history" alsoSet: ['read'] + apiTokenRole: ROLE_API_READ_ONLY revert_element: label: "perm.revert_elements" alsoSet: ["read", "edit", "create", "delete", "show_history"] + apiTokenRole: ROLE_API_EDIT import: label: "perm.import" alsoSet: ["read", "edit", "create"] + apiTokenRole: ROLE_API_EDIT parts_stock: group: "data" @@ -53,10 +61,13 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co operations: withdraw: label: "perm.parts_stock.withdraw" + apiTokenRole: ROLE_API_EDIT add: label: "perm.parts_stock.add" + apiTokenRole: ROLE_API_EDIT move: label: "perm.parts_stock.move" + apiTokenRole: ROLE_API_EDIT storelocations: &PART_CONTAINING @@ -65,23 +76,30 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co operations: read: label: "perm.read" + apiTokenRole: ROLE_API_READ_ONLY edit: label: "perm.edit" alsoSet: 'read' + apiTokenRole: ROLE_API_EDIT create: label: "perm.create" alsoSet: ['read', 'edit'] + apiTokenRole: ROLE_API_EDIT delete: label: "perm.delete" alsoSet: ['read', 'edit'] + apiTokenRole: ROLE_API_EDIT show_history: label: "perm.show_history" + apiTokenRole: ROLE_API_READ_ONLY revert_element: label: "perm.revert_elements" alsoSet: ["read", "edit", "create", "delete", "show_history"] + apiTokenRole: ROLE_API_EDIT import: label: "perm.import" alsoSet: [ "read", "edit", "create" ] + apiTokenRole: ROLE_API_EDIT footprints: <<: *PART_CONTAINING @@ -145,6 +163,7 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co create_parts: label: "perm.part.info_providers.create_parts" alsoSet: ['parts.create'] + apiTokenRole: ROLE_API_EDIT groups: label: "perm.groups" @@ -152,26 +171,34 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co operations: read: label: "perm.read" + apiTokenRole: ROLE_API_ADMIN edit: label: "perm.edit" alsoSet: 'read' + apiTokenRole: ROLE_API_ADMIN create: label: "perm.create" alsoSet: ['read', 'edit'] + apiTokenRole: ROLE_API_ADMIN delete: label: "perm.delete" alsoSet: ['read', 'delete'] + apiTokenRole: ROLE_API_ADMIN edit_permissions: label: "perm.edit_permissions" alsoSet: ['read', 'edit'] + apiTokenRole: ROLE_API_ADMIN show_history: label: "perm.show_history" + apiTokenRole: ROLE_API_ADMIN revert_element: label: "perm.revert_elements" alsoSet: ["read", "edit", "create", "delete", "edit_permissions", "show_history"] + apiTokenRole: ROLE_API_ADMIN import: label: "perm.import" alsoSet: [ "read", "edit", "create" ] + apiTokenRole: ROLE_API_ADMIN users: label: "perm.users" @@ -179,37 +206,49 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co operations: read: label: "perm.read" + apiTokenRole: ROLE_API_ADMIN create: label: "perm.create" alsoSet: ['read', 'edit_username', 'edit_infos'] + apiTokenRole: ROLE_API_ADMIN delete: label: "perm.delete" alsoSet: ['read', 'edit_username', 'edit_infos'] + apiTokenRole: ROLE_API_ADMIN edit_username: label: "perm.users.edit_user_name" alsoSet: ['read'] + apiTokenRole: ROLE_API_ADMIN edit_infos: label: "perm.users.edit_infos" alsoSet: 'read' + apiTokenRole: ROLE_API_ADMIN edit_permissions: label: "perm.users.edit_permissions" alsoSet: 'read' + apiTokenRole: ROLE_API_ADMIN set_password: label: "perm.users.set_password" alsoSet: 'read' + apiTokenRole: ROLE_API_FULL impersonate: label: "perm.users.impersonate" alsoSet: ['set_password'] + apiTokenRole: ROLE_API_FULL change_user_settings: label: "perm.users.change_user_settings" + apiTokenRole: ROLE_API_ADMIN show_history: label: "perm.show_history" + apiTokenRole: ROLE_API_ADMIN revert_element: label: "perm.revert_elements" alsoSet: ["read", "create", "delete", "edit_permissions", "show_history", "edit_infos", "edit_username"] + apiTokenRole: ROLE_API_ADMIN import: label: "perm.import" alsoSet: [ "read", "create" ] + apiTokenRole: ROLE_API_ADMIN #database: # label: "perm.database" @@ -244,62 +283,94 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co operations: show_logs: label: "perm.show_logs" + apiTokenRole: ROLE_API_ADMIN delete_logs: label: "perm.delete_logs" alsoSet: 'show_logs' + apiTokenRole: ROLE_API_ADMIN server_infos: label: "perm.server_infos" + apiTokenRole: ROLE_API_ADMIN manage_oauth_tokens: label: "Manage OAuth tokens" + apiTokenRole: ROLE_API_ADMIN + show_updates: + label: "perm.system.show_available_updates" + apiTokenRole: ROLE_API_ADMIN + attachments: label: "perm.part.attachments" operations: show_private: label: "perm.attachments.show_private" + apiTokenRole: ROLE_API_READ_ONLY list_attachments: label: "perm.attachments.list_attachments" alsoSet: ['attachment_types.read'] + apiTokenRole: ROLE_API_READ_ONLY self: label: "perm.self" operations: edit_infos: label: "perm.self.edit_infos" + apiTokenRole: ROLE_API_FULL edit_username: label: "perm.self.edit_username" + apiTokenRole: ROLE_API_FULL show_permissions: label: "perm.self.show_permissions" + apiTokenRole: ROLE_API_READ_ONLY show_logs: label: "perm.self.show_logs" + apiTokenRole: ROLE_API_FULL labels: label: "perm.labels" operations: create_labels: label: "perm.self.create_labels" + apiTokenRole: ROLE_API_READ_ONLY edit_options: label: "perm.self.edit_options" alsoSet: ['create_labels'] + apiTokenRole: ROLE_API_READ_ONLY read_profiles: label: "perm.self.read_profiles" + apiTokenRole: ROLE_API_READ_ONLY edit_profiles: label: "perm.self.edit_profiles" alsoSet: ['read_profiles'] + apiTokenRole: ROLE_API_EDIT create_profiles: label: "perm.self.create_profiles" alsoSet: ['read_profiles', 'edit_profiles'] + apiTokenRole: ROLE_API_EDIT delete_profiles: label: "perm.self.delete_profiles" alsoSet: ['read_profiles', 'edit_profiles', 'create_profiles'] + apiTokenRole: ROLE_API_EDIT use_twig: label: "perm.labels.use_twig" alsoSet: ['create_labels', 'edit_options'] + apiTokenRole: ROLE_API_ADMIN show_history: label: "perm.show_history" alsoSet: ['read_profiles'] + apiTokenRole: ROLE_API_READ_ONLY revert_element: label: "perm.revert_elements" alsoSet: ['read_profiles', 'edit_profiles', 'create_profiles', 'delete_profiles'] + apiTokenRole: ROLE_API_EDIT - + api: + label: "perm.api" + operations: + access_api: + label: "perm.api.access_api" + apiTokenRole: ROLE_API_READ_ONLY + manage_tokens: + label: "perm.api.manage_tokens" + alsoSet: ['access_api'] + apiTokenRole: ROLE_API_FULL \ No newline at end of file diff --git a/config/routes.yaml b/config/routes.yaml index 2da939a1..8b38fa71 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -15,5 +15,5 @@ redirector: requirements: url: ".*" controller: App\Controller\RedirectController::addLocalePart - # Dont match localized routes (no redirection loop, if no root with that name exists) - condition: "not (request.getPathInfo() matches '/^\\\\/[a-z]{2}(_[A-Z]{2})?\\\\//')" \ No newline at end of file + # Dont match localized routes (no redirection loop, if no root with that name exists) or API prefixed routes + condition: "not (request.getPathInfo() matches '/^\\\\/([a-z]{2}(_[A-Z]{2})?|api)\\\\//')" \ No newline at end of file diff --git a/config/routes/api_platform.yaml b/config/routes/api_platform.yaml new file mode 100644 index 00000000..38f11cba --- /dev/null +++ b/config/routes/api_platform.yaml @@ -0,0 +1,4 @@ +api_platform: + resource: . + type: api_platform + prefix: /api diff --git a/config/routes/dev/php_translation.yaml b/config/routes/dev/php_translation.yaml deleted file mode 100644 index 903b23fb..00000000 --- a/config/routes/dev/php_translation.yaml +++ /dev/null @@ -1,6 +0,0 @@ -_translation_webui: - resource: '@TranslationBundle/Resources/config/routing_webui.yaml' - prefix: /admin - -_translation_profiler: - resource: '@TranslationBundle/Resources/config/routing_symfony_profiler.yaml' diff --git a/config/routes/jbtronics_translation_editor.yaml b/config/routes/jbtronics_translation_editor.yaml new file mode 100644 index 00000000..31409a61 --- /dev/null +++ b/config/routes/jbtronics_translation_editor.yaml @@ -0,0 +1,3 @@ +when@dev: + translation_editor: + resource: '@JbtronicsTranslationEditorBundle/config/routes.php' \ No newline at end of file diff --git a/config/routes/php_translation.yaml b/config/routes/php_translation.yaml deleted file mode 100644 index 96ffd76f..00000000 --- a/config/routes/php_translation.yaml +++ /dev/null @@ -1,3 +0,0 @@ -_translation_edit_in_place: - resource: '@TranslationBundle/Resources/config/routing_edit_in_place.yaml' - prefix: /admin diff --git a/config/routes/security.yaml b/config/routes/security.yaml new file mode 100644 index 00000000..f853be15 --- /dev/null +++ b/config/routes/security.yaml @@ -0,0 +1,3 @@ +_security_logout: + resource: security.route_loader.logout + type: service diff --git a/config/services.yaml b/config/services.yaml index a278ae78..b2342edd 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -76,23 +76,18 @@ services: # Only the event classes specified here are saved to DB (set to []) to log all events $whitelist: [] - App\EventSubscriber\LogSystem\EventLoggerSubscriber: + App\EventListener\LogSystem\EventLoggerListener: arguments: $save_changed_fields: '%env(bool:HISTORY_SAVE_CHANGED_FIELDS)%' $save_changed_data: '%env(bool:HISTORY_SAVE_CHANGED_DATA)%' $save_removed_data: '%env(bool:HISTORY_SAVE_REMOVED_DATA)%' $save_new_data: '%env(bool:HISTORY_SAVE_NEW_DATA)%' - tags: - - { name: 'doctrine.event_subscriber' } - - App\EventSubscriber\LogSystem\LogDBMigrationSubscriber: - tags: - - { name: 'doctrine.event_subscriber' } App\Form\AttachmentFormType: arguments: $allow_attachments_download: '%partdb.attachments.allow_downloads%' $max_file_size: '%partdb.attachments.max_file_size%' + $download_by_default: '%partdb.attachments.download_by_default%' App\Services\Attachments\AttachmentSubmitHandler: arguments: @@ -140,6 +135,19 @@ services: $saml_role_mapping: '%env(json:SAML_ROLE_MAPPING)%' $update_group_on_login: '%env(bool:SAML_UPDATE_GROUP_ON_LOGIN)%' + + security.access_token_extractor.header.token: + class: Symfony\Component\Security\Http\AccessToken\HeaderAccessTokenExtractor + arguments: + $tokenType: 'Token' + + security.access_token_extractor.main: + class: Symfony\Component\Security\Http\AccessToken\ChainAccessTokenExtractor + arguments: + $accessTokenExtractors: + - '@security.access_token_extractor.header' + - '@security.access_token_extractor.header.token' + #################################################################################################################### # Cache #################################################################################################################### @@ -211,6 +219,15 @@ services: arguments: $saml_enabled: '%partdb.saml.enabled%' + #################################################################################################################### + # Table settings + #################################################################################################################### + App\DataTables\PartsDataTable: + arguments: + $visible_columns: '%partdb.table.parts.default_columns%' + + App\DataTables\Helpers\ColumnSortHelper: + shared: false # Service has a state so not share it between different tables #################################################################################################################### # Label system @@ -277,6 +294,44 @@ services: $search_limit: '%env(int:PROVIDER_OCTOPART_SEARCH_LIMIT)%' $onlyAuthorizedSellers: '%env(bool:PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS)%' + App\Services\InfoProviderSystem\Providers\MouserProvider: + arguments: + $api_key: '%env(string:PROVIDER_MOUSER_KEY)%' + $language: '%env(string:PROVIDER_MOUSER_SEARCH_WITH_SIGNUP_LANGUAGE)%' + $options: '%env(string:PROVIDER_MOUSER_SEARCH_OPTION)%' + $search_limit: '%env(int:PROVIDER_MOUSER_SEARCH_LIMIT)%' + + App\Services\InfoProviderSystem\Providers\LCSCProvider: + arguments: + $enabled: '%env(bool:PROVIDER_LCSC_ENABLED)%' + $currency: '%env(string:PROVIDER_LCSC_CURRENCY)%' + + App\Services\InfoProviderSystem\Providers\OEMSecretsProvider: + arguments: + $api_key: '%env(string:PROVIDER_OEMSECRETS_KEY)%' + $country_code: '%env(string:PROVIDER_OEMSECRETS_COUNTRY_CODE)%' + $currency: '%env(PROVIDER_OEMSECRETS_CURRENCY)%' + $zero_price: '%env(PROVIDER_OEMSECRETS_ZERO_PRICE)%' + $set_param: '%env(PROVIDER_OEMSECRETS_SET_PARAM)%' + $sort_criteria: '%env(PROVIDER_OEMSECRETS_SORT_CRITERIA)%' + + + #################################################################################################################### + # API system + #################################################################################################################### + App\State\PartDBInfoProvider: + arguments: + $default_uri: '%partdb.default_uri%' + $global_locale: '%partdb.locale%' + $global_timezone: '%partdb.timezone%' + + #################################################################################################################### + # EDA system + #################################################################################################################### + App\Services\EDA\KiCadHelper: + arguments: + $category_depth: '%env(int:EDA_KICAD_CATEGORY_DEPTH)%' + #################################################################################################################### # Symfony overrides #################################################################################################################### @@ -315,6 +370,20 @@ services: arguments: $project_dir: '%kernel.project_dir%' + App\Services\System\UpdateAvailableManager: + arguments: + $check_for_updates: '%partdb.check_for_updates%' + + App\Services\System\BannerHelper: + arguments: + $partdb_banner: '%partdb.banner%' + $project_dir: '%kernel.project_dir%' + + App\Doctrine\Middleware\MySQLSSLConnectionMiddlewareWrapper: + arguments: + $enabled: '%env(bool:DATABASE_MYSQL_USE_SSL_CA)%' + $verify: '%env(bool:DATABASE_MYSQL_SSL_VERIFY_CERT)%' + #################################################################################################################### # Monolog #################################################################################################################### @@ -341,4 +410,4 @@ when@test: arguments: - '@doctrine.fixtures.loader' - '@doctrine' - - { default: '@App\Doctrine\Purger\ResetAutoIncrementPurgerFactory' } \ No newline at end of file + - { default: '@App\Doctrine\Purger\DoNotUsePurgerFactory' } diff --git a/docs/api/authentication.md b/docs/api/authentication.md new file mode 100644 index 00000000..b386c0cd --- /dev/null +++ b/docs/api/authentication.md @@ -0,0 +1,77 @@ +--- +title: Authentication +layout: default +parent: API +nav_order: 2 +--- + +# Authentication + +To use API endpoints, the external application has to authenticate itself, so that Part-DB knows which user is accessing +the data and which permissions +the application should have during the access. Authentication is always bound to a specific user, so the external +applications is acting on behalf of a +specific user. This user limits the permissions of the application so that it can only access data, which the user is +allowed to access. + +The only method currently available for authentication is to use API tokens: + +## API tokens + +An API token is a long alphanumeric string, which is bound to a specific user and can be used to authenticate as this user when accessing the API. +The API token is passed via the `Authorization` HTTP header during the API request, like the +following: `Authorization: Bearer tcp_sdjfks....`. + +{: .important } +> Everybody who knows the API token can access the API as the user, which is bound to the token. So you should treat the +> API token like a password +> and keep it secret. Only share it with trusted applications. + +API tokens can be created and managed on the user settings page in the API token section. You can create as many API +tokens as you want and also delete them again. +When deleting a token, it is immediately invalidated and can not be used anymore, which means that the application can +not access the API anymore with this token. + +### Token permissions and scopes + +API tokens are ultimately limited by the permissions of the user, which belongs to the token. That means that the token +can only access data, that the user is allowed to access, no matter the token permissions. + +But you can further limit the permissions of a token by choosing a specific scope for the token. The scope defines which +subset of permissions the token has, which can be less than the permissions of the user. For example, you can have a +user +with full read and write permissions, but create a token with only read permissions, which can only read data, but not +change anything in the database. + +{: .warning } +> In general, you should always use the least possible permissions for a token, to limit the possible damage, which can +> be done with a stolen token or a bug in the application. +> Only use the full or admin scope, if you really need it, as they could potentially be used to do a lot of damage to +> your Part-DB instance. + +The following token scopes are available: + +* **Read-Only**: The token can only read non-sensitive data (like parts, but no users or groups) from the API and can + not change anything. +* **Edit**: The token can read and write non-sensitive data via the API. This includes creating, updating and deleting + data. This should be enough for most applications. +* **Admin**: The token can read and write all data via the API, including sensitive data like users and groups. This + should only be used for trusted applications, which need to access sensitive data and perform administrative actions. +* **Full**: The token can do anything the user can do, including changing the user's password and creating new tokens. This + should only be used for highly trusted applications!! + +Please note, that in early versions of the API, there might be no endpoints yet, to really perform the actions, which +would be allowed by the token scope. + +### Expiration date + +API tokens can have an expiration date, which means that the token is only valid until the expiration date. After that +the token is automatically invalidated and can not be used anymore. The token is still listed on the user settings page, +and can be deleted there, but the code can not be used to access Part-DB anymore after the expiration date. + +### Get token information + +When authenticating with an API token, you can get information about the currently used token by accessing +the `/api/tokens/current` endpoint. +It gives you information about the token scope, expiration date and the user, which is bound to the token and the last +time the token was used. \ No newline at end of file diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 00000000..441ede9a --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,11 @@ +--- +layout: default +title: API +nav_order: 7 +has_children: true +--- + +# API + +Part-DB provides a REST API to access the data stored in the database. +In this section you can find information about the API and how to use it. diff --git a/docs/api/intro.md b/docs/api/intro.md new file mode 100644 index 00000000..78a8d2c1 --- /dev/null +++ b/docs/api/intro.md @@ -0,0 +1,229 @@ +--- +title: Introduction +layout: default +parent: API +nav_order: 1 +--- + +# Introduction + +Part-DB provides a [REST API](https://en.wikipedia.org/wiki/REST) to programmatically access the data stored in the +database. +This allows external applications to interact with Part-DB, extend it or integrate it into other applications. + +{: .warning } +> This feature is currently in beta. Please report any bugs you find. +> The API should not be considered stable yet and could change in future versions, without prior notice. +> Some features might be missing or not working yet. +> Also be aware, that there might be security issues in the API, which could allow attackers to access or edit data via +> the API, which +> they normally should be able to access. So currently you should only use the API with trusted users and trusted +> applications. + +Part-DB uses [API Platform](https://api-platform.com/) to provide the API, which allows for easy creation of REST APIs +with Symfony and gives you a lot of features out of the box. +See the [API Platform documentation](https://api-platform.com/docs/core/) for more details about the API Platform +features and how to use them. + +## Enable the API + +The API is available under the `/api` path, but not reachable without proper permissions. +You have to give the users, which should be able to access the API the proper permissions (Miscellaneous -> API). +Please note that there are two relevant permissions, the first one allows users to access the `/api/` path at all and show the documentation, +and the second one allows them to create API tokens which are needed for the authentication of external applications. + +## Authentication + +To use API endpoints, the external application has to authenticate itself, so that Part-DB knows which user is accessing +the data and +which permissions the application should have. Basically, this is done by creating an API token for a user and then +passing it on every request +with the `Authorization` header as bearer token, so you add a header `Authorization: Bearer `. + +See [Authentication chapter]({% link api/authentication.md %}) for more details. + +## API endpoints + +The API is split into different endpoints, which are reachable under the `/api/` path of your Part-DB instance ( +e.g. `https://your-part-db.local/api/`). +There are various endpoints for each entity type (like `part`, `manufacturer`, etc.), which allow you to read and write data, and some special endpoints like `search` or `statistics`. + +For example, all API endpoints for managing categories are available under `/api/categories/`. Depending on the exact +path and the HTTP method used, you can read, create, update or delete categories. +For most entities, there are endpoints like this: + +* **GET**: `/api/categories/` - List all categories in the database (with pagination of the results) +* **POST**: `/api/categories/` - Create a new category +* **GET**: `/api/categories/{id}` - Get a specific category by its ID +* **DELETE**: `/api/categories/{id}` - Delete a specific category by its ID +* **UPDATE**: `/api/categories/{id}` - Update a specific category by its ID. Only the fields which are sent in the + request are updated, all other fields are left unchanged. + Be aware that you have to set the [JSON Merge Patch](https://datatracker.ietf.org/doc/html/rfc7386) content type + header (`Content-Type: application/merge-patch+json`) for this to work. + +A full (interactive) list of endpoints can be displayed when visiting the `/api/` path in your browser, when you are +logged in with a user, which is allowed to access the API. +There is also a link to this page, on the user settings page in the API token section. +This documentation also lists all available fields for each entity type and the allowed operations. + +## Formats + +The API supports different formats for the request and response data, which you can control via the `Accept` +and `Content-Type` headers. +You should use [JSON-LD](https://json-ld.org/) as format, which is basically JSON with some additional metadata, which +allows you to describe the data in a more structured way and also allows to link between different entities. You can achieve this +by setting `Accept: application/ld+json` header to the API requests. + +To get plain JSON without any metadata or links, use the `Accept: application/json` header. + +Without an `Accept` header (e.g. when you call the endpoint in a browser), the API will return an HTML page with the +documentation, so be sure to include the desired `Accept` header in your API requests. +If you can not control the `Accept` header, you can add a `.json` or `.jsonld` suffix to the URL to enforce a JSON or +JSON-LD response (e.g. `/api/parts.jsonld`). + +## OpenAPI schema + +Part-DB provides a [OpenAPI](https://swagger.io/specification/) (formally Swagger) schema for the API +under `/api/docs.json` (so `https://your-part-db.local/api/docs.json`). +This schema is a machine-readable description of the API, which can be imported into software to test the API or even +automatically generate client libraries for the API. + +API generators which can generate a client library for the API from the schema are available for many programming +languages, like [OpenAPI Generator](https://openapi-generator.tech/). + +An JSONLD/Hydra version of the schema is also available under `/api/docs.jsonld` ( +so `https://your-part-db.local/api/docs.jsonld`). + +## Interactive documentation + +Part-DB provides an interactive documentation for the API, which is available under `/api/docs` ( +so `https://your-part-db.local/api/docs`). +You can pass your API token in the form on the top of the page, to authenticate yourself, and then you can try out the +API directly in the browser. +This is a great way to test the API and see how it works, without having to write any code. + +## Pagination + +By default, all list endpoints are paginated, which means only a certain number of results is returned per request. +To get another page of the results, you have to use the `page` query parameter, which contains the page number you want +to get (e.g. `/api/categoues/?page=2`). +When using JSONLD, the links to the next page are also included in the `hydra:view` property of the response. + +To change the size of the pages (the number of items in a single page) use the `itemsPerPage` query parameter ( +e.g. `/api/categoues/?itemsPerPage=50`). + +See [API Platform docs](https://api-platform.com/docs/core/pagination) for more infos. + +## Filtering results / Searching + +When retrieving a list of entities, you can restrict the results by various filters. Almost all entities have a search +filter, which allows you to only include entities, which (text) fields match the given search term: For example, if you only want +to get parts, with the Name "BC547", you can use `/api/parts.jsonld?name=BC547`. You can use `%` as a wildcard for multiple +characters in the search term (Be sure to properly encode the search term, if you use special characters). For example, if you want +to get all parts, whose name starts with "BC", you can use `/api/parts.jsonld?name=BC%25` (the `%25` is the url encoded version of `%`). + +There are other filters available for some entities, allowing you to search on other fields, or restricting the results +by numeric values or dates. See the endpoint documentation for the available filters. + +## Filter by associated entities + +To get all parts with a certain category, manufacturer, etc. you can use the `category`, `manufacturer`, etc. query +parameters of the `/api/parts` endpoint. +They are so-called entity filters and accept a comma-separated list of IDs of the entities you want to filter by. +For example, if you want to get all parts with the category "Resistor" (Category ID 1) and "Capacitor" (Category ID 2), +you can use `/api/parts.jsonld?category=1,2`. + +Suffix an id with `+` to suffix, to include all direct children categories of the given category. Use the `++` suffix to +include all children categories recursively. +To get all parts with the category "Resistor" (Category ID 1) and all children categories of "Capacitor" (Category ID +2), you can use `/api/parts.jsonld?category=1,2++`. + +See the endpoint documentation for the available entity filters. + +## Ordering results + +When retrieving a list of entities, you can order the results by various fields using the `order` query parameter. +For example, if you want to get all parts ordered by their name, you can use `/api/parts/?order[name]=asc`. You can use +this parameter multiple times to order by multiple fields. + +See the endpoint documentation for the available fields to order by. + +## Property filter + +Sometimes you only want to get a subset of the properties of an entity, for example when you only need the name of a +part, but not all the other properties. +You can achieve this using the `properties[]` query parameter with the name of the field you want to get. You can use +this parameter multiple times to get multiple fields. +For example, if you only want to get the name and the description of a part, you can +use `/api/parts/123?properties[]=name&properties[]=description`. +It is also possible to use these filters on list endpoints (get collection), to only get a subset of the properties of +all entities in the collection. + +See [API Platform docs](https://api-platform.com/docs/core/filters/#property-filter) for more info. + +## Change comment + +Similar to the changes using Part-DB web interface, you can add a change comment to every change you make via the API, +which will be +visible in the log of the entity. + +You can pass the text for this via the `_comment` query parameter (beware of the proper encoding). For +example `/api/parts/123?_comment=This%20is%20a%20change%20comment`. + +## Creating attachments and parameters + +To create attachments and parameters, use the POST endpoint. Internally there are different types of attachments and +parameters, for each entity type, where the attachments or parameters are used (e.g. PartAttachment for parts, etc.). +The type of the attachment or parameter is automatically determined by the `element` property of the request data if a +IRI is passed. You can use the `_type` property to explicitly set the type of the attachment or parameter (the value must +be the value of the `@type` property of the owning entity. e.g. `Part` for parts). + +For example, to create an attachment on a part, you can use the following request: + +``` +POST /api/attachments + +{ + "name": "front68", + "attachment_type": "/api/attachment_types/1", + "url": "https://invalid.invalid/test.url", + "element": "/api/parts/123" +} +``` + +## Uploading files to attachments + +To upload files to the attachments you can use the special `upload` property of the attachment entity during write operations (POST, PUT, PATCH). +Under `data` you can pass a base64 encoded string of the file content, and under `filename` the name of the file. +Using the `private` property you can control if the file is the attachment should be stored privately or public. + +For example, to upload a file to an attachment, you can use the following request: + +``` +PATCH /api/attachments/123 + +{ + "upload": { + "data": "data:@file/octet-stream;base64,LS0gcGhwTXlB[...]", + "filename": "test.csv", + "private": false + }, + "name": "Rename attachment" +} +``` + +This also works for creating new attachments, by including the `upload` property in the request data along with the other properties. + +Using the `downloadUrl` property of `upload` you can say Part-DB to upload the file specified at the URL set on the attachment. + +``` +PATCH /api/attachments/123 + +{ + "upload": { + "downloadUrl": true + }, + "url": "https://host.invalid/myfile.pdf" +} + +``` \ No newline at end of file diff --git a/docs/concepts.md b/docs/concepts.md index 844c50ee..ddf38633 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -5,50 +5,85 @@ nav_order: 2 --- # Concepts + This page explains the different concepts of Part-DB and what their intended use is: 1. TOC {:toc} -## Part managment +## Part management ### Part -A part is the central concept of Part-DB. A part represents a single kind (or type) of a thing, like an electronic component, an device, an book or similar (depending on what you use Part-DB for). A part entity just represents a certain type of a thing, so if you have 1000 times an BC547 transistor you would create ONE part with the name BC547 and set its quantity to 1000. The individual quantities (so a single BC547 transistor) of a part, should be indistinguishable from each other, so that it does not matter which one of your 1000 things of Part you use. -A part entity have many fields, which can be used to describe it better. Most of the fields are optional: -* **Name** (Required): The name of the part or how you wanna call it. This could be an manufacturer provided name, or a name you thought of your self. The name have to be unique in a single category. -* **Description**: A short (single-line) description of what this part is/does. For longer informations you should use the comment field or the specifications + +A part is the central concept of Part-DB. A part represents a single kind (or type) of a thing, like an electronic +component, a device, a book or similar (depending on what you use Part-DB for). A part entity just represents a certain +type of thing, so if you have 1000 times a BC547 transistor you would create ONE part with the name BC547 and set its +quantity to 1000. The individual quantities (so a single BC547 transistor) of a part, should be indistinguishable from +each other so that it does not matter which one of your 1000 things of Part you use. +A part entity has many fields, which can be used to describe it better. Most of the fields are optional: + +* **Name** (Required): The name of the part or how you want to call it. This could be a manufacturer-provided name, or a + name you thought of yourself. Each name needs to be unique and must exist in a single category. +* **Description**: A short (single-line) description of what this part is/does. For longer information, you should use + the comment field or the specifications * **Category** (Required): The category (see there) to which this part belongs to. -* **Tags**: The list of tags this part belong to. Tags can be used to group parts logically (similar to the category), but tags are much less strict and formal (they dont have to be defined forehands) and you can assign multiple tags to a part. When clicking on a tag, a list with all parts which have the same tag, is shown. -* **Min Instock**: *Not really implemented yet*. Parts where the total instock is below this value, will show up for ordering. -* **Footprint**: See there. Useful especially for electronic parts, which have one of the common electronic footprints (like DIP8, SMD0805 or similar). If a part has no explicit defined preview picture, the preview picture of its footprint will be shown instead in tables. +* **Tags**: The list of tags this part belongs to. Tags can be used to group parts logically (similar to the category), + but tags are much less strict and formal (they don't have to be defined forehands) and you can assign multiple tags to + a part. When clicking on a tag, a list with all parts which have the same tag, is shown. +* **Min Instock**: *Not really implemented yet*. Parts where the total instock is below this value, will show up for + ordering. +* **Footprint**: See there. Useful especially for electronic parts, which have one of the common electronic footprints ( + like DIP8, SMD0805 or similar). If a part has no explicitly defined preview picture, the preview picture of its + footprint will be shown instead in tables. * **Manufacturer**: The manufacturer which has manufactured (not sold) this part. See Manufacturer entity for more info. -* **Manufacturer part number** (MPN): If you have used your own name for a part, you can put the part number the manufacturer uses in this field, so that you can find a part also under its manufacturer number. -* **Link to product page**: If you want to link to the manufacturer website of a part, and it is not possible to determine it automatically from the part name, set in the manufacturer entity (or no manfacturer is set), you can set the link here for each part individually. -* **Manufacturing Status**: The manufacturing status of this part, meaning the information about where the part is in its manufacturing lifecycle. -* **Needs review**: If you think parts informations maybe are inaccurate or incomplete and needs some later review/checking, you can set this flag. A part with this flag is marked, so that users know the informations are not completly trustworthy. +* **Manufacturer part number** (MPN): If you have used your own name for a part, you can put the part number the + manufacturer uses in this field so that you can find a part also under its manufacturer number. +* **Link to product page**: If you want to link to the manufacturer website of a part, and it is not possible to + determine it automatically from the part name, set in the manufacturer entity (or no manufacturer is set), you can set + the link here for each part individually. +* **Manufacturing Status**: The manufacturing status of this part, meaning the information about where the part is in + its manufacturing lifecycle. +* **Needs review**: If you think parts information may be inaccurate or incomplete and needs some later + review/checking, you can set this flag. A part with this flag is marked, so that users know the information is not + completely trustworthy. * **Favorite**: Parts with this flag are highlighted in parts lists * **Mass**: The mass of a single piece of this part (so of a single transistor). Given in grams. -* **Internal Part number** (IPN): Each part is automatically assigned an numerical ID which identifies a part in the database. This ID depends on when a part was created and can not be changed. If you want to assign your own unique identifiers, or sync parts identifiers with the identifiers of another database you can use this field. +* **Internal Part number** (IPN): Each part is automatically assigned a numerical ID that identifies a part in the + database. This ID depends on when a part was created and can not be changed. If you want to assign your own unique + identifiers, or sync parts identifiers with the identifiers of another database you can use this field. ### Stock / Part lot -A part can have many stock at multiple different locations. This is represented by part lots / stocks, which consists basically of a storelocation (so where are the parts of this lot are stored) and an amount (how many parts are there). -### Purchase Informations -The purchase informations describe where the part can be bought (at which vendors) and to which prices. -The first part (the order information) describes at which supplier the part can be bought and which is the name of the part under which you can order the part there. -An order information can contain multiple price informations, which describes the prices for the part at the supplier including bulk discount, etc. +A part can have many stocks at multiple different locations. This is represented by part lots/stocks, which consists +basically of a storage location (so where the parts of this lot are stored) and an amount (how many parts are there). + +### Purchase Information + +The purchase information describes where the part can be bought (at which vendors) and at which prices. +The first part (the order information) describes at which supplier the part can be bought and which is the name of the +part under which you can order the part there. +An order information can contain multiple price information, which describes the prices for the part at the supplier +including bulk discount, etc. ### Parameters -Parameters represents various specifications / parameters of a part, like the the maximum current of a diode, etc. The advantage of using parameters instead of just putting the data in the comment field or so, is that you can filter for parameters values (including ranges and more) later on. -Parameters describe can describe numeric values and/or text values for which they can be filtered. This basically allows you to define custom fields on a part. -Using the group field a parameter allows you to group parameters together in the info page later (all parameters with the same group value will be shown under the same group title). +Parameters represent various specifications/parameters of a part, like the maximum current of a diode, etc. The +advantage of using parameters instead of just putting the data in the comment field or so, is that you can filter for +parameter's values (including ranges and more) later on. +Parameters can describe numeric values and/or text values for which they can be filtered. This allows +you to define custom fields on a part. + +Using the group field as a parameter allows you to group parameters together on the info page later (all parameters with +the same group value will be shown under the same group title). ## Core data + ### Category -A category is used to group parts logically by their function (e.g. all NPN transistors would be put in a "NPN-Transistors" category). -Categories are hierarchical structures meaning that you can create logical trees to group categories together. A possible category tree could look like this: +A category is used to group parts logically by their function (e.g. all NPN transistors would be put in a " +NPN-Transistors" category). +Categories are hierarchical structures meaning that you can create logical trees to group categories together. A +possible category tree could look like this: * Active Components * Transistors @@ -60,97 +95,148 @@ Categories are hierarchical structures meaning that you can create logical trees * MCUs * Passive Components * Capacitors - * Resitors + * Resistors ### Supplier -A Supplier is a vendor / distributor where you can buy/order parts. Price informations of parts are associated with a supplier. + +A Supplier is a vendor/distributor where you can buy/order parts. Price information of parts is associated with a +supplier. ### Manufacturer -A manufacturer represents the company that manufacturer / build various parts (not necessary sell them). If the manufacturer also sell the parts, you have to create a supplier for that. -### Storelocation -A storelocation represents a place where parts can be stored. This could be a box, a shelf or other things (like the SMD feeder of a machine or so). +A manufacturer represents the company that manufacturers/builds various parts (not necessarily sell them). If the +manufacturer also sells the parts, you have to create a supplier for that. -Storelocations are hierarchical to represent storelocations contained in each other. +### Storage location + +A storage location represents a place where parts can be stored. This could be a box, a shelf, or other things (like the +SMD feeder of a machine or so). + +Storage locations are hierarchical to represent storage locations contained in each other. An example tree could look like this: + * Shelf 1 - * Box 1 - * Box 2 - * Box shelf A1 - * Box shelf A2 - * Box shelf B1 - * Box shelf B2 + * Box 1 + * Box 2 + * Box shelf A1 + * Box shelf A2 + * Box shelf B1 + * Box shelf B2 * Shelf 2 * Cupboard -Storelocations should be defined down to the smallest possible location, to make finding the part again easy. +Storage locations should be defined down to the smallest possible location, to make finding the part again easy. ### Footprint -In electronics many components have one of the common components cases / footprints. The footprint entity describes such common footprints, which can be assigned to parts. -You can assign an image (and an 3D model) as an attachment to a footprint, which will be used as preview for parts with this footprint, even if the parts do not have an explicitly assigned preview image. -Footprints are a hierachically which allows you to build logical sorted trees. An example tree could look like this: +In electronics, many components have one of the common components cases/footprints. The footprint entity describes such +common footprints, which can be assigned to parts. +You can assign an image (and a 3D model) as an attachment to a footprint, which will be used as preview for parts with +this footprint, even if the parts do not have an explicitly assigned preview image. + +Footprints are hierarchically which allows you to build logically sorted trees. An example tree could look like this: * Through-Hole components * DIP - * DIP-8 - * DIP-28 - * DIP-28W + * DIP-8 + * DIP-28 + * DIP-28W * TO - * TO-92 + * TO-92 * SMD components * SOIC - * SO-8 + * SO-8 * Resistors - * 0805 - * 0603 + * 0805 + * 0603 ### Measurement Unit -By default part instock is counted in number of individual parts, which is fine for things like electronic components, which exists only in integer quantities. However if you have things with fractional units like the length of a wire or the volume of a liquid, you have to define a measurement unit. -The measurement unit represents a physical quantity like mass, volume or length. -You can define a short unit for it (like m for Meters, or g for gramms) which will be shown, when a quantity of a part with this unit is shown. +By default, part in stock is counted in number of individual parts, which is fine for things like electronic components, +which exist only in integer quantities. However, if you have things with fractional units like the length of a wire or +the volume of a liquid, you have to define a measurement unit. +The measurement unit represents a physical quantity like mass, volume, or length. + +You can define a short unit for it (like m for Meters, or g for grams) which will be shown when a quantity of a part +with this unit is shown. + +In order to cover wider use cases and allow you to define measurement units further, it is possible to define parameters +associated to a measurement unit. These parameters are distinct from a part's parameters and are not inherited. ### Currency -By default all prices are set in the base currency configured for the instance (by default euros). If you want to use multiple currencies together (as e.g. vendors use foreign currencies for their price and you do not want to update the prices for every exchange rate change), you have to define these currencies here. -You can set an exchange rate here in terms of the base currency (or fetch it from the internet if configured). The exchange rate will be used to show users the prices in their preferred currency. +By default, all prices are set in the base currency configured for the instance (by default euros). If you want to use +multiple currencies together (e.g. vendors use foreign currencies for their price, and you do not want to update the +prices for every exchange rate change), you have to define these currencies here. + +You can set an exchange rate here in terms of the base currency (or fetch it from the internet if configured). The +exchange rate will be used to show users the prices in their preferred currency. ## Attachments + ### Attachment -An attachment is an file that can be associated with another entity (like a Part, Storelocation, User, etc.). This could for example be a datasheet in a Part, the logo of a vendor or some CAD drawing of a footprint. -An attachment has an attachment type (see below), which groups the attachments logically (and optionally restricts the allowed file types), a name describing the attachment and a file. The file can either be uploaded to the server and stored there, or given as a link to a file on another webpath. If configured in the settings, it is also possible that the webserver downloads the file from the supplied website and stores it locally on the server. +An attachment is a file that can be associated with another entity (like a Part, location, User, etc.). This could +for example be a datasheet in a Part, the logo of a vendor or some CAD drawing of a footprint. -By default all uploaded files, are accessible for everyone (even non logged in users), if the link is known. If your Part-DB instance is publicly available and you want to store private/sensitve files on it, you should mark the attachment as "Private attachment". Private attachments are only accessible to users, which has the permission to access private attachments. -Please not, that no thumbnails are generated for private attachments, which can have an performance impact. +An attachment has an attachment type (see below), which groups the attachments logically (and optionally restricts the +allowed file types), a name describing the attachment and a file. The file can either be uploaded to the server and +stored there, or given as a link to a file on another web path. If configured in the settings, it is also possible that +the web server downloads the file from the supplied website and stores it locally on the server. -Part-DB ships some preview images for various common footprints like DIP-8 and others, as internal ressources. These can be accessed/searched by typing the keyword in the URL field of a part and choosing one of the choices from the dropdown. +By default, all uploaded files, are accessible for everyone (even non-logged-in users), if the link is known. If your +Part-DB instance is publicly available, and you want to store private/sensitive files on it, you should mark the +attachment as "Private attachment". Private attachments are only accessible to users, which has permission to access +private attachments. +Please note, that no thumbnails are generated for private attachments, which can have a performance impact. -### Preview image / attachment -Most entities with attachments allow you to select one of the defined attachments as "Preview image". You can select an image attachment here, that previews the entity, this could be a picture of a Part, the logo of a manufacturer or supplier, the schematic symbol of a category or the image of an footprint. -The preview image will be shown in various locations together with the entities name. +Part-DB ships some preview images for various common footprints like DIP-8 and others, as internal resources. These can +be accessed/searched by typing the keyword in the URL field of a part and choosing one of the choices from the dropdown. -Please note that as long as the picture is not secret, it should be stored on the Part-DB instance (by upload, or letting Part-DB download the file) and *not* be marked as a private attachments, so that thumbnails can be generated for the picture (which improves performance). +### Preview image/attachment +Most entities with attachments allow you to select one of the defined attachments as "Preview image". You can select an +image attachment here, that previews the entity, this could be a picture of a Part, the logo of a manufacturer or +supplier, the schematic symbol of a category or the image of a footprint. +The preview image will be shown in various locations together with the entity's name. + +Please note that as long as the picture is not secret, it should be stored on the Part-DB instance (by uploading, or +letting Part-DB download the file) and *not* be marked as a private attachment, so that thumbnails can be generated for +the picture (which improves performance). ### Attachment types -Attachment types define logical groups of attachments. For example you could define an attachment group "Datasheets" where all datasheets of Parts, Footprints, etc. belong in, "Pictures" for preview images and more. -You can define file type restrictions, which file types and extensions are allowed for files with that attachment type. + +Attachment types define logical groups of attachments. For example, you could define an attachment group "Datasheets" +where all datasheets of Parts, Footprints, etc. belong in, "Pictures" for preview images and more. +You can define file type restrictions, and which file types and extensions are allowed for files with that attachment type. ## User System -### User -Each person which should be able to use Part-DB (by logging in) is represented by an user entity, which defines things like access rights, the password, and other things. For security reasons, every person which will use Part-DB should use its own personal account with an secret password. This allows to track activity of the users via the log. -There is a special user called `anonymous`, whose access rights are used to determine what an non-logged in user can do. Normally the anonymous user should be the most restricted user. +### User + +Each person who should be able to use Part-DB (by logging in) is represented by a user entity, which defines things +like access rights, the password, and other things. For security reasons, every person who will use Part-DB should use +their own personal account with a secret password. This allows to track activity of the users via the log. + +There is a special user called `anonymous`, whose access rights are used to determine what a non-logged-in user can do. +Normally the anonymous user should be the most restricted user. For simplification of access management users can be assigned to groups. ### Group -A group is entity, to which users can be assigned to. This can be used to logically group users by for example organisational structures and to simplify permissions managment, as you can define groups with access rights for common use cases and then just assign users to them, without the need to change every permission on the users individually. + +A group is an entity, to which users can be assigned to. This can be used to logically group users by for example +organizational structures and to simplify permissions management, as you can define groups with access rights for common +use cases and then just assign users to them, without the need to change every permission on the users individually. ## Labels -### Label profiles -A label profile represents an template for a label (for a storelocation, a part or part lot). It consists of a size, an barcode type and the content. There are various placeholders which can be inserted in the text content and which will be used replaced with data for the actual thing. -You do not have to define a label profile to generate labels (you can just set the settings on the fly in the label dialog), however if you want to generate many labels, it is recommended to save the settings as label profile, to save it for later usage. This ensures that all generated labels look the same. \ No newline at end of file +### Label profiles + +A label profile represents a template for a label (for a storage location, a part or part lot). It consists of a size, a +barcode type and the content. There are various placeholders that can be inserted in the text content and which will be +replaced with data for the actual thing. + +You do not have to define a label profile to generate labels (you can just set the settings on the fly in the label +dialog), however, if you want to generate many labels, it is recommended to save the settings as a label profile, to save +it for later usage. This ensures that all generated labels look the same. diff --git a/docs/configuration.md b/docs/configuration.md index c0f00933..0ad30a00 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -6,106 +6,250 @@ nav_order: 5 # Configuration -Part-DBs behavior can be configured to your needs. There are different kind of configuration options: Options which are user changable (changable dynamically via frontend), options which can be configured by environment variables, and options which are only configurable via symfony config files. +Part-DBs behavior can be configured to your needs. There are different kinds of configuration options: Options, which are +user-changeable (changeable dynamically via frontend), options that can be configured by environment variables, and +options that are only configurable via Symfony config files. -## User changable -Following things can be changed for every user and a user can change it for himself (if he has the correct permission for it). Configuration is either possible via the users own setting page (where you can also change the password) or via the user admin page: -* **Language**: The language that the users prefers, and which will be used when no language is explicitly specified. Language can still always be changed via the language selector. By default the global configured language is used. -* **Timezone**: The timezone which the user resides in and in which all dates and times should be shown. By default the globally configured language. -* **Theme**: The theme to use for the frontend. Allows the user to choose the frontend design, he prefers. -* **Prefered currency**: One of the defined currencies, in which all prices should be shown, if possible. Prices with other currencies will be converted to the price selected here +## User changeable + +The following things can be changed for every user and a user can change it for himself (if he has the correct permission +for it). Configuration is either possible via the user's own settings page (where you can also change the password) or via +the user admin page: + +* **Language**: The language that the users prefer, and which will be used when no language is explicitly specified. + Language can still always be changed via the language selector. By default, the globally configured language is used. +* **Timezone**: The timezone in which the user resides and in which all dates and times should be shown. By default, the + globally configured language. +* **Theme**: The theme to use for the front end. Allows the user to choose the front end design, he prefers. +* **Preferred currency**: One of the defined currencies, in which all prices should be shown, if possible. Prices with + other currencies will be converted to the price selected here ## Environment variables (.env.local) -The following configuration options can only be changed by the server administrator, by either changing the server variables, changing the `.env.local` file or setting env for your docker container. Here are just the most important options listed, see `.env` file for full list of possible env variables. + +The following configuration options can only be changed by the server administrator, by either changing the server +variables, changing the `.env.local` file or setting env for your docker container. Here are just the most important +options listed, see `.env` file for the full list of possible env variables. ### General options -* `DATABASE_URL`: Configures the database which Part-DB uses. For mysql use a string in the form of `mysql://:@:/` here (e.g. `DATABASE_URL=mysql://user:password@127.0.0.1:3306/part-db`. For sqlite use the following format to specify the absolute path where it should be located `sqlite:///path/part/app.db`. You can use `%kernel.project_dir%` as placeholder for the Part-DB root folder (e.g. `sqlite:///%kernel.project_dir%/var/app.db`) -* `DEFAULT_LANG`: The default language to use serverwide (when no language is explictly specified by a user or via language chooser). Must be something like `en`, `de`, `fr`, etc. -* `DEFAULT_TIMEZONE`: The default timezone to use globally, when a user has not timezone specified. Must be something like `Europe/Berlin`. See [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) under TZ Database name for a list of available options. -* `BASE_CURRENCY`: The currency to use internally for monetary values and when no currency is explictly specified. When migrating from a legacy Part-DB version, this should be the same as the currency in the old Part-DB instance (normally euro). This should be the currency you use the most. **Please note that you can not really change this setting after you have created data**. The value has to be a valid [ISO4217](https://en.wikipedia.org/wiki/ISO_4217) code, like `EUR` or `USD`. -* `INSTANCE_NAME`: The name of your installation. It will be shown as a title in the navbar and other places. By default `Part-DB`, but you can customize it to something likes `ExampleCorp. Inventory`. -* `ALLOW_ATTACHMENT_DOWNLOADS` (allowed values `0` or `1`): By setting this option to 1, users can make Part-DB directly download a file specified as an URL and create it as local file. Please not that this allows users access to all ressources publicly available to the server (so full access to other servers in the same local network), which could be a security risk. -* `USE_GRAVATAR`: Set to `1` to use [gravatar.com](gravatar.com) images for user avatars (as long as they have not set their own picture). The users browsers have to download the pictures from a third-party (gravatars) server, so this might be a privacy risk. -* `MAX_ATTACHMENT_FILE_SIZE`: The maximum file size (in bytes) for attachments. You can use the suffix `K`, `M` or `G` to specify the size in kilobytes, megabytes or gigabytes. By default `100M` (100 megabytes). Please note that this only the limit of Part-DB. You still need to configure the php.ini `upload_max_filesize` and `post_max_size` to allow bigger files to be uploaded. -* `DEFAULT_URI`: The default URI base to use for the Part-DB, when no URL can be determined from the browser request. This should be the primary URL/Domain, which is used to access Part-DB. This value is used to create correct links in emails and other places, where the URL is needed. It is also used, when SAML is enabled.s If you are using a reverse proxy, you should set this to the URL of the reverse proxy (e.g. `https://part-db.example.com`). **This value must end with a slash**. -* `ENFORCE_CHANGE_COMMENTS_FOR`: With this option you can configure, where users are enforced to give a change reason, which will be written to the log. This is a comma separated list of values (e.g. `part_edit,part_delete`). Leave empty to make change comments optional everywhere. Possible values are: - * `part_edit`: Edit operation of a existing part - * `part_delete`: Delete operation of a existing part - * `part_create`: Creation of a new part - * `part_stock_operation`: Stock operation on a part (therefore withdraw, add or move stock) - * `datastructure_edit`: Edit operation of a existing datastructure (e.g. category, manufacturer, ...) - * `datastructure_delete`: Delete operation of a existing datastructure (e.g. category, manufacturer, ...) - * `datastructure_create`: Creation of a new datastructure (e.g. category, manufacturer, ...) + +* `DATABASE_URL`: Configures the database which Part-DB uses: + * For MySQL (or MariaDB) use a string in the form of `mysql://:@:/` here + (e.g. `DATABASE_URL=mysql://user:password@127.0.0.1:3306/part-db`). + * For SQLite use the following format to specify the + absolute path where it should be located `sqlite:///path/part/app.db`. You can use `%kernel.project_dir%` as + placeholder for the Part-DB root folder (e.g. `sqlite:///%kernel.project_dir%/var/app.db`) + * For Postgresql use a string in the form of `DATABASE_URL=postgresql://user:password@127.0.0.1:5432/part-db?serverVersion=x.y`. + + Please note that **`serverVersion=x.y`** variable is required due to dependency of Symfony framework. + +* `DATABASE_MYSQL_USE_SSL_CA`: If this value is set to `1` or `true` and a MySQL connection is used, then the connection + is encrypted by SSL/TLS and the server certificate is verified against the system CA certificates or the CA certificate +bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept all certificates. +* `DATABASE_EMULATE_NATURAL_SORT` (default 0): If set to 1, Part-DB will emulate natural sorting, even if the database + does not support it natively. However this is much slower than the native sorting, and contain bugs or quirks, so use + it only, if you have to. +* `DEFAULT_LANG`: The default language to use server-wide (when no language is explicitly specified by a user or via + language chooser). Must be something like `en`, `de`, `fr`, etc. +* `DEFAULT_TIMEZONE`: The default timezone to use globally, when a user has no timezone specified. Must be something + like `Europe/Berlin`. See [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) under TZ Database name + for a list of available options. +* `BASE_CURRENCY`: The currency to use internally for monetary values and when no currency is explicitly specified. When + migrating from a legacy Part-DB version, this should be the same as the currency in the old Part-DB instance (normally + euro). This should be the currency you use the most. **Please note that you can not really change this setting after + you have created data**. The value has to be a valid [ISO4217](https://en.wikipedia.org/wiki/ISO_4217) code, + like `EUR` or `USD`. +* `INSTANCE_NAME`: The name of your installation. It will be shown as a title in the navbar and other places. By + default `Part-DB`, but you can customize it to something likes `ExampleCorp. Inventory`. +* `ALLOW_ATTACHMENT_DOWNLOADS` (allowed values `0` or `1`): By setting this option to 1, users can make Part-DB directly + download a file specified as a URL and create it as a local file. Please note that this allows users access to all + resources publicly available to the server (so full access to other servers in the same local network), which could + be a security risk. +* `ATTACHMENT_DOWNLOAD_BY_DEFAULT`: When this is set to 1, the "download external file" checkbox is checked by default + when adding a new attachment. Otherwise, it is unchecked by default. Use this if you wanna download all attachments + locally by default. Attachment download is only possible, when `ALLOW_ATTACHMENT_DOWNLOADS` is set to 1. +* `USE_GRAVATAR`: Set to `1` to use [gravatar.com](https://gravatar.com/) images for user avatars (as long as they have + not set their own picture). The users browsers have to download the pictures from a third-party (gravatar) server, so + this might be a privacy risk. +* `MAX_ATTACHMENT_FILE_SIZE`: The maximum file size (in bytes) for attachments. You can use the suffix `K`, `M` or `G` + to specify the size in kilobytes, megabytes or gigabytes. By default `100M` (100 megabytes). Please note that this is + only the limit of Part-DB. You still need to configure the php.ini `upload_max_filesize` and `post_max_size` to allow + bigger files to be uploaded. +* `DEFAULT_URI`: The default URI base to use for the Part-DB, when no URL can be determined from the browser request. + This should be the primary URL/Domain, which is used to access Part-DB. This value is used to create correct links in + emails and other places, where the URL is needed. It is also used, when SAML is enabled.s If you are using a reverse + proxy, you should set this to the URL of the reverse proxy (e.g. `https://part-db.example.com`). **This value must end + with a slash**. +* `ENFORCE_CHANGE_COMMENTS_FOR`: With this option, you can configure, where users are enforced to give a change reason, + which will be written to the log. This is a comma-separated list of values (e.g. `part_edit,part_delete`). Leave empty + to make change comments optional everywhere. Possible values are: + * `part_edit`: Edit operation of an existing part + * `part_delete`: Delete operation of an existing part + * `part_create`: Creation of a new part + * `part_stock_operation`: Stock operation on a part (therefore withdraw, add or move stock) + * `datastructure_edit`: Edit operation of an existing datastructure (e.g. category, manufacturer, ...) + * `datastructure_delete`: Delete operation of a existing datastructure (e.g. category, manufacturer, ...) + * `datastructure_create`: Creation of a new datastructure (e.g. category, manufacturer, ...) +* `CHECK_FOR_UPDATES` (default `1`): Set this to 0, if you do not want Part-DB to connect to GitHub to check for new + versions, or if your server can not connect to the internet. +* `APP_SECRET`: This variable is a configuration parameter used for various security-related purposes, + particularly for securing and protecting various aspects of your application. It's a secret key that is used for + cryptographic operations and security measures (session management, CSRF protection, etc..). Therefore this + value should be handled as confidential data and not shared publicly. ### E-Mail settings -* `MAILER_DSN`: You can configure the mail provider which should be used for email delivery (see https://symfony.com/doc/current/components/mailer.html for full documentation). If you just want to use an SMTP mail account, you can use the following syntax `MAILER_DSN=smtp://user:password@smtp.mailserver.invalid:587` -* `EMAIL_SENDER_EMAIL`: The email address from which emails should be sent from (in most cases this has to be the same as the email address used for SMTP access) -* `EMAIL_SENDER_NAME`: Similar to `EMAIL_SENDER_EMAIL` but this allows you to specify the name from which the mails are sent from. -* `ALLOW_EMAIL_PW_RESET`: Set this value to true, if you wan to allow users to reset their password via an email notification. You have to configure the mailprovider first before via the MAILER_DSN setting. + +* `MAILER_DSN`: You can configure the mail provider which should be used for email delivery ( + see https://symfony.com/doc/current/components/mailer.html for full documentation). If you just want to use an SMTP + mail account, you can use the following syntax `MAILER_DSN=smtp://user:password@smtp.mailserver.invalid:587` +* `EMAIL_SENDER_EMAIL`: The email address from which emails should be sent from (in most cases this has to be the same + as the email address used for SMTP access) +* `EMAIL_SENDER_NAME`: Similar to `EMAIL_SENDER_EMAIL`, but this allows you to specify the name from which the mails are + sent from. +* `ALLOW_EMAIL_PW_RESET`: Set this value to true, if you want to allow users to reset their password via an email + notification. You have to configure the mail provider first before via the MAILER_DSN setting. ### Table related settings -* `TABLE_DEFAULT_PAGE_SIZE`: The default page size for tables. This is the number of rows which are shown per page. Set to `-1` to disable pagination and show all rows at once. -### History/Eventlog related settings +* `TABLE_DEFAULT_PAGE_SIZE`: The default page size for tables. This is the number of rows which are shown per page. Set + to `-1` to disable pagination and show all rows at once. +* `TABLE_PARTS_DEFAULT_COLUMNS`: The columns in parts tables, which are visible by default (when loading table for first + time). + Also specify the default order of the columns. This is a comma separated list of column names. Available columns + are: `name`, `id`, `ipn`, `description`, `category`, `footprint`, `manufacturer`, `storage_location`, `amount`, `minamount`, `partUnit`, `addedDate`, `lastModified`, `needs_review`, `favorite`, `manufacturing_status`, `manufacturer_product_number`, `mass`, `tags`, `attachments`, `edit`. + +### History/Eventlog-related settings + The following options are used to configure, which (and how much) data is written to the system log: -* `HISTORY_SAVE_CHANGED_FIELDS`: When this option is set to true, the name of the fields which are changed, are saved to the DB (so for example it is logged that a user has changed, that the user has changed the name and description of the field, but not the data/content of these changes) -* `HISTORY_SAVE_CHANGED_DATA`: When this option is set to true, the changed data is saved to log (so it is logged, that a user has changed the name of a part and what the name was before). This can increase database size, when you have a lot of changes to entities. -* `HISTORY_SAVE_REMOVED_DATA`: When this option is set to true, removed data is saved to log, meaning that you can easily undelete an entity, when it was removed accidentally. -* `HISTORY_SAVE_NEW_DATA`: When this option is set to true, the new data (the data after a change) is saved to element changed log entries. This allows you to easily see the changes between two revisions of an entity. This can increase database size, when you have a lot of changes to entities. -If you wanna use want to revert changes or view older revisions of entities, then `HISTORY_SAVE_CHANGED_FIELDS`, `HISTORY_SAVE_CHANGED_DATA` and `HISTORY_SAVE_REMOVED_DATA` all have to be true. +* `HISTORY_SAVE_CHANGED_FIELDS`: When this option is set to true, the name of the fields that are changed, are saved to + the DB (so for example it is logged that a user has changed, that the user has changed the name and description of the + field, but not the data/content of these changes) +* `HISTORY_SAVE_CHANGED_DATA`: When this option is set to true, the changed data is saved to log (so it is logged, that + a user has changed the name of a part and what the name was before). This can increase database size when you have a + lot of changes to entities. +* `HISTORY_SAVE_REMOVED_DATA`: When this option is set to true, removed data is saved to log, meaning that you can + easily undelete an entity, when it was removed accidentally. +* `HISTORY_SAVE_NEW_DATA`: When this option is set to true, the new data (the data after a change) is saved to element + changed log entries. This allows you to easily see the changes between two revisions of an entity. This can increase + database size, when you have a lot of changes to entities. + +If you want to use want to revert changes or view older revisions of entities, +then `HISTORY_SAVE_CHANGED_FIELDS`, `HISTORY_SAVE_CHANGED_DATA` and `HISTORY_SAVE_REMOVED_DATA` all have to be true. ### Error pages settings -* `ERROR_PAGE_ADMIN_EMAIL`: You can set an email-address here, which is shown on the error page, who should be contacted about the issue (e.g. an IT support email of your company) -* `ERROR_PAGE_SHOW_HELP`: Set this 0, to disable the solution hints shown on an error page. These hints should not contain senstive informations, but could confuse end-users. + +* `ERROR_PAGE_ADMIN_EMAIL`: You can set an email address here, which is shown on the error page, who should be contacted + about the issue (e.g. an IT support email of your company) +* `ERROR_PAGE_SHOW_HELP`: Set this 0, to disable the solution hints shown on an error page. These hints should not + contain sensitive information but could confuse end-users. + +### EDA related settings + +* `EDA_KICAD_CATEGORY_DEPTH`: A number, which determines how many levels of Part-DB categories should be shown inside KiCad. + All parts in the selected category and all subcategories are shown in KiCad. + For performance reason this value should not be too high. The default is 0, which means that only the top level categories are shown in KiCad. + All parts in the selected category and all subcategories are shown in KiCad. Set this to a higher value, if you want to show more categories in KiCad. + When you set this value to -1, all parts are shown inside a single category in KiCad. ### SAML SSO settings -The following settings can be used to enable and configure Single-Sign on via SAML. This allows users to login to Part-DB without entering a username and password, but instead they are redirected to a SAML Identity Provider (IdP) and are logged in automatically. This is especially useful, when you want to use Part-DB in a company, where all users have a SAML account (e.g. via Active Directory or LDAP). -You can find more advanced settings in the `config/packages/hslavich_onelogin_saml.yaml` file. Please note that this file is not backuped by the backup script, so you have to backup it manually, if you want to keep your changes. If you want to edit it on docker, you have to map the file to a volume. -* `SAML_ENABLED`: When this is set to 1, SAML SSO is enabled and the SSO Login button is shown in the login form. You have to configure the SAML settings below, before you can use this feature. -* `SAML_ROLE_MAPPING`: A [JSON](https://en.wikipedia.org/wiki/JSON) encoded map which specifies how Part-DB should convert the user roles given by SAML attribute `group` should be converted to a Part-DB group (specified by ID). You can use a wildcard `*` to map all otherwise unmapped roles to a certain group. Example: `{"*": 1, "admin": 2, "editor": 3}`. This would map all roles to the group with ID 1, except the role `admin`, which is mapped to the group with ID 2 and the role `editor`, which is mapped to the group with ID 3. -* `SAML_UPDATE_GROUP_ON_LOGIN`: When this is enabled the group of the user is updated on every login of the user based on the SAML role attributes. When this is disabled, the group is only assigned on the first login of the user, and a Part-DB administrator can change the group afterwards by editing the user. -* `SAML_IDP_ENTITY_ID`: The entity ID of your SAML Identity Provider (IdP). You can find this value in the metadata XML file or configuration UI of your IdP. -* `SAML_IDP_SINGLE_SIGN_ON_SERVICE`: The URL of the SAML IdP Single Sign-On Service (SSO). You can find this value in the metadata XML file or configuration UI of your IdP. -* `SAML_IDP_SINGLE_LOGOUT_SERVICE`: The URL of the SAML IdP Single Logout Service (SLO). You can find this value in the metadata XML file or configuration UI of your IdP. -* `SAML_IDP_X509_CERT`: The base64 encoded X.509 public certificate of your SAML IdP. You can find this value in the metadata XML file or configuration UI of your IdP. It should start with `MIIC` and end with `=`. -* `SAML_SP_ENTITY_ID`: The entity ID of your SAML Service Provider (SP). This is the value you have configured for the Part-DB client in your IdP. -* `SAML_SP_X509_CERT`: The public X.509 certificate of your SAML SP (here Part-DB). This is the value you have configured for the Part-DB client in your IdP. It should start with `MIIC` and end with `=`. IdPs like keycloak allows you to generate a public/private key pair for the client which you can setup here and in the `SAML_SP_PRIVATE_KEY` setting. -* `SAML_SP_PRIVATE_KEY`: The private key of your SAML SP (here Part-DB), corresponding the public key specified in `SAML_SP_X509_CERT`. This is the value you have configured for the Part-DB client in your IdP. It should start with `MIIE` and end with `=`. IdPs like keycloak allows you to generate a public/private key pair for the client which you can setup here and in the `SAML_SP_X509_CERT` setting. +The following settings can be used to enable and configure Single-Sign on via SAML. This allows users to log in to +Part-DB without entering a username and password, but instead they are redirected to a SAML Identity Provider (IdP) and +are logged in automatically. This is especially useful when you want to use Part-DB in a company, where all users have +a SAML account (e.g. via Active Directory or LDAP). +You can find more advanced settings in the `config/packages/hslavich_onelogin_saml.yaml` file. Please note that this +file is not backed up by the backup script, so you have to back up it manually, if you want to keep your changes. If you +want to edit it on docker, you have to map the file to a volume. + +* `SAML_ENABLED`: When this is set to 1, SAML SSO is enabled and the SSO Login button is shown in the login form. You + have to configure the SAML settings below before you can use this feature. +* `SAML_BEHIND_PROXY`: Set this to 1, if Part-DB is behind a reverse proxy. See [here]({% link installation/reverse-proxy.md %}) + for more information. Otherwise, leave it to 0 (default.) +* `SAML_ROLE_MAPPING`: A [JSON](https://en.wikipedia.org/wiki/JSON)-encoded map which specifies how Part-DB should + convert the user roles given by SAML attribute `group` should be converted to a Part-DB group (specified by ID). You + can use a wildcard `*` to map all otherwise unmapped roles to a certain group. + Example: `{"*": 1, "admin": 2, "editor": 3}`. This would map all roles to the group with ID 1, except the + role `admin`, which is mapped to the group with ID 2, and the role `editor`, which is mapped to the group with ID 3. +* `SAML_UPDATE_GROUP_ON_LOGIN`: When this is enabled the group of the user is updated on every login of the user based + on the SAML role attributes. When this is disabled, the group is only assigned on the first login of the user, and a + Part-DB administrator can change the group afterward by editing the user. +* `SAML_IDP_ENTITY_ID`: The entity ID of your SAML Identity Provider (IdP). You can find this value in the metadata XML + file or configuration UI of your IdP. +* `SAML_IDP_SINGLE_SIGN_ON_SERVICE`: The URL of the SAML IdP Single Sign-On Service (SSO). You can find this value in + the metadata XML file or configuration UI of your IdP. +* `SAML_IDP_SINGLE_LOGOUT_SERVICE`: The URL of the SAML IdP Single Logout Service (SLO). You can find this value in the + metadata XML file or configuration UI of your IdP. +* `SAML_IDP_X509_CERT`: The base64 encoded X.509 public certificate of your SAML IdP. You can find this value in the + metadata XML file or configuration UI of your IdP. It should start with `MIIC` and end with `=`. +* `SAML_SP_ENTITY_ID`: The entity ID of your SAML Service Provider (SP). This is the value you have configured for the + Part-DB client in your IdP. +* `SAML_SP_X509_CERT`: The public X.509 certificate of your SAML SP (here Part-DB). This is the value you have + configured for the Part-DB client in your IdP. It should start with `MIIC` and end with `=`. IdPs like keycloak allows + you to generate a public/private key pair for the client which you can set up here and in the `SAML_SP_PRIVATE_KEY` + setting. +* `SAML_SP_PRIVATE_KEY`: The private key of your SAML SP (here Part-DB), corresponding the public key specified + in `SAML_SP_X509_CERT`. This is the value you have configured for the Part-DB client in your IdP. It should start + with `MIIE` and end with `=`. IdPs like keycloak allows you to generate a public/private key pair for the client which + you can set up here and in the `SAML_SP_X509_CERT` setting. ### Information provider settings + The settings prefixes with `PROVIDER_*` are used to configure the information providers. See the [information providers]({% link usage/information_provider_system.md %}) page for more information. -### Other / less used options -* `TRUSTED_PROXIES`: Set the IP addresses (or IP blocks) of trusted reverse proxies here. This is needed to get correct IP informations (see [here](https://symfony.com/doc/current/deployment/proxies.html) for more info). -* `TRUSTED_HOSTS`: To prevent `HTTP Host header attacks` you can set a regex containing all host names via which Part-DB should be accessible. If accessed via the wrong hostname, an error will be shown. -* `DEMO_MODE`: Set Part-DB into demo mode, which forbids users to change their passwords and settings. Used for the demo instance, should not be needed for normal installations. -* `NO_URL_REWRITE_AVAILABLE` (allowed values `true` or `false`): Set this value to true, if your webserver does not support rewrite. In this case, all URL pathes will contain index.php/, which is needed then. Normally this setting do not need to be changed. -* `FIXER_API_KEY`: If you want to automatically retrieve exchange rates for base currencies other than euros, you have configure an exchange rate provider API. [Fixer.io](https://fixer.io/) is preconfigured, and you just have to register there and set the retrieved API key in this environment variable. -* `APP_ENV`: This value should always be set to `prod` in normal use. Set it to `dev` to enable debug/development mode. (**You should not do this on a publicly accessible server, as it will leak sensitive informations!**) -* `BANNER`: You can configure the text that should be shown as the banner on the homepage. Useful especially for docker container. In all other applications you can just change the `config/banner.md` file. +### Other / less-used options + +* `TRUSTED_PROXIES`: Set the IP addresses (or IP blocks) of trusted reverse proxies here. This is needed to get correct + IP information (see [here](https://symfony.com/doc/current/deployment/proxies.html) for more info). +* `TRUSTED_HOSTS`: To prevent `HTTP Host header attacks` you can set a regex containing all host names via which Part-DB + should be accessible. If accessed via the wrong hostname, an error will be shown. +* `DEMO_MODE`: Set Part-DB into demo mode, which forbids users to change their passwords and settings. Used for the demo + instance. This should not be needed for normal installations. +* `NO_URL_REWRITE_AVAILABLE` (allowed values `true` or `false`): Set this value to true, if your webserver does not + support rewrite. In this case, all URL paths will contain index.php/, which is needed then. Normally this setting does + not need to be changed. +* `REDIRECT_TO_HTTPS`: If this is set to true, all requests to http will be redirected to https. This is useful if your + web server does not already do this (like the one used in the demo instance). If your web server already redirects to + https, you don't need to set this. Ensure that Part-DB is accessible via HTTPS before you enable this setting. +* `FIXER_API_KEY`: If you want to automatically retrieve exchange rates for base currencies other than euros, you have to + configure an exchange rate provider API. [Fixer.io](https://fixer.io/) is preconfigured, and you just have to register + there and set the retrieved API key in this environment variable. +* `APP_ENV`: This value should always be set to `prod` in normal use. Set it to `dev` to enable debug/development + mode. (**You should not do this on a publicly accessible server, as it will leak sensitive information!**) +* `BANNER`: You can configure the text that should be shown as the banner on the homepage. Useful especially for docker + containers. In all other applications you can just change the `config/banner.md` file. +* `DISABLE_YEAR2038_BUG_CHECK`: If set to `1`, the year 2038 bug check is disabled on 32-bit systems, and dates after +2038 are no longer forbidden. However this will lead to 500 error messages when rendering dates after 2038 as all current +32-bit PHP versions can not format these dates correctly. This setting is for the case that future PHP versions will +handle this correctly on 32-bit systems. 64-bit systems are not affected by this bug, and the check is always disabled. ## Banner + To change the banner you can find on the homepage, you can either set the `BANNER` environment variable to the text you want to show, or you can edit the `config/banner.md` file. The banner is written in markdown, so you can use all markdown (and even some subset of HTML) syntax to format the text. ## parameters.yaml -You can also configure some options via the `config/parameters.yaml` file. This should normally not needed, -and you should know what you are doing, when you change something here. You should expect, that you will have to do some -manual merge, when you have changed something here and update to a newer version of Part-DB. It is possible that configuration -options here will change or completely removed in future versions of Part-DB. -If you change something here, you have to clear the cache, before the changes will take effect with the command `bin/console cache:clear`. +You can also configure some options via the `config/parameters.yaml` file. This should normally not need, +and you should know what you are doing, when you change something here. You should expect, that you will have to do some +manual merge, when you have changed something here and update to a newer version of Part-DB. It is possible that +configuration options here will change or be completely removed in future versions of Part-DB. + +If you change something here, you have to clear the cache, before the changes will take effect with the +command `bin/console cache:clear`. The following options are available: -* `partdb.global_theme`: The default theme to use, when no user specific theme is set. Should be one of the themes from the `partdb.available_themes` config option. -* `partdb.locale_menu`: The codes of the languages, which should be shown in the language chooser menu (the one with the user icon in the navbar). The first language in the list will be the default language. -* `partdb.gdpr_compliance`: When set to true (default value), IP addresses which are saved in the database will be anonymized, by removing the last byte of the IP. This is required by the GDPR (General Data Protection Regulation) in the EU. -* `partdb.sidebar.items`: The panel contents which should be shown in the sidebar by default. You can also change the number of sidebar panels by changing the number of items in this list. +* `partdb.global_theme`: The default theme to use, when no user specific theme is set. Should be one of the themes from + the `partdb.available_themes` config option. +* `partdb.locale_menu`: The codes of the languages, which should be shown in the language chooser menu (the one with the + user icon in the navbar). The first language in the list will be the default language. +* `partdb.gdpr_compliance`: When set to true (default value), IP addresses which are saved in the database will be + anonymized, by removing the last byte of the IP. This is required by the GDPR (General Data Protection Regulation) in + the EU. +* `partdb.sidebar.items`: The panel contents which should be shown in the sidebar by default. You can also change the + number of sidebar panels by changing the number of items in this list. * `partdb.sidebar.root_node_enable`: Show a root node in the sidebar trees, of which all nodes are children of * `partdb.sidebar.root_expanded`: Expand the root node in the sidebar trees by default -* `partdb.available_themes`: The list of available themes a user can choose from. \ No newline at end of file +* `partdb.available_themes`: The list of available themes a user can choose from. diff --git a/docs/index.md b/docs/index.md index 200f2919..d732f31d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,39 +5,52 @@ nav_order: 0 --- # Part-DB + Part-DB is an Open-Source inventory management system for your electronic components. It is installed on a web server and so can be accessed with any browser without the need to install additional software. {: .important-title } > Demo -> -> If you want to test Part-DB without installing it, you can use [this](https://part-db.herokuapp.com) Heroku instance. -> (Or this link for the [German Version](https://part-db.herokuapp.com/de/)). +> +> If you want to test Part-DB without installing it, you can use [this](https://demo.part-db.de/) Heroku instance. +> (Or this link for the [German Version](https://demo.part-db.de/de/)). > > You can log in with username: **user** and password: **user**, to change/create data. > -> Every change to the master branch gets automatically deployed, so it represents the currenct development progress and is -> maybe not completly stable. Please mind, that the free Heroku instance is used, so it can take some time when loading the page +> Every change to the master branch gets automatically deployed, so it represents the current development progress and +> is +> maybe not completely stable. Please mind, that the free Heroku instance is used, so it can take some time when loading +> the page > for the first time. ## Features -* Inventory management of your electronic parts. Each part can be assigned to a category, footprint, manufacturer - and multiple store locations and price information. Parts can be grouped using tags. You can associate various files like datasheets or pictures with the parts. -* Multi-Language support (currently German, English, Russian, Japanese and French (experimental)) + +* Inventory management of your electronic parts. Each part can be assigned to a category, footprint, manufacturer, + and multiple store locations and price information. Parts can be grouped using tags. You can associate various files + like datasheets or pictures with the parts. +* Multi-language support (currently German, English, Russian, Japanese and French (experimental)) * Barcodes/Labels generator for parts and storage locations, scan barcodes via webcam using the builtin barcode scanner * User system with groups and detailed (fine granular) permissions. - Two-factor authentication is supported (Google Authenticator and Webauthn/U2F keys) and can be enforced for groups. Password reset via email can be setuped. -* Optional support for single sign-on (SSO) via SAML (using an intermediate service like [Keycloak](https://www.keycloak.org/) you can connect Part-DB to an existing LDAP or Active Directory server) + Two-factor authentication is supported (Google Authenticator and Webauthn/U2F keys) and can be enforced for groups. + Password reset via email can be setup. +* Optional support for single sign-on (SSO) via SAML (using an intermediate service + like [Keycloak](https://www.keycloak.org/) you can connect Part-DB to an existing LDAP or Active Directory server) * Import/Export system -* Project management: Create projects and assign parts to the bill of material (BOM), to show how often you could build this project and directly withdraw all components needed from DB -* Event log: Track what changes happens to your inventory, track which user does what. Revert your parts to older versions. +* Project management: Create projects and assign parts to the bill of material (BOM), to show how often you could build + this project and directly withdraw all components needed from DB +* Event log: Track what changes happens to your inventory, track which user does what. Revert your parts to older + versions. * Responsive design: You can use Part-DB on your PC, your tablet and your smartphone using the same interface. -* MySQL and SQLite supported as database backends +* MySQL, SQLite and PostgreSQL are supported as database backends * Support for rich text descriptions and comments in parts * Support for multiple currencies and automatic update of exchange rates supported * Powerful search and filter function, including parametric search (search for parts according to some specifications) * Easy migration from an existing PartKeepr instance (see [here]({%link partkeepr_migration.md %})) -* Use cloud providers (like Octopart, Digikey, farnell or TME) to automatically get part information, datasheets and prices for parts (see [here]({% link usage/information_provider_system.md %})) +* Use cloud providers (like Octopart, Digikey, Farnell or TME) to automatically get part information, datasheets and + prices for parts (see [here]({% link usage/information_provider_system.md %})) +* API to access Part-DB from other applications/scripts +* [Integration with KiCad]({%link usage/eda_integration.md %}): Use Part-DB as central datasource for your + KiCad and see available parts from Part-DB directly inside KiCad. With these features Part-DB is useful to hobbyists, who want to keep track of their private electronic parts inventory, or makerspaces, where many users have should have (controlled) access to the shared inventory. @@ -45,25 +58,31 @@ or makerspaces, where many users have should have (controlled) access to the sha Part-DB is also used by small companies and universities for managing their inventory. ## License + Part-DB is licensed under the GNU Affero General Public License v3.0 (or at your opinion any later). This mostly means that you can use Part-DB for whatever you want (even use it commercially) as long as you publish the source code for every change you make under the AGPL, too. -See [LICENSE](https://github.com/Part-DB/Part-DB-symfony/blob/master/LICENSE) for more informations. +See [LICENSE](https://github.com/Part-DB/Part-DB-symfony/blob/master/LICENSE) for more information. ## Donate for development + If you want to donate to the Part-DB developer, see the sponsor button in the top bar (next to the repo name). There you will find various methods to support development on a monthly or a one time base. ## Built with + * [Symfony 5](https://symfony.com/): The main framework used for the serverside PHP * [Bootstrap 5](https://getbootstrap.com/) and [Bootswatch](https://bootswatch.com/): Used as website theme * [Fontawesome](https://fontawesome.com/): Used as icon set -* [Hotwire Stimulus](https://stimulus.hotwired.dev/) and [Hotwire Turbo](https://turbo.hotwired.dev/): Frontend Javascript +* [Hotwire Stimulus](https://stimulus.hotwired.dev/) and [Hotwire Turbo](https://turbo.hotwired.dev/): Frontend + Javascript ## Authors -* **Jan Böhmer** - *Inital work and Maintainer* - [Github](https://github.com/jbtronics/) -See also the list of [contributors](https://github.com/Part-DB/Part-DB-symfony/graphs/contributors) who participated in this project. +* **Jan Böhmer** - *Initial work and Maintainer* - [GitHub](https://github.com/jbtronics/) + +See also the list of [contributors](https://github.com/Part-DB/Part-DB-symfony/graphs/contributors) who participated in +this project. Based on the original Part-DB by Christoph Lechner and K. Jacobs diff --git a/docs/installation/choosing_database.md b/docs/installation/choosing_database.md index b3a7a3a8..cd9657d4 100644 --- a/docs/installation/choosing_database.md +++ b/docs/installation/choosing_database.md @@ -7,24 +7,176 @@ nav_order: 1 # Choosing database: SQLite or MySQL -Part-DB saves its data in a [relational (SQL) database](https://en.wikipedia.org/wiki/Relational_database). Part-DB supports either the use of [SQLite](https://www.sqlite.org/index.html) or [MySQL](https://www.mysql.com/) / [MariaDB](https://mariadb.org/) (which are mostly the same, except for some minor differences). +Part-DB saves its data in a [relational (SQL) database](https://en.wikipedia.org/wiki/Relational_database). + +For this multiple database types are supported, currently these are: + +* [SQLite](https://www.sqlite.org/index.html) +* [MySQL](https://www.mysql.com/) / [MariaDB](https://mariadb.org/) (which are mostly the same, except for some minor + differences) +* [PostgreSQL](https://www.postgresql.org/) + +All these database types allow for the same basic functionality and allow Part-DB to run. However, there are some minor +differences between them, which might be important for you. Therefore the pros and cons of the different database types +are listed here. {: .important } -You have to choose between the database types before you start using Part-DB and **you can not change it (easily) after you have started creating data**. So you should choose the database type for your usecase (and possible future uses). +You have to choose between the database types before you start using Part-DB and **you can not change it (easily) after +you have started creating data**. So you should choose the database type for your use case (and possible future uses). ## Comparison -**SQLite** is the default database type which is configured out of the box. All data is saved in a single file (normally `var/app.db` in the Part-DB folder) and no additional installation or configuration besides Part-DB is needed. -To use **MySQL/MariaDB** as database, you have to install and configure the MySQL server, configure it and create a database and user for Part-DB, which needs some additional work. When using docker you need an additional docker container, and volume for the data +### SQLite -When using **SQLite** The database can be backuped easily by just copying the SQLite file to a safe place. Ideally the **MySQL** database has to be dumped to a SQL file (using `mysqldump`). The `console partdb:backup` command can do this automatically - -However SQLite does not support certain operations like regex search, which has to be emulated by PHP and therefore are pretty slow compared to the same operation at MySQL. In future there might be features that may only be available, when using MySQL. +#### Pros -In general MySQL might perform better for big Part-DB instances with many entries, lots of users and high activity, than SQLite. +* **Easy to use**: No additional installation or configuration is needed, just start Part-DB and it will work out of the box +* **Easy backup**: Just copy the SQLite file to a safe place, and you have a backup, which you can restore by copying it + back. No need to work with SQL dumps -## Conclusion and Suggestion +#### Cons -When you are a hobbyist and use Part-DB for your own small inventory managment with only you as user (or maybe sometimes a few other people), then the easy to use SQLite database will be fine. +* **Performance**: SQLite is not as fast as MySQL or PostgreSQL, especially when using complex queries or many users. +* **Emulated RegEx search**: SQLite does not support RegEx search natively. Part-DB can emulate it, however that is pretty slow. +* **Emualted natural sorting**: SQLite does not support natural sorting natively. Part-DB can emulate it, but it is pretty slow. +* **Limitations with Unicode**: SQLite has limitations in comparisons and sorting of Unicode characters, which might lead to + unexpected behavior when using non-ASCII characters in your data. For example `µ` (micro sign) is not seen as equal to + `μ` (greek minuscule mu), therefore searching for `µ` (micro sign) will not find parts containing `μ` (mu) and vice versa. + The other databases behave more intuitive in this case. +* **No advanced features**: SQLite do no support many of the advanced features of MySQL or PostgreSQL, which might be utilized + in future versions of Part-DB -When you are planning to have a very big database, with a lot of entries and many users which regulary (and concurrently) using Part-DB you should maybe use MySQL as this will scale better. \ No newline at end of file + +### MySQL/MariaDB + +**If possible, it is recommended to use MariaDB 10.7+ (instead of MySQL), as it supports natural sorting of columns natively.** + +#### Pros + +* **Performance**: Compared to SQLite, MySQL/MariaDB will probably perform better, especially in large databases with many + users and high activity. +* **Natural Sorting**: MariaDB 10.7+ supports natural sorting of columns. On other databases it has to be emulated, which is pretty + slow. +* **Native RegEx search**: MySQL supports RegEx search natively, which is faster than emulating it in PHP. +* **Advanced features**: MySQL/MariaDB supports many advanced features, which might be utilized in future versions of Part-DB. +* **Full Unicode support**: MySQL/MariaDB has better support for Unicode characters, which makes it more intuitive to use + non-ASCII characters in your data. + +#### Cons + +* **Additional installation and configuration**: You have to install and configure the MySQL server, create a database and + user for Part-DB, which needs some additional work compared to SQLite. +* **Backup**: The MySQL database has to be dumped to a SQL file (using `mysqldump`). The `console partdb:backup` command can automate this. + + +### PostgreSQL + +#### Pros +* **Performance**: PostgreSQL is known for its performance, especially in large databases with many users and high activity. +* **Advanced features**: PostgreSQL supports many advanced features, which might be utilized in future versions of Part-DB. +* **Full Unicode support**: PostgreSQL has better support for Unicode characters, which makes it more intuitive to use + non-ASCII characters in your data. +* **Native RegEx search**: PostgreSQL supports RegEx search natively, which is faster than emulating it in PHP. +* **Native Natural Sorting**: PostgreSQL supports natural sorting of columns natively in all versions and in general the support for it + is better than on MariaDB. +* **Support of transactional DDL**: PostgreSQL supports transactional DDL, which means that if you encounter a problem during a schema change, +the database will automatically rollback the changes. On MySQL/MariaDB you have to manually rollback the changes, by restoring from a database backup. + +#### Cons +* **New backend**: The support of postgresql is new, and it was not tested as much as the other backends. There might be some bugs caused by this. +* **Additional installation and configuration**: You have to install and configure the PostgreSQL server, create a database and + user for Part-DB, which needs some additional work compared to SQLite. +* **Backup**: The PostgreSQL database has to be dumped to a SQL file (using `pg_dump`). The `console partdb:backup` command can automate this. + + +## Recommendation + +When you are a hobbyist and use Part-DB for your own small inventory management with only you as user (or maybe sometimes +a few other people), then the easy-to-use SQLite database will be fine, as long as you can live with the limitations, stated above. +However using MariaDB (or PostgreSQL), has no disadvantages in that situation (besides the initial setup requirements), so you might +want to use it, to be prepared for future use cases. + +When you are planning to have a very big database, with a lot of entries and many users which regularly using Part-DB, then you should +use MariaDB or PostgreSQL, as they will perform better in that situation and allow for more advanced features. +If you should use MariaDB or PostgreSQL depends on your personal preference and what you already have installed on your servers and +what you are familiar with. + +## Using the different databases + +The only difference in using the different databases, is a different value in the `DATABASE_URL` environment variable in the `.env.local` file +or in the `DATABASE_URL` environment variable in your server or container configuration. It has the shape of a URL, where the scheme (the part before `://`) +is the database type, and the rest is connection information. + +**The env var format below is for the `env.local` file. It might work differently for other env configuration. E.g. in a docker-compose file you have to remove the quotes!** + +### SQLite + +```shell +DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db" +``` + +Here you just need to configure the path to the SQLite file, which is created by Part-DB when performing the database migrations. +The `%kernel.project_dir%` is a placeholder for the path to the project directory, which is replaced by the actual path by Symfony, so that you do not +need to specify the path manually. In the example the database will be created as `app.db` in the `var` directory of your Part-DB installation folder. + +### MySQL/MariaDB + +```shell +DATABASE_URL="mysql://user:password@127.0.0.1:3306/database?serverVersion=8.0.37" +``` + +Here you have to replace `user`, `password` and `database` with the credentials of the MySQL/MariaDB user and the database name you want to use. +The host (here 127.0.0.1) and port should also be specified according to your MySQL/MariaDB server configuration. + +In the `serverVersion` parameter you can specify the version of the MySQL/MariaDB server you are using, in the way the server returns it +(e.g. `8.0.37` for MySQL and `10.4.14-MariaDB`). If you do not know it, you can leave the default value. + +If you want to use a unix socket for the connection instead of a TCP connnection, you can specify the socket path in the `unix_socket` parameter. +```shell +DATABASE_URL="mysql://user:password@localhost/database?serverVersion=8.0.37&unix_socket=/var/run/mysqld/mysqld.sock" +``` + +### PostgreSQL + +```shell +DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=12.19&charset=utf8" +``` + +Here you have to replace `db_user`, `db_password` and `db_name` with the credentials of the PostgreSQL user and the database name you want to use. +The host (here 127.0.0.1) and port should also be specified according to your PostgreSQL server configuration. + +In the `serverVersion` parameter you can specify the version of the PostgreSQL server you are using, in the way the server returns it +(e.g. `12.19 (Debian 12.19-1.pgdg120+1)`). If you do not know it, you can leave the default value. + +The `charset` parameter specify the character set of the database. It should be set to `utf8` to ensure that all characters are stored correctly. + +If you want to use a unix socket for the connection instead of a TCP connnection, you can specify the socket path in the `host` parameter. +```shell +DATABASE_URL="postgresql://db_user@localhost/db_name?serverVersion=16.6&charset=utf8&host=/var/run/postgresql" +``` + + +## Natural Sorting + +Natural sorting is the sorting of strings in a way that numbers are sorted by their numerical value, not by their ASCII value. + +For example in the classical binary sorting the string `DIP-4`, `DIP-8`, `DIP-16`, `DIP-28` would be sorted as following: + +* `DIP-16` +* `DIP-28` +* `DIP-4` +* `DIP-8` + +In natural sorting, it would be sorted as: + +* `DIP-4` +* `DIP-8` +* `DIP-16` +* `DIP-28` + +Part-DB can sort names in part tables and tree views naturally. PostgreSQL and MariaDB 10.7+ support natural sorting natively, +and it is automatically used if available. + +For SQLite and MySQL < 10.7 it has to be emulated if wanted, which is pretty slow. Therefore it has to be explicity enabled by setting the +`DATABASE_EMULATE_NATURAL_SORT` environment variable to `1`. If it is 0 the classical binary sorting is used, on these databases. The emulations +might have some quirks and issues, so it is recommended to use a database which supports natural sorting natively, if you want to use it. diff --git a/docs/installation/email.md b/docs/installation/email.md index 08211616..c9feaba6 100644 --- a/docs/installation/email.md +++ b/docs/installation/email.md @@ -7,31 +7,34 @@ nav_order: 12 # Email -Part-DB can communicate with its users via email. +Part-DB can communicate with its users via email. At the moment this is only used to send password reset links, but in future this will be used for other things too. To make emails work you have to properly configure a mail provider in Part-DB. ## Configuration -Part-DB uses [Symfony Mailer](https://symfony.com/doc/current/mailer.html) to send emails, which supports multiple -automatic mail providers (like MailChimp or SendGrid). If you want to use one of these providers, check the Symfony Mailer documentation for more information. -We will only cover the configuration of a SMTP provider here, which is sufficient for most usecases. -You will need an email account, which you can use send emails from via password-bases SMTP authentication, this account +Part-DB uses [Symfony Mailer](https://symfony.com/doc/current/mailer.html) to send emails, which supports multiple +automatic mail providers (like MailChimp or SendGrid). If you want to use one of these providers, check the Symfony +Mailer documentation for more information. + +We will only cover the configuration of an SMTP provider here, which is sufficient for most use-cases. +You will need an email account, which you can use send emails from via password-bases SMTP authentication, this account should be dedicated to Part-DB. To configure the SMTP provider, you have to set the following environment variables: -`MAILER_DSN`: You have to provide the SMTP server address and the credentials for the email account here. The format is the following: -`smtp://:@:`. In most cases the username is the email address of the account, and the port is 587. +`MAILER_DSN`: You have to provide the SMTP server address and the credentials for the email account here. The format is +the following: +`smtp://:@:`. In most cases the username is the email address of the +account, and the port is 587. So the resulting DSN could look like this: `smtp://j.doe@mail.invalid:SUPER_SECRET_PA$$WORD@smtp.mail.invalid:587`. `EMAIL_SENDER_EMAIL`: This is the email address which will be used as sender address for all emails sent by Part-DB. -This should be the same email address as the one used in the `MAILER_DSN` (the email adress of your email account): +This should be the same email address as the one used in the `MAILER_DSN` (the email address of your email account): e.g. `j.doe@mail.invalid`. -`EMAIL_SENDER_NAME`: This is the name which will be used as sender name for all emails sent by Part-DB. +`EMAIL_SENDER_NAME`: This is the name which will be used as sender name for all emails sent by Part-DB. This can be anything you want, e.g. `My Part-DB Mailer`. - Now you can enable the possibility to reset password by setting the `ALLOW_EMAIL_PW_RESET` env to `1` (or `true`). \ No newline at end of file diff --git a/docs/installation/index.md b/docs/installation/index.md index e7b59104..217f702a 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -6,4 +6,6 @@ has_children: true --- # Installation -Below you can find some guides to install Part-DB. \ No newline at end of file +Below you can find some guides to install Part-DB. + +For the hobbyists without much experience, we recommend the docker installation or direct installation on debian. \ No newline at end of file diff --git a/docs/installation/installation_docker.md b/docs/installation/installation_docker.md index ddac7e42..c9b46fdb 100644 --- a/docs/installation/installation_docker.md +++ b/docs/installation/installation_docker.md @@ -7,19 +7,23 @@ nav_order: 2 # Installation of Part-DB via docker -Part-DB can be installed containerized via docker. This is the easiest way to get Part-DB up and running and works on all platforms, -where docker is available (especially recommended for Windows and MacOS). - +Part-DB can be installed containerized via docker. This is the easiest way to get Part-DB up and running and works on +all platforms, +where docker is available (especially recommended for Windows and macOS). {: .warning } -> The methods described here, configure PHP without HTTPS and therefore should only be used locally in a trusted network. +> The methods described here, configure PHP without HTTPS and therefore should only be used locally in a trusted +> network. > If you want to expose Part-DB to the internet, you have to configure a reverse proxy with an SSL certificate! +It is recommended to install Part-DB on a 64-bit system, as the 32-bit version of PHP is affected by the +[Year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) and can not handle dates after 2038 correctly. + ## Docker-compose + Docker-compose configures the needed images and automatically creates the needed containers and volumes. - -1. Install docker and docker-compose like described under https://docs.docker.com/compose/install/ +1. Install docker and docker-compose as described under https://docs.docker.com/compose/install/ 2. Create a folder where the Part-DB data should live 3. Create a file named docker-compose.yaml with the following content: @@ -43,11 +47,18 @@ services: - DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db # In docker env logs will be redirected to stderr - APP_ENV=docker + + # Uncomment this, if you want to use the automatic database migration feature. With this you have you do not have to + # run the doctrine:migrations:migrate commands on installation or upgrade. A database backup is written to the uploads/ + # folder (under .automigration-backup), so you can restore it, if the migration fails. + # This feature is currently experimental, so use it at your own risk! + # - DB_AUTOMIGRATE=true # You can configure Part-DB using environment variables # Below you can find the most essential ones predefined - # However you can add add any other environment configuration you want here + # However you can add any other environment configuration you want here # See .env file for all available options or https://docs.part-db.de/configuration.html + # !!! Do not use quotes around the values, as they will be interpreted as part of the value and this will lead to errors !!! # The language to use serverwide as default (en, de, ru, etc.) - DEFAULT_LANG=en @@ -64,23 +75,35 @@ services: # Use gravatars for user avatars, when user has no own avatar defined - USE_GRAVATAR=0 - # Override value if you want to show to show a given text on homepage. + # Override value if you want to show a given text on homepage. # When this is empty the content of config/banner.md is used as banner #- BANNER=This is a test banner
with a line break + + # If you use a reverse proxy in front of Part-DB, you must configure the trusted proxies IP addresses here (see reverse proxy documentation for more information): + # - TRUSTED_PROXIES=127.0.0.0/8,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 ``` -4. Customize the settings by changing the environment variables (or add new ones). See [Configuration]({% link configuration.md %}) for more information. + +4. Customize the settings by changing the environment variables (or adding new ones). See [Configuration]({% link + configuration.md %}) for more information. 5. Inside the folder, run + ```bash docker-compose up -d ``` -6. Create the inital database with + +6. Create the initial database with + ```bash docker exec --user=www-data partdb php bin/console doctrine:migrations:migrate ``` -and watch for the password output -6. Part-DB is available under `http://localhost:8080` and you can log in with username `admin` and the password shown before -The docker image uses a SQLite database and all data (database, uploads and other media) is put into folders relative to the docker-compose.yml. +and watch for the password output + +6. Part-DB is available under `http://localhost:8080` and you can log in with the username `admin` and the password shown + before + +The docker image uses a SQLite database and all data (database, uploads, and other media) is put into folders relative to +the docker-compose.yml. ### MySQL @@ -113,6 +136,12 @@ services: # In docker env logs will be redirected to stderr - APP_ENV=docker + # Uncomment this, if you want to use the automatic database migration feature. With this you have you do not have to + # run the doctrine:migrations:migrate commands on installation or upgrade. A database backup is written to the uploads/ + # folder (under .automigration-backup), so you can restore it, if the migration fails. + # This feature is currently experimental, so use it at your own risk! + # - DB_AUTOMIGRATE=true + # You can configure Part-DB using environment variables # Below you can find the most essential ones predefined # However you can add add any other environment configuration you want here @@ -140,7 +169,8 @@ services: database: container_name: partdb_database image: mysql:8.0 - command: --default-authentication-plugin=mysql_native_password + restart: unless-stopped + command: --default-authentication-plugin=mysql_native_password --log-bin-trust-function-creators=1 environment: # Change this Password MYSQL_ROOT_PASSWORD: SECRET_ROOT_PASSWORD @@ -156,8 +186,10 @@ services: ``` ### Update Part-DB + You can update Part-DB by pulling the latest image and restarting the container. Then you have to run the database migrations again + ```bash docker-compose pull docker-compose up -d @@ -165,19 +197,30 @@ docker exec --user=www-data partdb php bin/console doctrine:migrations:migrate ``` ## Direct use of docker image -You can use the `jbtronics/part-db1:master` image directly. You have to expose the port 80 to a host port and configure volumes for `/var/www/html/uploads` and `/var/www/html/public/media`. -If you want to use SQLite database (which is default), you have to configure Part-DB to put the database file in a mapped volume via the `DATABASE_URL` environment variable. -For example if you set `DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db` then you will have to map the `/var/www/html/var/db/` folder to the docker container (see docker-compose.yaml for example). +You can use the `jbtronics/part-db1:master` image directly. You have to expose port 80 to a host port and configure +volumes for `/var/www/html/uploads` and `/var/www/html/public/media`. -You also have to create the database like described above in step 4. +If you want to use SQLite database (which is default), you have to configure Part-DB to put the database file in a +mapped volume via the `DATABASE_URL` environment variable. +For example, if you set `DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db` then you will have to map +the `/var/www/html/var/db/` folder to the docker container (see docker-compose.yaml for example). + +You also have to create the database as described above in step 4. ## Running console commands -You can run the console commands described in README by executing `docker exec --user=www-data -it partdb bin/console [command]` + +You can run the console commands described in README by +executing `docker exec --user=www-data -it partdb bin/console [command]` + +{: .warning } +> If you run a root console inside the container, and wanna execute commands on the webserver behalf, be sure to use `sudo -E` command (with the `-E` flag) to preserve env variables from the current shell. +> Otherwise Part-DB console might use the wrong configuration to execute commands. ## Troubleshooting -*Login not possible. Login page is just reloading and no error message is shown or something like "CSFR token invalid"*: +*Login is not possible. Login page is just reloading and no error message is shown or something like "CSFR token invalid"*: -Clear all cookies in your browser or use a inkognito tab for Part-DB. -This related to the fact that Part-DB can not set cookies via HTTP, after some webpage has set cookies before under localhost via https. This is a security mechanism of the browser and can not be bypassed by Part-DB. +Clear all cookies in your browser or use an incognito tab for Part-DB. +This is related to the fact that Part-DB can not set cookies via HTTP after some webpages have set cookies before under +localhost via HTTPS. This is a security mechanism of the browser and can not be bypassed by Part-DB. diff --git a/docs/installation/installation_guide-debian.md b/docs/installation/installation_guide-debian.md index 11bddc03..885eea90 100644 --- a/docs/installation/installation_guide-debian.md +++ b/docs/installation/installation_guide-debian.md @@ -6,25 +6,41 @@ nav_order: 4 --- # Part-DB installation guide for Debian 11 (Bullseye) -This guide shows you how to install Part-DB directly on Debian 11 using apache2 and SQLite. This guide should work with recent Ubuntu and other Debian based distributions with little to no changes. -Depending on what you want to do, using the prebuilt docker images may be a better choice, as you dont need to install this much dependencies. See **TODO** for more information of the docker installation. + +This guide shows you how to install Part-DB directly on Debian 11 using apache2 and SQLite. This guide should work with +recent Ubuntu and other Debian-based distributions with little to no changes. +Depending on what you want to do, using the prebuilt docker images may be a better choice, as you don't need to install +this many dependencies. See [here]({% link installation/installation_docker.md %}) for more information on the docker +installation. {: .warning } -> The methods described here, configure PHP without HTTPS and therefore should only be used locally in a trusted network. +> The methods described here, configure PHP without HTTPS and therefore should only be used locally in a trusted +> network. > If you want to expose Part-DB to the internet, you HAVE to configure an SSL connection! +It is recommended to install Part-DB on a 64-bit system, as the 32-bit version of PHP is affected by the +[Year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) and can not handle dates after 2038 correctly. + ## Installation with SQLite database ### Install prerequisites + For the installation of Part-DB, we need some prerequisites. They can be installed by running the following command: + ```bash sudo apt install git curl zip ca-certificates software-properties-common apt-transport-https lsb-release nano wget ``` ### Install PHP and apache2 -Part-DB is written in [PHP](https://php.net) and therefore needs an PHP interpreter to run. Part-DB needs PHP 8.1 or higher, however it is recommended to use the most recent version of PHP for performance reasons and future compatibility. -As Debian 11 does not ship PHP 8.1 in it's default repositories, we have to add a repository for it. You can skip this step if your distribution is shipping a recent version of PHP or you want to use the built-in PHP version. If you are using Debian 12, you can skip this step, as PHP 8.1 is already included in the default repositories. +Part-DB is written in [PHP](https://php.net) and therefore needs a PHP interpreter to run. Part-DB needs PHP 8.1 or +higher. However, it is recommended to use the most recent version of PHP for performance reasons and future +compatibility. + +As Debian 11 does not ship PHP 8.1 in its default repositories, we have to add a repository for it. You can skip this +step if your distribution is shipping a recent version of PHP or you want to use the built-in PHP version. If you are +using Debian 12, you can skip this step, as PHP 8.1 is already included in the default repositories. + ```bash # Add sury repository for PHP 8.1 sudo curl -sSL https://packages.sury.org/php/README.txt | sudo bash -x @@ -32,14 +48,21 @@ sudo curl -sSL https://packages.sury.org/php/README.txt | sudo bash -x # Update package list sudo apt update && sudo apt upgrade ``` -Now you can install PHP 8.1 and required packages (change the 8.1 in the package version according to the version you want to use): + +Now you can install PHP 8.1 and the required packages (change the 8.1 in the package version according to the version you +want to use): + ```bash sudo apt install php8.1 libapache2-mod-php8.1 php8.1-opcache php8.1-curl php8.1-gd php8.1-mbstring php8.1-xml php8.1-bcmath php8.1-intl php8.1-zip php8.1-xsl php8.1-sqlite3 php8.1-mysql ``` + The apache2 webserver should be already installed with this command and configured basically. ### Install composer -Part-DB uses [composer](https://getcomposer.org/) to install required PHP libraries. As the versions shipped in the repositories is pretty old we install it manually: + +Part-DB uses [composer](https://getcomposer.org/) to install required PHP libraries. As the version shipped in the +repositories is pretty old, we will install it manually: + ```bash # Download composer installer script wget -O /tmp/composer-setup.php https://getcomposer.org/installer @@ -50,7 +73,10 @@ chmod +x /usr/local/bin/composer ``` ### Install yarn and nodejs -To build the frontend (the user interface) Part-DB uses [yarn](https://yarnpkg.com/). As it dependens on nodejs and the shipped versions are pretty old, we install new versions from offical nodejs repository: + +To build the front end (the user interface) Part-DB uses [yarn](https://yarnpkg.com/). As it depends on Node.js and the +shipped versions are pretty old, we install new versions from the official Node.js repository: + ```bash # Add recent node repository (nodejs 18 is supported until 2025) curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash - @@ -59,6 +85,7 @@ sudo apt install nodejs ``` We can install yarn with the following commands: + ```bash # Add yarn repository curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/yarnkey.gpg >/dev/null @@ -68,46 +95,64 @@ sudo apt update && sudo apt install yarn ``` ### Create a folder for Part-DB and download it -We now have all prerequisites installed and can start to install Part-DB. We will create a folder for Part-DB in a webfolder of apache2 and download it to this folder. The downloading is done via git, which allows you to update easily later. + +We now have all prerequisites installed and can start to install Part-DB. We will create a folder for Part-DB in the +webroot of apache2 and download it to this folder. The downloading is done via git, which allows you to update easily +later. + ```bash # Download Part-DB into the new folder /var/www/partdb git clone https://github.com/Part-DB/Part-DB-symfony.git /var/www/partdb ``` -By default you are now on the latest development version. In most cases you want to use the latest stable version. You can switch to the latest stable version (tagged) by running the following command: +By default, you are now on the latest development version. In most cases, you want to use the latest stable version. You +can switch to the latest stable version (tagged) by running the following command: + ```bash # This finds the latest release/tag and checks it out git checkout $(git describe --tags $(git rev-list --tags --max-count=1)) ``` -Alternatively you can checkout a specific version by running (see [GitHub Relases page](https://github.com/Part-DB/Part-DB-server/releases) for a list of available versions): + +Alternatively, you can check out a specific version by running ( +see [GitHub Releases page](https://github.com/Part-DB/Part-DB-server/releases) for a list of available versions): + ```bash # This checks out the version 1.5.2 git checkout v1.5.2 ``` Change ownership of the files to the apache user: + ```bash chown -R www-data:www-data /var/www/partdb ``` For the next steps we should be in the Part-DB folder, so move into it: + ```bash cd /var/www/partdb ``` ### Create configuration for Part-DB -The basic configuration of Part-DB is done by a `.env.local` file in the main directory. Create on by from the default configuration: + +The basic configuration of Part-DB is done by a `.env.local` file in the main directory. Create on by from the default +configuration: + ```bash cp .env .env.local ``` -In your `.env.local` you can configure Part-DB according to your wishes. A full list of configuration options can be found [here]({% link configuration.md %}. +In your `.env.local` you can configure Part-DB according to your wishes. A full list of configuration options can be +found [here](../configuration.md). Other configuration options like the default language or default currency can be found in `config/parameters.yaml`. -Please check that the `partdb.default_currency` value in `config/parameters.yaml` matches your mainly used currency, as this can not be changed after creating price informations. +Please check that the `partdb.default_currency` value in `config/parameters.yaml` matches your mainly used currency, as +this can not be changed after creating price information. ### Install dependencies for Part-DB and build frontend + Part-DB depends on several other libraries and components. Install them by running the following commands: + ```bash # Install composer dependencies (please note the sudo command, to run it under the web server user) sudo -u www-data composer install --no-dev -o @@ -121,32 +166,47 @@ sudo yarn build ### Clear cache To ensure everything is working, clear the cache: + ```bash sudo -u www-data php bin/console cache:clear ``` ### Check if everything is installed + To check if everything is installed, run the following command: + ```bash sudo -u www-data php bin/console partdb:check-requirements ``` -The most things should be green, and no red ones. Yellow messages means optional dependencies which are not important but can improve performance and functionality. + +Most things should be green, and no red ones. Yellow messages mean optional dependencies which are not important +but can improve performance and functionality. ### Create a database for Part-DB -Part-DB by default uses a file based sqlite database to store the data. Use the following command to create the database. The database will normally created at `/var/www/partdb/var/app.db`. + +Part-DB by default uses a file-based SQLite database to store the data. Use the following command to create the +database. The database will normally be created at `/var/www/partdb/var/app.db`. + ```bash sudo -u www-data php bin/console doctrine:migrations:migrate ``` + The command will warn you about schema changes and potential data loss. Continue with typing `yes`. -The command will output several lines of informations. Somewhere should be a a yellow background message like `The initial password for the "admin" user is: f502481134`. Write down this password as you will need it later for inital login. +The command will output several lines of information. Somewhere should be a yellow background message +like `The initial password for the "admin" user is: f502481134`. Write down this password as you will need it later for the initial login. ### Configure apache2 to show Part-DB -Part-DB is now configured, but we have to say apache2 to serve Part-DB as web application. This is done by creating a new apache site: + +Part-DB is now configured, but we have to say apache2 to serve Part-DB as web application. This is done by creating a +new apache site: + ```bash sudo nano /etc/apache2/sites-available/partdb.conf ``` + and add the following content (change ServerName and ServerAlias to your needs): + ``` ServerName partdb.lan @@ -163,33 +223,44 @@ and add the following content (change ServerName and ServerAlias to your needs): CustomLog /var/log/apache2/partdb_access.log combined ``` + Activate the new site by: + ```bash sudo ln -s /etc/apache2/sites-available/partdb.conf /etc/apache2/sites-enabled/partdb.conf ``` -Configure apache to show pretty URL pathes for Part-DB (`/label/dialog` instead of `/index.php/label/dialog`): +Configure apache to show pretty URL paths for Part-DB (`/label/dialog` instead of `/index.php/label/dialog`): + ```bash sudo a2enmod rewrite ``` -If you want to access Part-DB via the IP-Address of the server, instead of the domain name, you have to remove the apache2 default configuration with: +If you want to access Part-DB via the IP-Address of the server, instead of the domain name, you have to remove the +apache2 default configuration with: + ```bash sudo rm /etc/apache2/sites-enabled/000-default.conf ``` Restart the apache2 webserver with: + ```bash sudo service apache2 restart ``` -and Part-DB should now be available under `http://YourServerIP` (or `http://partdb.lan` if you configured DNS in your network to point on the server). +and Part-DB should now be available under `http://YourServerIP` (or `http://partdb.lan` if you configured DNS in your +network to point to the server). ### Login to Part-DB -Navigate to the Part-DB web interface and login via the user icon in the top right corner. You can login using the username `admin` and the password you have written down earlier. + +Navigate to the Part-DB web interface and login via the user icon in the top right corner. You can log in using the +username `admin` and the password you have written down earlier. ## Update Part-DB + If you want to update your existing Part-DB installation, you just have to run the following commands: + ```bash # Move into Part-DB folder cd /var/www/partdb @@ -218,7 +289,8 @@ sudo -u www-data php bin/console cache:clear ``` ## MySQL/MariaDB database -To use a MySQL database, follow the steps from above (except the creation of database, we will do this later). + +To use a MySQL database, follow the steps from above (except the creation of the database, we will do this later). Debian 11 does not ship MySQL in its repositories anymore, so we use the compatible MariaDB instead: 1. Install maria-db with: @@ -228,9 +300,11 @@ sudo apt update && sudo apt install mariadb-server ``` 2. Configure maria-db with: + ```bash sudo mysql_secure_installation ``` + When asked for the root password, just press enter, as we have not set a root password yet. In the next steps you are asked if you want to switch to unix_socket authentication, answer with `n` and press enter. Then you are asked if you want to remove anonymous users, answer with `y` and press enter. @@ -239,33 +313,42 @@ Then you are asked if you want to remove the test database and access to it, ans Then you are asked if you want to reload the privilege tables now, answer with `y` and press enter. 3. Create a new database and user for Part-DB: Run the following commands: + ```bash sudo mariadb ``` + A SQL shell will open, in which you can run the following commands to create a new database and user for Part-DB. Replace 'YOUR_SECRET_PASSWORD' with a secure password. + ```sql CREATE DATABASE partdb; GRANT ALL PRIVILEGES ON partdb.* TO 'partdb'@'localhost' IDENTIFIED BY 'YOUR_SECRET_PASSWORD'; ``` -Finally save the changes with: + +Finally, save the changes with: + ```sql FLUSH PRIVILEGES; ``` + and exit the SQL shell with: + ```sql exit ``` 4. Configure Part-DB to use the new database. Open your `.env.local` file and search the line `DATABASE_URL`. -Change it to the following (you have to replace `YOUR_SECRET_PASSWORD` with the password you have choosen in step 3): + Change it to the following (you have to replace `YOUR_SECRET_PASSWORD` with the password you have chosen in step 3): + ``` -DATABASE_URL=DATABASE_URL=mysql://partdb:YOUR_SECRET_PASSWORD@127.0.0.1:3306/partdb +DATABASE_URL=mysql://partdb:YOUR_SECRET_PASSWORD@127.0.0.1:3306/partdb ``` 5. Create the database schema with: + ```bash sudo -u www-data php bin/console doctrine:migrations:migrate ``` -6. The migration step should have shown you a password for the admin user, which you can use now to login to Part-DB. +6. The migration step should have shown you a password for the admin user, which you can use now to log in to Part-DB. diff --git a/docs/installation/kubernetes.md b/docs/installation/kubernetes.md new file mode 100644 index 00000000..86504af2 --- /dev/null +++ b/docs/installation/kubernetes.md @@ -0,0 +1,42 @@ +--- +title: Kubernetes / Helm +layout: default +parent: Installation +nav_order: 5 +--- + +# Kubernetes / Helm Charts + +If you are using Kubernetes, you can use the [helm charts](https://helm.sh/) provided in this [repository](https://github.com/Part-DB/helm-charts). + +## Usage + +[Helm](https://helm.sh) must be installed to use the charts. Please refer to +Helm's [documentation](https://helm.sh/docs) to get started. + +Once Helm has been set up correctly, add the repo as follows: + +`helm repo add part-db https://part-db.github.io/helm-charts` + +If you had already added this repo earlier, run `helm repo update` to retrieve +the latest versions of the packages. You can then run `helm search repo +part-db` to see the charts. + +To install the part-db chart: + + helm install my-part-db part-db/part-db + +To uninstall the chart: + + helm delete my-part-db + +This repository is also available at [ArtifactHUB](https://artifacthub.io/packages/search?repo=part-db). + +## Configuration + +See the README in the [chart directory](https://github.com/Part-DB/helm-charts/tree/main/charts/part-db) for more +information on the available configuration options. + +## Bugreports + +If you find issues related to the helm charts, please open an issue in the [helm-charts repository](https://github.com/Part-DB/helm-charts). \ No newline at end of file diff --git a/docs/installation/nginx.md b/docs/installation/nginx.md index 542c11eb..84305975 100644 --- a/docs/installation/nginx.md +++ b/docs/installation/nginx.md @@ -6,14 +6,18 @@ nav_order: 10 --- # Nginx + You can also use [nginx](https://www.nginx.com/) as webserver for Part-DB. Setup Part-DB with apache is a bit easier, so this is the method shown in the guides. This guide assumes that you already have a working nginx installation with PHP configured. ## Setup -1. Install composer and yarn like described in the [apache guide]({% link installation/installation_guide-debian.md %}#install-composer). + +1. Install composer and yarn as described in the [apache guide]({% link installation/installation_guide-debian.md + %}#install-composer). 2. Create a folder for Part-DB and install and configure it as described 3. Instead of creating the config for apache, add the following snippet to your nginx config: + ```nginx server { # Redirect all HTTP requests to HTTPS @@ -48,6 +52,11 @@ server { location ~ \.php$ { return 404; } + + # Set Content-Security-Policy for svg files, to block embedded javascript in there + location ~* \.svg$ { + add_header Content-Security-Policy "default-src 'self'; script-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none';"; + } error_log /var/log/nginx/parts.error.log; access_log /var/log/nginx/parts.access.log; @@ -64,4 +73,6 @@ server { ssl_prefer_server_ciphers on; } ``` -4. Restart nginx with `sudo systemctl restart nginx` and you should be able to access Part-DB under your configured domain. \ No newline at end of file + +4. Restart nginx with `sudo systemctl restart nginx` and you should be able to access Part-DB under your configured + domain. \ No newline at end of file diff --git a/docs/installation/proxmox.md b/docs/installation/proxmox.md new file mode 100644 index 00000000..865d2bf4 --- /dev/null +++ b/docs/installation/proxmox.md @@ -0,0 +1,31 @@ +--- +title: Proxmox VE LXC +layout: default +parent: Installation +nav_order: 6 +--- + +# Proxmox VE LXC + +{: .warning } +> The proxmox VE LXC script for Part-DB is developed and maintained by [Proxmox VE Helper-Scripts](https://community-scripts.github.io/ProxmoxVE/) +> and not by the Part-DB developers. Keep in mind that the script is not officially supported by the Part-DB developers. + +If you are using Proxmox VE you can use the scripts provided by [Proxmox VE Helper-Scripts community](https://community-scripts.github.io/ProxmoxVE/scripts?id=part-db) +to easily install Part-DB in a LXC container. + +## Usage + +To create a new LXC container with Part-DB, you can use the following command in the Proxmox VE shell: + +```bash +bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/part-db.sh)" +``` + +The same command can be used to update an existing Part-DB container. + +See the [helper script website](https://community-scripts.github.io/ProxmoxVE/scripts?id=part-db) for more information. + +## Bugreports + +If you find issues related to the proxmox VE LXC script, please open an issue in the [Proxmox VE Helper-Scripts repository](https://github.com/community-scripts/ProxmoxVE). diff --git a/docs/installation/reverse-proxy.md b/docs/installation/reverse-proxy.md index d42e5a2b..605b93fa 100644 --- a/docs/installation/reverse-proxy.md +++ b/docs/installation/reverse-proxy.md @@ -9,13 +9,32 @@ nav_order: 11 If you want to put Part-DB behind a reverse proxy, you have to configure Part-DB correctly to make it work properly. -You have to set the `TRUSTED_PROXIES` environment variable to the IP address of your reverse proxy -(either in your `docker-compose.yaml` in the case of docker, or `.env.local` in case of direct installation). +You have to set the `TRUSTED_PROXIES` environment variable to the IP address of your reverse proxy +(either in your `docker-compose.yaml` in the case of docker, or `.env.local` in case of direct installation). If you have multiple reverse proxies, you can set multiple IP addresses separated by a comma (or specify a range). -For example, if your reverse proxy has the IP address `192.168.2.10`, your value should be: +For example, if your reverse proxy has the IP address `192.168.2.10`, your value should be: + ``` TRUSTED_PROXIES=192.168.2.10 ``` -Set the `DEFAULT_URI` environment variable to the URL of your Part-DB installation, available from the outside (so via the reverse proxy). \ No newline at end of file +Set the `DEFAULT_URI` environment variable to the URL of your Part-DB installation, available from the outside (so via +the reverse proxy). + +## Part-DB in a subpath via reverse proxy + +If you put Part-DB into a subpath via the reverse proxy, you have to configure your webserver to include `X-Forwarded-Prefix` in the request headers. +For example if you put Part-DB behind a reverse proxy with the URL `https://example.com/partdb`, you have to set the `X-Forwarded-Prefix` header to `/partdb`. + +In apache, you can do this by adding the following line to your virtual host configuration: + +``` +RequestHeader set X-Forwarded-Prefix "/partdb" +``` + +and in nginx, you can do this by adding the following line to your server configuration: + +``` +proxy_set_header X-Forwarded-Prefix "/partdb"; +``` \ No newline at end of file diff --git a/docs/installation/saml_sso.md b/docs/installation/saml_sso.md index 22a3076e..d2e65e7f 100644 --- a/docs/installation/saml_sso.md +++ b/docs/installation/saml_sso.md @@ -7,43 +7,56 @@ nav_order: 12 # Single Sign-On via SAML -Part-DB supports Single Sign-On via SAML. This means that you can use your existing SAML identity provider to log in to Part-DB. -Using an intermediate SAML server like [Keycloak](https://www.keycloak.org/), also allows you to connect Part-DB to a LDAP or Active Directory server. +Part-DB supports Single Sign-On via SAML. This means that you can use your existing SAML identity provider to log in to +Part-DB. +Using an intermediate SAML server like [Keycloak](https://www.keycloak.org/), also allows you to connect Part-DB to an +LDAP or Active Directory server. {: .important } -> This feature is for advanced users only. Single Sign-On is useful for large organizations with many users, which are already using SAML for other services. +> This feature is for advanced users only. Single Sign-On is useful for large organizations with many users, which are +> already using SAML for other services. > If you have only one or a few users, you should use the built-in authentication system of Part-DB. -> This guide assumes that you already have an SAML identity provider set up and working, and have a basic understanding of how SAML works. +> This guide assumes that you already have an SAML identity provider set up and working, and have a basic understanding +> of how SAML works. {: .warning } > This feature is currently in beta. Please report any bugs you find. > So far it has only tested with Keycloak, but it should work with any SAML 2.0 compatible identity provider. -This guide will show you how to configure Part-DB with [Keycloak](https://www.keycloak.org/) as the SAML identity provider, -but it should work with any SAML 2.0 compatible identity provider. +This guide will show you how to configure Part-DB with [Keycloak](https://www.keycloak.org/) as the SAML identity +provider, but it should work with any SAML 2.0 compatible identity provider. -This guide assumes that you have a working Keycloak installation with some users. If you don't, you can follow the [Keycloak Getting Started Guide](https://www.keycloak.org/docs/latest/getting_started/index.html). +This guide assumes that you have a working Keycloak installation with some users. If you don't, you can follow +the [Keycloak Getting Started Guide](https://www.keycloak.org/docs/latest/getting_started/index.html). {: .important } -> Part-DB associates local users with SAML users by their username. That means if the username of a SAML user changes, a new local user will be created (and the old account can not be accessed). -> You should make sure that the username of a SAML user does not change. If you use Keycloak make sure that the possibility to change the username is disabled (which is by default). -> If you really have to rename a SAML user, a Part-DB admin can rename the local user in the Part-DB in the admin panel, to match the new username of the SAML user. +> Part-DB associates local users with SAML users by their username. That means if the username of a SAML user changes, a +> new local user will be created (and the old account can not be accessed). +> You should make sure that the username of a SAML user does not change. If you use Keycloak make sure that the +> possibility to change the username is disabled (which is by default). +> If you really have to rename a SAML user, a Part-DB admin can rename the local user in the Part-DB in the admin panel, +> to match the new username of the SAML user. ## Configure basic SAML connection ### Create a new SAML client -1. First, you need to configure a new SAML client in Keycloak. Login in to your Keycloak admin console and go to the `Clients` page. -2. Click on `Create client` and select `SAML` as type from the dropdown menu. For the client ID, you can use anything you want, but it should be unique. -*It is recommended to set this value to the domain name of your Part-DB installation, with an attached `/sp` (e.g. `https://partdb.yourdomain.invalid/sp`)*. -The name field should be set to something human-readable, like `Part-DB`. -3. Click on `Save` to create the new client. + +1. First, you need to configure a new SAML client in Keycloak. Login in to your Keycloak admin console and go to + the `Clients` page. +2. Click on `Create client` and select `SAML` as type from the dropdown menu. For the client ID, you can use anything + you want, but it should be unique. + *It is recommended to set this value to the domain name of your Part-DB installation, with an attached `/sp` ( + e.g. `https://partdb.yourdomain.invalid/sp`)*. + The name field should be set to something human-readable, like `Part-DB`. +3. Click on `Save` to create a new client. ### Configure the SAML client 1. Now you need to configure the SAML client. Go to the `Settings` tab and set the following values: * Set `Home URL` to the homepage of your Part-DB installation (e.g. `https://partdb.yourdomain.invalid/`). - * Set `Valid redirect URIs` to your homepage with a wildcard at the end (e.g. `https://partdb.yourdomain.invalid/*`). - * Set `Valid post logout redirect URIs` to `+` to allow all urls from the `Valid redirect URIs`. + * Set `Valid redirect URIs` to your homepage with a wildcard at the end ( + e.g. `https://partdb.yourdomain.invalid/*`). + * Set `Valid post logout redirect URIs` to `+` to allow all URLs from the `Valid redirect URIs`. * Set `Name ID format` to `username` * Ensure `Force POST binding` is enabled. * Ensure `Sign documents` is enabled. @@ -52,30 +65,47 @@ The name field should be set to something human-readable, like `Part-DB`. Click on `Save` to save the changes. 2. Go to the `Advanced` tab and set the following values: - * Assertion Consumer Service POST Binding URL to your homepage with `/saml/acs` at the end (e.g. `https://partdb.yourdomain.invalid/saml/acs`). - * Logout Service POST Binding URL to your homepage with `/logout` at the end (e.g. `https://partdb.yourdomain.invalid/logout`). + * Assertion Consumer Service POST Binding URL to your homepage with `/saml/acs` at the end ( + e.g. `https://partdb.yourdomain.invalid/saml/acs`). + * Logout Service POST Binding URL to your homepage with `/logout` at the end ( + e.g. `https://partdb.yourdomain.invalid/logout`). 3. Go to Keys tab and ensure `Client Signature Required` is enabled. -4. In the Keys tab click on `Generate new keys`. This will generate a new key pair for the SAML client. The private key will be downloaded to your computer. +4. In the Keys tab click on `Generate new keys`. This will generate a new key pair for the SAML client. The private key + will be downloaded to your computer. ### Configure Part-DB to use SAML + 1. Open the `.env.local` file of Part-DB (or the docker-compose.yaml) for edit -2. Set the `SAMLP_SP_PRIVATE_KEY` environment variable to the content of the private key file you downloaded in the previous step. It should start with `MIEE` and end with `=`. -3. Set the `SAML_SP_X509_CERT` environment variable to the content of the Certificate field shown in the `Keys` tab of the SAML client in Keycloak. It should start with `MIIC` and end with `=`. -4. Set the `SAML_SP_ENTITY_ID` environment variable to the entityID of the SAML client in Keycloak (e.g. `https://partdb.yourdomain.invalid/sp`). -5. In Keycloak navigate to `Realm Settings` -> `SAML 2.0 Identity Provider` (by default something like `https://idp.yourdomain.invalid/realms/master/protocol/saml/descriptor) to show the SAML metadata. -6. Copy the `entityID` value from the metadata to the `SAML_IDP_ENTITY_ID` configuration variable of Part-DB (by default something like `https://idp.yourdomain.invalid/realms/master`). -7. Copy the `Single Sign-On Service` value from the metadata to the `SAML_IDP_SINGLE_SIGN_ON_SERVICE` configuration variable of Part-DB (by default something like `https://idp.yourdomain.invalid/realms/master/protocol/saml`). -8. Copy the `Single Logout Service` value from the metadata to the `SAML_IDP_SINGLE_LOGOUT_SERVICE` configuration variable of Part-DB (by default something like `https://idp.yourdomain.invalid/realms/master/protocol/saml/logout`). -9. Copy the `X.509 Certificate` value from the metadata to the `SAML_IDP_X509_CERT` configuration variable of Part-DB (it should start with `MIIC` and should be pretty long). -10. Set the `DEFAULT_URI` to the homepage (on the publicly available domain) of your Part-DB installation (e.g. `https://partdb.yourdomain.invalid/`). It must end with a slash. +2. Set the `SAMLP_SP_PRIVATE_KEY` environment variable to the content of the private key file you downloaded in the + previous step. It should start with `MIEE` and end with `=`. +3. Set the `SAML_SP_X509_CERT` environment variable to the content of the Certificate field shown in the `Keys` tab of + the SAML client in Keycloak. It should start with `MIIC` and end with `=`. +4. Set the `SAML_SP_ENTITY_ID` environment variable to the entityID of the SAML client in Keycloak ( + e.g. `https://partdb.yourdomain.invalid/sp`). +5. In Keycloak navigate to `Realm Settings` -> `SAML 2.0 Identity Provider` (by default something + like `https://idp.yourdomain.invalid/realms/master/protocol/saml/descriptor) to show the SAML metadata. +6. Copy the `entityID` value from the metadata to the `SAML_IDP_ENTITY_ID` configuration variable of Part-DB (by default + something like `https://idp.yourdomain.invalid/realms/master`). +7. Copy the `Single Sign-On Service` value from the metadata to the `SAML_IDP_SINGLE_SIGN_ON_SERVICE` configuration + variable of Part-DB (by default something like `https://idp.yourdomain.invalid/realms/master/protocol/saml`). +8. Copy the `Single Logout Service` value from the metadata to the `SAML_IDP_SINGLE_LOGOUT_SERVICE` configuration + variable of Part-DB (by default something like `https://idp.yourdomain.invalid/realms/master/protocol/saml/logout`). +9. Copy the `X.509 Certificate` value from the metadata to the `SAML_IDP_X509_CERT` configuration variable of Part-DB ( + it should start with `MIIC` and should be pretty long). +10. Set the `DEFAULT_URI` to the homepage (on the publicly available domain) of your Part-DB installation ( + e.g. `https://partdb.yourdomain.invalid/`). It must end with a slash. 11. Set the `SAML_ENABLED` configuration in Part-DB to 1 to enable SAML authentication. -When you access the Part-DB login form now, you should see a new button to log in via SSO. Click on it to be redirected to the SAML identity provider and log in. +When you access the Part-DB login form now, you should see a new button to log in via SSO. Click on it to be redirected +to the SAML identity provider and log in. -In the following sections, you will learn how to configure that Part-DB uses the data provided by the SAML identity provider to fill out user informations. +In the following sections, you will learn how to configure that Part-DB uses the data provided by the SAML identity +provider to fill out user information. ### Set user information based on SAML attributes -Part-DB can set basic user information like the username, the real name and the email address based on the SAML attributes provided by the SAML identity provider. + +Part-DB can set basic user information like the username, the real name and the email address based on the SAML +attributes provided by the SAML identity provider. To do this, you need to configure your SAML identity provider to provide the following attributes: * `email` or `urn:oid:1.2.840.113549.1.9.1` for the email address @@ -83,68 +113,125 @@ To do this, you need to configure your SAML identity provider to provide the fol * `lastName` or `urn:oid:2.5.4.4` for the last name * `department` for the department field of the user -You can omit any of these attributes, but then the corresponding field will be empty (but can be overriden by an administrator). -These values are written to Part-DB database, whenever the user logs in via SAML (the user is created on the first login, and updated on every login). +You can omit any of these attributes, but then the corresponding field will be empty (but can be overwritten by an +administrator). +These values are written to Part-DB database, whenever the user logs in via SAML (the user is created on the first +login, and updated on every login). -To configure Keycloak to provide these attributes, you need to go to the `Client scopes` page and select the `sp-dedicatd` client scope (or create a new one). +To configure Keycloak to provide these attributes, you need to go to the `Client scopes` page and select +the `sp-dedicatd` client scope (or create a new one). In the scope configuration page, click on `Add mappers` and `From predefined mappers`. Select the following mappers: + * `X500 email` * `X500 givenName` * `X500 surname` -and click `Add`. Now Part-DB will be provided with the email, first name and last name of the user based on the Keycloak user database. +and click `Add`. Now Part-DB will be provided with the email, first name and last name of the user based on the Keycloak +user database. ### Configure permissions for SAML users -On the first login of a SAML user, Part-DB will create a new user in the database. This user will have the same username as the SAML user, but no password set. The user will be marked as a SAML user, so he can only login via SAML in the future. However in other aspects the user is a normal user, so Part-DB admins can set permissions for SAML users like for any other user and override permissions assigned via groups. -However for large organizations you maybe want to automatically assign permissions to SAML users based on the roles or groups configured in the identity provider. For this purpose Part-DB allows you to map SAML roles or groups to Part-DB groups. See the next section for details. +On the first login of a SAML user, Part-DB will create a new user in the database. This user will have the same username +as the SAML user, but no password set. The user will be marked as a SAML user, so he can only log in via SAML in the +future. However, in other aspects the user is a normal user, so Part-DB admins can set permissions for SAML users like +for any other user and override permissions assigned via groups. + +For large organizations, you maybe want to automatically assign permissions to SAML users based on the roles or +groups configured in the identity provider. For this purpose Part-DB allows you to map SAML roles or groups to Part-DB +groups. See the next section for details. ### Map SAML roles to Part-DB groups -Part-DB allows you to configure a mapping between SAML roles or groups and Part-DB groups. This allows you to automatically assign permissions to SAML users based on the roles or groups configured in the identity provider. For example if a user at your SAML provider has the role `admin`, you can configure Part-DB to assign the `admin` group to this user. This will give the user all permissions of the `admin` group. -For this you need first have to create the groups in Part-DB, to which you want to assign the users and configure their permissions. You will need the IDs of the groups, which you can find in the `System->Group` page of Part-DB in the Info tab. +Part-DB allows you to configure a mapping between SAML roles or groups and Part-DB groups. This allows you to +automatically assign permissions to SAML users based on the roles or groups configured in the identity provider. For +example, if a user at your SAML provider has the role `admin`, you can configure Part-DB to assign the `admin` group to +this user. This will give the user all permissions of the `admin` group. -The map is provided as [JSON](https://en.wikipedia.org/wiki/JSON) encoded map between the SAML role and the group ID, which has the form `{"saml_role": group_id, "*": group_id, ...}`. You can use the `*` key to assign a group to all users, which are not in any other group. The map is configured via the `SAML_ROLE_MAPPING` environment variable, which you can configure via the `.env.local` or `docker-compose.yml` file. Please note that you have to enclose the JSON string in single quotes here, as JSON itself uses double quotes (e.g. `SAML_ROLE_MAPPING='{ "*": 2, "editor": 3, "admin": 1 }`). +For this, you need first have to create the groups in Part-DB, to which you want to assign the users and configure their +permissions. You will need the IDs of the groups, which you can find on the `System->Group` page of Part-DB in the Info +tab. -For example if you want to assign the group with ID 1 (by default admin) to every SAML user which has the role `admin`, the role with ID 3 (by default editor) to every SAML user with the role `editor` and everybody else to the group with ID 2 (by default readonly), you can configure the following map: +The map is provided as [JSON](https://en.wikipedia.org/wiki/JSON) encoded map between the SAML role and the group ID, +which has the form `{"saml_role": group_id, "*": group_id, ...}`. You can use the `*` key to assign a group to all +users, which are not in any other group. The map is configured via the `SAML_ROLE_MAPPING` environment variable, which +you can configure via the `.env.local` or `docker-compose.yml` file. Please note that you have to enclose the JSON +string in single quotes here, as JSON itself uses double quotes ( +e.g. `SAML_ROLE_MAPPING='{ "*": 2, "editor": 3, "admin": 1 }`). + +For example, if you want to assign the group with ID 1 (by default admin) to every SAML user which has the role `admin`, +the role with ID 3 (by default editor) to every SAML user with the role `editor` and everybody else to the group with ID +2 (by default readonly), you can configure the following map: ``` SAML_ROLE_MAPPING='{"admin": 1, "editor": 3, "*": 2}' ``` -Please not that the order of the mapping is important. The first matching role will be assigned to the user. So if you have a user with the roles `admin` and `editor`, he will be assigned to the group with ID 1 (admin) and not to the group with ID 3 (editor), as the `admin` role comes first in the JSON map. -This mean that you should always put the most specific roles (e.g. admins) first of the map and the most general roles (e.g. normal users) later. +Please note that the order of the mapping is important. The first matching role will be assigned to the user. So if you +have a user with the roles `admin` and `editor`, he will be assigned to the group with ID 1 (admin) and not to the group +with ID 3 (editor), as the `admin` role comes first in the JSON map. +This mean that you should always put the most specific roles (e.g. admins) first of the map and the most general roles ( +e.g. normal users) later. -If you want to assign users with a certain role to a empty group, provide the group ID -1 as the value. This is not a valid group ID, so the user will not be assigned to any group. +If you want to assign users with a certain role to an empty group, provide the group ID -1 as the value. This is not a +valid group ID, so the user will not be assigned to any group. -The SAML roles (or groups depending on your configuration), have to be supplied via a SAML attribute `group`. You have to configure your SAML identity provider to provide this attribute. For example in Keycloak you can configure this attribute in the `Client scopes` page. Select the `sp-dedicated` client scope (or create a new one) and click on `Add mappers`. Select `Role mapping` or `Group membership`, change the field name and click `Add`. Now Part-DB will be provided with the groups of the user based on the Keycloak user database. +The SAML roles (or groups depending on your configuration), have to be supplied via a SAML attribute `group`. You have +to configure your SAML identity provider to provide this attribute. For example, in Keycloak you can configure this +attribute on the `Client scopes` page. Select the `sp-dedicated` client scope (or create a new one) and click +on `Add mappers`. Select `Role mapping` or `Group membership`, change the field name, and click `Add`. Now Part-DB will +be provided with the groups of the user based on the Keycloak user database. -By default, the group is assigned to the user on the first login and updated on every login based on the SAML attributes. This allows you to configure the groups in the SAML identity provider and the users will automatically stay up to date with their permissions. However, if you want to disable this behavior (and let the Part-DB admins configure the groups manually, after the first login), you can set the `SAML_UPDATE_GROUP_ON_LOGIN` environment variable to `false`. If you want to disable the automatic group assignment completly (so not even on the first login of a user), set the `SAML_ROLE_MAPPING` to `{}` (empty JSON object). +By default, the group is assigned to the user on the first login and updated on every login based on the SAML +attributes. This allows you to configure the groups in the SAML identity provider and the users will automatically stay +up to date with their permissions. However, if you want to disable this behavior (and let the Part-DB admins configure +the groups manually, after the first login), you can set the `SAML_UPDATE_GROUP_ON_LOGIN` environment variable +to `false`. If you want to disable the automatic group assignment completely (so not even on the first login of a user), +set the `SAML_ROLE_MAPPING` to `{}` (empty JSON object). ## Overview of possible SAML attributes used by Part-DB -The following table shows all SAML attributes, which can be usedby Part-DB. If your identity provider is configured to provide these attributes, you can use to automatically fill the corresponding fields of the user in Part-DB. + +The following table shows all SAML attributes, which can be used by Part-DB. If your identity provider is configured to +provide these attributes, you can use to automatically fill the corresponding fields of the user in Part-DB. | SAML attribute | Part-DB user field | Description | -|-------------------------------------------|-------------------|-------------------------------------------------------------------| -| `urn:oid:1.2.840.113549.1.9.1` or `email` | email | The email address of the user. | -| `urn:oid:2.5.4.42` or `firstName` | firstName | The first name of the user. | -| `urn:oid:2.5.4.4` or `lastName` | lastName | The last name of the user. | -| `department` | department | The department of the user. | -| `group` | group | The group of the user (determined by `SAML_ROLE_MAPPING` option). | +|-------------------------------------------|--------------------|-------------------------------------------------------------------| +| `urn:oid:1.2.840.113549.1.9.1` or `email` | email | The email address of the user. | +| `urn:oid:2.5.4.42` or `firstName` | firstName | The first name of the user. | +| `urn:oid:2.5.4.4` or `lastName` | lastName | The last name of the user. | +| `department` | department | The department of the user. | +| `group` | group | The group of the user (determined by `SAML_ROLE_MAPPING` option). | ## Use SAML Login for existing users -Part-DB distinguishes between local users and SAML users. Local users are users, which can login via Part-DB login form and which use the password (hash) saved in the Part-DB database. SAML users are stored in the database too (they are created on the first login of the user via SAML), but they use the SAML identity provider to authenticate the user and have no password stored in the database. When you try you will get an error message. -For security reasons it is not possible to authenticate via SAML as a local user (and vice versa). So if you have existing users in your Part-DB database and want them to be able to login via SAML in the future, you can use the `php bin/console partdb:user:convert-to-saml-user username` command to convert them to SAML users. This will remove the password hash from the database and mark them as SAML users, so they can login via SAML in the future. +Part-DB distinguishes between local users and SAML users. Local users are users, that can log in via the Part-DB login form +and use the password (hash) saved in the Part-DB database. SAML users are stored in the database too (they are +created on the first login of the user via SAML), but they use the SAML identity provider to authenticate the user and +have no password stored in the database. When you try you will get an error message. -The reverse is also possible: If you have existing SAML users and want them to be able to login via the Part-DB login form, you can use the `php bin/console partdb:user:convert-to-saml-user --to-local username` command to convert them to local users. You have to set an password for the user afterwards. +For security reasons, it is not possible to authenticate via SAML as a local user (and vice versa). So if you have +existing users in your Part-DB database and want them to be able to log in via SAML in the future, you can use +the `php bin/console partdb:user:convert-to-saml-user username` command to convert them to SAML users. This will remove +the password hash from the database and mark them as SAML users, so they can log in via SAML in the future. + +The reverse is also possible: If you have existing SAML users and want them to be able to log in via the Part-DB login +form, you can use the `php bin/console partdb:user:convert-to-saml-user --to-local username` command to convert them to +local users. You have to set a password for the user afterward. {: .important } -> It is recommended that you let the original admin user (ID: 2) be a local user, so you can still login to Part-DB if the SAML identity provider is not available. +> It is recommended that you let the original admin user (ID: 2) be a local user, so you can still login to Part-DB if +> the SAML identity provider is not available. ## Advanced SAML configuration -You can find some more advanced SAML configuration options in the `config/packages/hslavich_onelogin_saml.yaml` file. Refer to the file for more information. + +You can find some more advanced SAML configuration options in the `config/packages/nbgrp_onelogin_saml.yaml` file. Refer +to the file for more information. Normally you don't have to change anything here. -Please note that this file is not saved by the Part-DB backup tool, so you have to save it manually if you want to keep your changes. On docker containers you have to configure a volume mapping for it. +Please note that this file is not saved by the Part-DB backup tool, so you have to save it manually if you want to keep +your changes. On docker containers you have to configure a volume mapping for it. +## SAML behind a reverse proxy + +If you are running Part-DB behind a reverse proxy, configure the `TRUSTED_PROXIES` environment and other reverse proxy +settings as described in the [reverse proxy guide]({% link installation/reverse-proxy.md %}). +If you want to use SAML you also need to set `SAML_BEHIND_PROXY` to `true` to enable the SAML proxy mode. diff --git a/docs/partkeepr_migration.md b/docs/partkeepr_migration.md index 41a1ff40..e37f8055 100644 --- a/docs/partkeepr_migration.md +++ b/docs/partkeepr_migration.md @@ -11,41 +11,57 @@ nav_order: 101 This guide describes how to migrate from [PartKeepr](https://partkeepr.org/) to Part-DB. -Part-DB has a built-in migration tool, which can be used to migrate the data from an existing PartKeepr instance to -a new Part-DB instance. Most of the data can be migrated, however there are some limitations, you can find below. - +Part-DB has a built-in migration tool, which can be used to migrate the data from an existing PartKeepr instance to +a new Part-DB instance. Most of the data can be migrated, however, there are some limitations, that you can find below. + ## What can be imported -* Datastructures (Categories, Footprints, Storage Locations, Manufacturers, Distributors, Part Measurement Units) -* Basic part informations (Name, Description, Comment, etc.) -* Attachments and images of parts, projects, footprints, manufacturers and storage locations + +* Data structures (Categories, Footprints, Storage Locations, Manufacturers, Distributors, Part Measurement Units) +* Basic part information (Name, Description, Comment, etc.) +* Attachments and images of parts, projects, footprints, manufacturers, and storage locations * Part prices (distributor infos) * Part parameters * Projects (including parts and attachments) -* Users (optional): Passwords however will be not migrated, and need to be reset later +* Users (optional): Passwords however will not be migrated, and need to be reset later ## What can't be imported -* Metaparts (A dummy version of the metapart will be created in Part-DB, however it will not function as metapart) + +* Metaparts (A dummy version of the metapart will be created in Part-DB, however, it will not function as metapart) * Multiple manufacturers per part (only the last manufacturer of a part will be migrated) -* Overage information for project parts (the overage info will be set as comment in the project BOM, but will have no effect) +* Overage information for project parts (the overage info will be set as a comment in the project BOM, but will have no + effect) * Batch Jobs * Parameter Units (the units will be written into the parameters) * Project Reports and Project Runs -* Stock history +* Stock History * Any kind of PartKeepr preferences ## How to migrate -1. Install Part-DB like described in the installation guide. You can use any database backend you want (mysql or sqlite). Run the database migration, but do not create any new data yet. -2. Export your PartKeepr database as XML file using [mysqldump](https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html): -When the MySQL database is running on the local computer and you are root you can just run the command `mysqldump --xml PARTKEEPR_DATABASE --result-file pk.xml`. -If your server is remote or your MySQL authentication is different, you need to run `mysqldump --xml -h PARTKEEPR_HOST -u PARTKEEPR_USER -p PARTKEEPR_DATABASE`, where you replace `PARTKEEPR_HOST` -with the hostname of your MySQL database and `PARTKEEPR_USER` with the username of MySQL user which has access to the PartKeepr database. You will be asked for the MySQL user password. -3. Go the Part-DB main folder and run the command `php bin/console partdb:migrations:import-partkeepr path/to/pk.xml`. This step will delete all existing data in the Part-DB database and import the contents of PartKeepr. -4. Copy the contents of `data/files/` from your PartKeepr installation to the `uploads/` folder of your Part-DB installation and the contents of `data/images` from PartKeepr to `public/media/` of Part-DB. + +1. Install Part-DB as described in the installation guide. You can use any database backend you want (MySQL or + SQLite). Run the database migration, but do not create any new data yet. +2. Export your PartKeepr database as XML file using [mysqldump](https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html): + When the MySQL database is running on the local computer, and you are root you can just run the + command `mysqldump --xml PARTKEEPR_DATABASE --result-file pk.xml`. + If your server is remote or your MySQL authentication is different, you need to + run `mysqldump --xml -h PARTKEEPR_HOST -u PARTKEEPR_USER -p PARTKEEPR_DATABASE`, where you replace `PARTKEEPR_HOST` + with the hostname of your MySQL database and `PARTKEEPR_USER` with the username of MySQL user which has access to the + PartKeepr database. You will be asked for the MySQL user password. +3. Go to the Part-DB main folder and run the command `php bin/console partdb:migrations:import-partkeepr path/to/pk.xml`. + This step will delete all existing data in the Part-DB database and import the contents of PartKeepr. +4. Copy the contents of `data/files/` from your PartKeepr installation to the `uploads/` folder of your Part-DB + installation and the contents of `data/images` from PartKeepr to `public/media/` of Part-DB. 5. Clear the cache of Part-DB by running: `php bin/console cache:clear` -6. Go to the Part-DB web interface. You can login with the username `admin` and the password, which is shown during the installation process of Part-DB (step 1). You should be able to see all the data from PartKeepr. +6. Go to the Part-DB web interface. You can log in with the username `admin` and the password, which is shown during the + installation process of Part-DB (step 1). You should be able to see all the data from PartKeepr. ## Import users -If you want to import the users (mostly the username and email address) from PartKeepr, you can add the `--import-users` option on the database import command (step 3): `php bin/console partdb:migrations:import-partkeepr --import-users path/to/pk.xml`. -All imported users of PartKeepr will be assigned to a new group "PartKeepr Users", which has normal user permissions (so editing data, but no administrative tasks). You can change the group and permissions later in Part-DB users managment. -Passwords can not be imported from PartKeepr and all imported users get marked as disabled user. So to allow users to login, you need to enable them in the user management and assign a password. \ No newline at end of file +If you want to import the users (mostly the username and email address) from PartKeepr, you can add the `--import-users` +option on the database import command (step 3): +`php bin/console partdb:migrations:import-partkeepr --import-users path/to/pk.xml`. + +All imported users of PartKeepr will be assigned to a new group "PartKeepr Users", which has normal user permissions (so +editing data, but no administrative tasks). You can change the group and permissions later in Part-DB users management. +Passwords can not be imported from PartKeepr and all imported users get marked as disabled. So to allow users to +log in, you need to enable them in the user management and assign a password. \ No newline at end of file diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 9441d9b9..f20a7f22 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -4,35 +4,46 @@ title: Troubleshooting --- # Troubleshooting + Sometimes things go wrong and Part-DB shows an error message. This page should help you to solve the problem. ## Error messages -When a common, easy fixable error occurs (like a non up-to-date database), Part-DB will show you some short instructions on how to fix the problem. If you have a problem that is not listed here, please open an issue on GitHub. + +When a common, easy fixable error occurs (like a non-up-to-date database), Part-DB will show you some short instructions +on how to fix the problem. If you have a problem that is not listed here, please open an issue on GitHub. ## General procedure + If you encounter an error, try the following steps: -* Clear cache of Part-DB with the console command: + +* Clear the cache of Part-DB with the console command: + ```bash php bin/console cache:clear ``` -* Check if the database needs an update (and perform it when needed) with the console command: + +* Check if the database needs an update (and perform it when needed) with the console command: + ```bash php bin/console doctrine:migrations:migrate ``` If this does not help, please [open an issue on GitHub](https://github.com/Part-DB/Part-DB-symfony). -## Search for user and reset password: -You can list all users with the following command: `php bin/console partdb:users:list` -To reset the password of a user you can use the following command: `php bin/console partdb:users:set-password [username]` +## Search for the user and reset the password: +You can list all users with the following command: `php bin/console partdb:users:list` +To reset the password of a user you can use the following +command: `php bin/console partdb:users:set-password [username]` ## Error logs + Detailed error logs can be found in the `var/log` directory. When Part-DB is installed directly, the errors are written to the `var/log/prod.log` file. -When Part-DB is installed with Docker, the errors are written directly to the console output. +When Part-DB is installed with Docker, the errors are written directly to the console output. You can see the logs with the following command, when you are in the folder with the `docker-compose.yml` file + ```bash docker-compose logs -f ``` @@ -40,4 +51,5 @@ docker-compose logs -f Please include the error logs in your issue on GitHub, if you open an issue. ## Report Issue + If an error occurs, or you found a bug, please [open an issue on GitHub](https://github.com/Part-DB/Part-DB-symfony). diff --git a/docs/upgrade_legacy.md b/docs/upgrade_legacy.md index d43fa2ed..e1e43831 100644 --- a/docs/upgrade_legacy.md +++ b/docs/upgrade_legacy.md @@ -6,55 +6,85 @@ nav_order: 100 # Upgrade from legacy Part-DB version -Part-DB 1.0 was a complete rewrite of the old Part-DB (< 1.0.0), which you can find [here](https://github.com/Part-DB/Part-DB). A lot of things changed internally, but Part-DB was always developed with compatibility in mind, so you can migrate smoothly to the new Part-DB version, and utilize its new features and improvements. +Part-DB 1.0 was a complete rewrite of the old Part-DB (< 1.0.0), which you can +find [here](https://github.com/Part-DB/Part-DB). A lot of things changed internally, but Part-DB was always developed +with compatibility in mind, so you can migrate smoothly to the new Part-DB version, and utilize its new features and +improvements. -Some things changed however to the old version and some features are still missing, so be sure to read the following sections carefully before proceeding to upgrade. +Some things changed however to the old version and some features are still missing, so be sure to read the following +sections carefully before proceeding to upgrade. ## Changes -* PHP 7.4 or higher is required now (Part-DB 0.5 required PHP 5.4+, Part-DB 0.6 PHP 7.0). - PHP 7.4 (or newer) is shipped by all current major Linux distros now (and can be installed by third party sources on others), - Releases are available for Windows too, so almost everybody should be able to use PHP 7.4 -* **Console access highly required.** The installation of composer and frontend dependencies require console access, also more sensitive stuff like database migration work via CLI now, so you should have console access on your server. + +* PHP 8.1 or higher is required now (Part-DB 0.5 required PHP 5.4+, Part-DB 0.6 PHP 7.0). + Releases are available for Windows too, so almost everybody should be able to use PHP 8.1 +* **Console access is highly recommended.** The installation of composer and frontend dependencies require console access, + also more sensitive stuff like database migration works via CLI now, so you should have console access on your server. * Markdown/HTML is now used instead of BBCode for rich text in description and command fields. - It is possible to migrate your existing BBCode to Markdown via `php bin/console php bin/console partdb:migrations:convert-bbcode`. -* Server exceptions are not logged to Event log anymore. For security reasons (exceptions can contain sensitive informations) - exceptions are only logged to server log (by default under './var/log'), so only the server admins can access it. -* Profile labels are now saved in Database (before they were saved in a seperate JSON file). **The profiles of legacy Part-DB versions can not be imported into new Part-DB 1.0** -* Label placeholders now use the `[[PLACEHOLDER]]` format instead of `%PLACEHOLDER%`. Also some placeholders has changed. -* Configuration is now done via configuration files / environment variables instead of the WebUI (this maybe change in the future). -* Database updated are now done via console instead of the WebUI + It is possible to migrate your existing BBCode to Markdown + via `php bin/console php bin/console partdb:migrations:convert-bbcode`. +* Server exceptions are not logged into event log anymore. For security reasons (exceptions can contain sensitive + information) exceptions are only logged to server log (by default under './var/log'), so only the server admins can access it. +* Profile labels are now saved in the database (before they were saved in a separate JSON file). **The profiles of legacy + Part-DB versions can not be imported into new Part-DB 1.0** +* Label placeholders now use the `[[PLACEHOLDER]]` format instead of `%PLACEHOLDER%`. Also, some placeholders have + changed. +* Configuration is now done via configuration files/environment variables instead of the WebUI (this may change in + the future). +* Database updates are now done via console instead of the WebUI * Permission system changed: **You will have to newly set the permissions of all users and groups!** -* Import / Export file format changed. Fields must be english now (unlike in legacy Part-DB versions, where german fields in CSV were possible) -and you maybe have to change the header line/field names of your CSV files. +* Import / Export file format changed. Fields must be English now (unlike in legacy Part-DB versions, where German + fields in CSV were possible) + and you may have to change the header line/field names of your CSV files. ## Missing features -* No possibility to mark parts for ordering (yet) + +* No possibility of marking parts for ordering (yet) * No support for 3D models of footprints (yet) -* No possibility to disable footprints, manufacturers globally (or per category). This should not have a big impact, when you forbid users to edit/create them. -* No resistor calculator or SMD labels tools +* No possibility to disable footprints, manufacturers globally (or per category). This should not have a big impact + when you forbid users to edit/create them. +* No resistor calculator or SMD label tools ## Upgrade process {: .warning } -> Once you have upgraded the database to the latest version, you will not be able to access the database with Part-DB 0.5.*. Doing so could lead to data corruption. So make a a backup before you proceed the upgrade, so you will be able to revert the upgrade, when you are not happy with the new version +> Once you have upgraded the database to the latest version, you will not be able to access the database with Part-DB +> 0.5.*. Doing so could lead to data corruption. So make a backup before you proceed the upgrade, so you will be able to +> revert the upgrade, when you are not happy with the new version > -> Beware that all user and group permissions will be reset, and you have to set the permissions again +> Beware that all user and group permissions will be reset, and you have to set the permissions again > the new Part-DB as many permissions changed, and automatic migration is not possible. - 1. Upgrade your existing Part-DB version the newest Part-DB 0.5.* version (in the moment Part-DB 0.5.8), like described in the old Part-DB's repository. - 2. Make a backup of your database and attachments. If somethings goes wrong during migration, you can use this backup to start over. If you have some more complex permission configuration, you maybe want to do screenshots of it, so you can redo it again later. - 3. Setup the new Part-DB like described in installation section. You will need to do the setup for a MySQL instance (either via docker or direct installation). Set the `DATABASE_URL` environment variable in your `.env.local` (or `docker-compose.yaml`) to your existing database. (e.g. `DATABASE_URL=mysql://PARTDB_USER:PASSWORD@localhost:3306/DATABASE_NAME`) - 4. Ensure that the correct base currency is configured (`BASE_CURRENCY` env), this must match the currency used in the old Part-DB version. If you used Euro, you do not need to change anything. - 5. Run `php bin/console cache:clear` and `php bin/console doctrine:migrations:migrate`. - 4. Run `php bin/console partdb:migrations:convert-bbcode` to convert the BBCode used in comments and part description to the newly used markdown. - 5. Copy the content of the `data/media` folder from the old Part-DB instance into `public/media` folder in the new version. - 6. Run `php bin/console cache:clear` - 7. You should be able to login to Part-DB now using your admin account and the old password. If you do not know the admin username, run `php bin/console partdb:users:list` and look for the user with ID 1. You can reset the password of this user using `php bin/console partdb:users:set-password [username]`. - 8. All other users besides the admin user are disabled (meaning they can not login). Go to "System->User" and "System->Group" and check the permissions of the users (and change them if needed). If you are done enable the users again, by removing the disabled checkmark in the password section. If you have a lot of users you can enable them all at once using `php bin/console partdb:users:enable --all` - -**It is not possible to access the database using the old Part-DB version. -If you do so, this could damage your database.** Therefore it is recommended to remove the old Part-DB version, after everything works. +1. Upgrade your existing Part-DB version the newest Part-DB 0.5.* version (at the moment Part-DB 0.5.8), as described + in the old Part-DB's repository. +2. Make a backup of your database and attachments. If something goes wrong during migration, you can use this backup to + start over. If you have some more complex permission configuration, you maybe want to do screenshots of it, so you + can redo it again later. +3. Set up the new Part-DB as described in the installation section. You will need to do the setup for a MySQL instance ( + either via docker or direct installation). Set the `DATABASE_URL` environment variable in your `.env.local` ( + or `docker-compose.yaml`) to your existing database. ( + e.g. `DATABASE_URL=mysql://PARTDB_USER:PASSWORD@localhost:3306/DATABASE_NAME`) +4. Ensure that the correct base currency is configured (`BASE_CURRENCY` env), this must match the currency used in the + old Part-DB version. If you used Euro, you do not need to change anything. +5. Run `php bin/console cache:clear` and `php bin/console doctrine:migrations:migrate`. +6. Run `php bin/console partdb:migrations:convert-bbcode` to convert the BBCode used in comments and part description to + the newly used markdown. +7. Copy the content of the `data/media` folder from the old Part-DB instance into `public/media` folder in the new + version. +8. Run `php bin/console cache:clear` +9. You should be able to log in to Part-DB now using your admin account and the old password. If you do not know the + admin username, run `php bin/console partdb:users:list` and look for the user with ID 1. You can reset the password + of this user using `php bin/console partdb:users:set-password [username]`. +10. All other users besides the admin user are disabled (meaning they can not log in). Go to "System->User" and "System-> + Group" and check the permissions of the users (and change them if needed). If you are done enable the users again, by + removing the disabled checkmark in the password section. If you have a lot of users you can enable them all at once + using `php bin/console partdb:users:enable --all` +**It is not possible to access the database using the old Part-DB version. +If you do so, this could damage your database.** Therefore, it is recommended to remove the old Part-DB version, after +everything works. ## Issues -If you encounter any issues (especially during the database migration) or features do not work like intended, please open an issue ticket at GitHub. \ No newline at end of file + +If you encounter any issues (especially during the database migration) or features do not work like intended, please +open an issue ticket at GitHub. diff --git a/docs/usage/backup_restore.md b/docs/usage/backup_restore.md index edcd1a87..bef3792d 100644 --- a/docs/usage/backup_restore.md +++ b/docs/usage/backup_restore.md @@ -6,48 +6,75 @@ parent: Usage # Backup and Restore Data -When working productively you should backup the data and configuration of Part-DB regularly to prevent data loss. This is also useful, if you want to migrate your Part-DB instance from one server to another. In that case you just have to backup the data on server 1, move the backup to server 2, install Part-DB on server 2 and restore the backup. +When working productively you should back up the data and configuration of Part-DB regularly to prevent data loss. This +is also useful if you want to migrate your Part-DB instance from one server to another. In that case, you just have to +back up the data on server 1, move the backup to server 2, install Part-DB on server 2, and restore the backup. ## Backup (automatic / Part-DB supported) -Part-DB includes a command `php bin/console partdb:backup` which automatically collects all the needed data (described below) and saves them to a ZIP file. + +Part-DB includes a command `php bin/console partdb:backup` which automatically collects all the needed data (described +below) and saves them to a ZIP file. If you are using a MySQL/MariaDB database you need to have `mysqldump` installed and added to your `$PATH` env. ### Usage -To backup all possible data, run the following command: `php bin/console partdb:backup --full /path/to/backup/partdb_backup.zip`. -It is possible to do only partial backups (config, attachments, or database). See `php bin/console partdb:backup --help` for more infos about these options. +To back up all possible data, run the following +command: `php bin/console partdb:backup --full /path/to/backup/partdb_backup.zip`. + +It is possible to do only partial backups (config, attachments, or database). See `php bin/console partdb:backup --help` +for more info about these options. ## Backup (manual) -There are 3 parts which have to be backup-ed: The configuration files, which contains the instance specific options, the uploaded files of attachments, and the database containing the most data of Part-DB. + +3 parts have to be backup-ed: The configuration files, which contain the instance-specific options, the +uploaded files of attachments, and the database containing the most data of Part-DB. Everything else like thumbnails and cache files, are recreated automatically when needed. ### Configuration files -You have to copy the `.env.local` file and (if you have changed it) the `config/parameters.yaml` and `config/banner.md` to your backup location. + +You have to copy the `.env.local` file and (if you have changed it) the `config/parameters.yaml` and `config/banner.md` +to your backup location. ### Attachment files + You have to recursively copy the `uploads/` folder and the `public/media` folder to your backup location. ### Database -#### Sqlite -If you are using sqlite, it is sufficient to just copy your `app.db` from your database location (normally `var/app.db`) to your backup location. + +#### SQLite + +If you are using sqlite, it is sufficient to just copy your `app.db` from your database location (normally `var/app.db`) +to your backup location. #### MySQL / MariaDB -For MySQL / MariaDB you have to dump the database to an SQL file. You can do this manually with phpmyadmin, or you use [`mysqldump`](https://mariadb.com/kb/en/mariadb-dumpmysqldump/) to dump the database to an SQL file via command line interface (`mysqldump -uBACKUP -pPASSWORD DATABASE`) + +For MySQL / MariaDB you have to dump the database to an SQL file. You can do this manually with phpmyadmin, or you +use [`mysqldump`](https://mariadb.com/kb/en/mariadb-dumpmysqldump/) to dump the database to an SQL file via command line +interface (`mysqldump -uBACKUP -pPASSWORD DATABASE`) ## Restore -Install Part-DB as usual as described in the installation section, with the exception of the database creation / migration part. You have to use the same database type (sqlite or mysql) as on the back-uped server instance. + +Install Part-DB as usual as described in the installation section, except for the database creation/migration part. You +have to use the same database type (SQLite or MySQL) as on the backuped server instance. ### Restore configuration -Copy configuration files `.env.local`, (and if existing) `config/parameters.yaml` and `config/banner.md` from the backup to your new Part-DB instance and overwrite the existing files there. + +Copy configuration files `.env.local`, (and if existing) `config/parameters.yaml` and `config/banner.md` from the backup +to your new Part-DB instance and overwrite the existing files there. ### Restore attachment files + Copy the `uploads/` and the `public/media/` folder from your backup into your new Part-DB folder. ### Restore database -#### Sqlite + +#### SQLite + Copy the backup-ed `app.db` into the database folder normally `var/app.db` in Part-DB root folder. #### MySQL / MariaDB -Recreate a database and user with the same credentials as before (or update the database credentials in the `.env.local` file). + +Recreate a database and user with the same credentials as before (or update the database credentials in the `.env.local` +file). Import the dumped SQL file from the backup into your new database. \ No newline at end of file diff --git a/docs/usage/bom_import.md b/docs/usage/bom_import.md index 86e590d7..94a06d55 100644 --- a/docs/usage/bom_import.md +++ b/docs/usage/bom_import.md @@ -7,23 +7,30 @@ parent: Usage # Import Bill of Material (BOM) for Projects -Part-DB supports the import of Bill of Material (BOM) files for projects. This allows you to directly import a BOM file from your ECAD software into your Part-DB project. +Part-DB supports the import of Bill of Material (BOM) files for projects. This allows you to directly import a BOM file +from your ECAD software into your Part-DB project. - -The import process is currently semi-automatic. This means Part-DB will take the BOM file and create entries for all parts in the BOM file in your project and assign fields like -mountnames (e.g. 'C1, C2, C3'), quantity and more. -However, you still have to assign the parts from Part-DB database to the entries (if applicable) after the import by hand, +The import process is currently semi-automatic. This means Part-DB will take the BOM file and create entries for all +parts in the BOM file in your project and assign fields like +mount names (e.g. 'C1, C2, C3'), quantity and more. +However, you still have to assign the parts from Part-DB database to the entries (if applicable) after the import by +hand, as Part-DB can not know which part you had in mind when you designed your schematic. ## Usage + In the project view or edit click on the "Import BOM" button, below the BOM table. This will open a dialog where you can select the BOM file you want to import and some options for the import process: * **Type**: The format/type of the BOM file. See below for explanations of the different types. -* **Clear existing BOM entries before import**: If this is checked, all existing BOM entries, which are currently associated with the project, will be deleted before the import. +* **Clear existing BOM entries before import**: If this is checked, all existing BOM entries, which are currently + associated with the project, will be deleted before the import. ### Supported BOM file formats -* **KiCAD Pcbnew BOM (CSV file)**: A CSV file of the Bill of Material (BOM) generated by [KiCAD Pcbnew](https://www.kicad.org/). -Please note that you have to export the BOM from the PCB editor, the BOM generated by the schematic editor (Eeschema) has a different format and does not work with this type. -You can generate this BOM file by going to "File" -> "Fabrication Outputs" -> "Bill of Materials" in Pcbnew and save the file to your desired location. +* **KiCAD Pcbnew BOM (CSV file)**: A CSV file of the Bill of Material (BOM) generated + by [KiCAD Pcbnew](https://www.kicad.org/). + Please note that you have to export the BOM from the PCB editor, the BOM generated by the schematic editor (Eeschema) + has a different format and does not work with this type. + You can generate this BOM file by going to "File" -> "Fabrication Outputs" -> "Bill of Materials" in Pcbnew and save + the file to your desired location. diff --git a/docs/usage/console_commands.md b/docs/usage/console_commands.md index 7a23483a..e5197251 100644 --- a/docs/usage/console_commands.md +++ b/docs/usage/console_commands.md @@ -8,31 +8,72 @@ parent: Usage Part-DB provides some console commands to display various information or perform some tasks. The commands are invoked from the main directory of Part-DB with the command `php bin/console [command]` in the context -of the database user (so usually the webserver user), so you maybe have to use `sudo` or `su` to execute the commands. +of the database user (so usually the webserver user), so you maybe have to use `sudo` or `su` to execute the commands: + +```bash +sudo -u www-data php bin/console [command] +``` -You can get help for every command with the parameter `--help`. See `php bin/console` for a list of all available commands. +You can get help for every command with the parameter `--help`. See `php bin/console` for a list of all available +commands. + +If you are running Part-DB in a docker container, you must either execute the commands from a shell inside a container, +or use the `docker exec` command to execute the command directly inside the container. For example if you docker container +is named `partdb`, you can execute the command `php bin/console cache:clear` with the following command: + +```bash +docker exec --user=www-data partdb php bin/console cache:clear +``` + +{: .warning } +> If you run a root console inside the docker container, and wanna execute commands on the webserver behalf, be sure to use `sudo -E` command (with the `-E` flag) to preserve env variables from the current shell. +> Otherwise Part-DB console might use the wrong configuration to execute commands. + +## Troubleshooting + +## User management commands -## User managment commands * `php bin/console partdb:users:list`: List all users of this Part-DB instance -* `php bin/console partdb:users:set-password [username]`: Set/Changes the password of the user with the given username. This allows administrators to reset a password of a user, if he forgot it. -* `php bin/console partdb:users:enable [username]`: Enable/Disable the user with the given username (use `--disable` to disable the user, which prevents login) +* `php bin/console partdb:users:set-password [username]`: Set/Changes the password of the user with the given username. + This allows administrators to reset a password of a user, if he forgot it. +* `php bin/console partdb:users:enable [username]`: Enable/Disable the user with the given username (use `--disable` to + disable the user, which prevents login) * `php bin/console partdb:users:permissions`: View/Change the permissions of the user with the given username -* `php bin/console partdb:users:upgrade-permissions-schema`: Upgrade the permissions schema of users to the latest version (this is normally automatically done when the user visits a page) +* `php bin/console partdb:users:upgrade-permissions-schema`: Upgrade the permissions schema of users to the latest + version (this is normally automatically done when the user visits a page) * `php bin/console partdb:logs:show`: Show the most recent entries of the Part-DB event log / recent activity -* `php bin/console partdb:user:convert-to-saml-user`: Convert a local user to a SAML/SSO user. This is needed, if you want to use SAML/SSO authentication for a user, which was created before you enabled SAML/SSO authentication. +* `php bin/console partdb:user:convert-to-saml-user`: Convert a local user to a SAML/SSO user. This is needed, if you + want to use SAML/SSO authentication for a user, which was created before you enabled SAML/SSO authentication. ## Currency commands -* `php bin/console partdb:currencies:update-exchange-rates`: Update the exchange rates of all currencies from the internet) + +* `php bin/console partdb:currencies:update-exchange-rates`: Update the exchange rates of all currencies from the + internet ## Installation/Maintenance commands + * `php bin/console partdb:backup`: Backup the database and the attachments * `php bin/console partdb:version`: Display the current version of Part-DB and the used PHP version -* `php bin/console partdb:check-requirements`: Check if the requirements for Part-DB are met (PHP version, PHP extensions, etc.) and make suggestions what could be improved -* `partdb:migrations:convert-bbcode`: Migrate the old BBCode markup codes used in legacy Part-DB versions (< 1.0.0) to the new markdown syntax -* `partdb:attachments:clean-unused`: Remove all attachments which are not used by any database entry (e.g. orphaned attachments) -* `partdb:cache:clear`: Clears all caches, so the next page load will be slower, but the cache will be rebuild. This can maybe fix some issues, when the cache were corrupted. This command is also needed after changing things in the `parameters.yaml` file or upgrading Part-DB. -* `partdb:migrations:import-partkeepr`: Imports an mysqldump XML dump of a PartKeepr database into Part-DB. This is only needed for users, which want to migrate from PartKeepr to Part-DB. *All existing data in the Part-DB database is deleted!* +* `php bin/console partdb:check-requirements`: Check if the requirements for Part-DB are met (PHP version, PHP + extensions, etc.) and make suggestions what could be improved +* `partdb:migrations:convert-bbcode`: Migrate the old BBCode markup codes used in legacy Part-DB versions (< 1.0.0) to + the new Markdown syntax +* `partdb:attachments:clean-unused`: Remove all attachments which are not used by any database entry (e.g. orphaned + attachments) +* `partdb:cache:clear`: Clears all caches, so the next page load will be slower, but the cache will be rebuilt. This can + maybe fix some issues, when the cache were corrupted. This command is also needed after changing things in + the `parameters.yaml` file or upgrading Part-DB. +* `partdb:migrations:import-partkeepr`: Imports a mysqldump XML dump of a PartKeepr database into Part-DB. This is only + needed for users, which want to migrate from PartKeepr to Part-DB. *All existing data in the Part-DB database is + deleted!* ## Database commands + * `php bin/console doctrine:migrations:migrate`: Migrate the database to the latest version -* `php bin/console doctrine:migrations:up-to-date`: Check if the database is up-to-date \ No newline at end of file +* `php bin/console doctrine:migrations:up-to-date`: Check if the database is up-to-date + +## Attachment commands + +* `php bin/console partdb:attachments:download`: Download all attachments, which are not already downloaded, to the + local filesystem. This is useful to create local backups of the attachments, no matter what happens on the remote and + also makes pictures thumbnails available for the frontend for them \ No newline at end of file diff --git a/docs/usage/eda_integration.md b/docs/usage/eda_integration.md new file mode 100644 index 00000000..9444e55f --- /dev/null +++ b/docs/usage/eda_integration.md @@ -0,0 +1,79 @@ +--- +layout: default +title: EDA / KiCad integration +parent: Usage +--- + +# EDA / KiCad integration + +Part-DB can function as a central database for [EDA](https://en.wikipedia.org/wiki/Electronic_design_automation) or ECAD software used to design electronic schematics and PCBs. +You can connect your EDA software and can view your available parts, with the data saved from Part-DB directly in your EDA software. +Part-DB allows to configure additional metadata for the EDA, to associate symbols and footprints for use inside the EDA software, so the part becomes +directly usable inside the EDA software. +This also allows to configure available and usable parts and their properties in a central place, which is especially useful in teams, where multiple persons design PCBs. + +**Currently only KiCad is supported!** + +## KiCad Setup + +{: .important } +> Part-DB uses the HTTP library feature of KiCad, which is experimental and not part of the stable KiCad 7 releases. If you want to use this feature, you need to install a KiCad nightly build (7.99 version). This feature will most likely also be part of KiCad 8. + +Part-DB should be accessible from the PCs with KiCAD. The URL should be stable (so no dynamically changing IP). +You require a user account in Part-DB, which has permission to access Part-DB API and create API tokens. Every user can have its own account, or you set up a shared read-only account. + +To connect KiCad with Part-DB do the following steps: + +1. Create an API token on the user settings page for the KiCAD application and copy/save it, when it is shown. Currently, KiCad can only read Part-DB database, so a token with a read-only scope is enough. +2. Add some EDA metadata to parts, categories, or footprints. Only parts with usable info will show up in KiCad. See below for more info. +3. Create a file `partd.kicad_httplib` (or similar, only the extension is important) with the following content: +``` +{ + "meta": { + "version": 1.0 + }, + "name": "Part-DB library", + "description": "This KiCAD library fetches information externally from ", + "source": { + "type": "REST_API", + "api_version": "v1", + "root_url": "http://kicad-instance.invalid/en/kicad-api/", + "token": "THE_GENERATED_API_TOKEN" + } +} +``` +4. Replace the `root_url` with the URL of your Part-DB instance plus `/en/kicad-api/`. You can find the right value for this in the Part-DB user settings page under "API endpoints" in the "API tokens" panel. +5. Replace the `token` field value with the token you have generated in step 1. +6. Open KiCad and add this created file as a library in the KiCad symbol table under (Preferences --> Manage Symbol Libraries) + +If you then place a new part, the library dialog opens, and you should be able to see the categories and parts from Part-DB. + +### How to associate footprints and symbols with parts + +Part-DB doesn't save any concrete footprints or symbols for the part. Instead, Part-DB just contains a reference string in the part metadata, which points to a symbol/footprint in KiCad's local library. + +You can define this on a per-part basis using the KiCad symbol and KiCad footprint field in the EDA tab of the part editor. Or you can define it at a category (symbol) or footprint level, to assign this value to all parts with this category and footprint. + +For example, to configure the values for a BC547 transistor you would put `Transistor_BJT:BC547` on the parts Kicad symbol to give it the right schematic symbol in EEschema and `Package_TO_SOT_THT:TO-92` to give it the right footprint in PcbNew. + +If you type in a character, you will get an autocomplete list of all symbols and footprints available in the KiCad standard library. You can also input your own value. + +### Parts and category visibility + +Only parts and their categories, on which there is any kind of EDA metadata are defined show up in KiCad. So if you want to see parts in KiCad, +you need to define at least a symbol, footprint, reference prefix, or value on a part, category or footprint. + +You can use the "Force visibility" checkbox on a part or category to override this behavior and force parts to be visible or hidden in KiCad. + +*Please note that KiCad caches the library categories. So if you change something, which would change the visible categories in KiCad, you have to reload EEschema to see the changes.* + +### Category depth in KiCad + +For performance reasons, only the most top-level categories of Part-DB are shown as categories in KiCad. All parts in the subcategories are shown in the top-level category. + +You can configure the depth of the categories shown in KiCad, via the `EDA_KICAD_CATEGORY_DEPTH` env option. The default value is 0, which means only the top-level categories are shown. +To show more levels of categories, you can set this value to a higher number. + +If you set this value to -1, all parts are shown inside a single category in KiCad, without any subcategories. + +You can view the "real" category path of a part in the part details dialog in KiCad. diff --git a/docs/usage/getting_started.md b/docs/usage/getting_started.md index bc25123f..4bb8afb9 100644 --- a/docs/usage/getting_started.md +++ b/docs/usage/getting_started.md @@ -7,111 +7,145 @@ nav_order: 4 # Getting started After Part-DB you should begin with customizing the settings, and setting up the basic structures. -Before starting its useful to read a bit about the [concepts of Part-DB]({% link concepts.md %}). +Before starting, it's useful to read a bit about the [concepts of Part-DB]({% link concepts.md %}). 1. TOC {:toc} ## Customize config files -Before you start creating data structures, you should configure Part-DB to your needs by changing possible configuration options. -This is done either via changing the `.env.local` file in a direct installation or by changing the env variables in your `docker-compose.yaml` file. -A list of possible configuration options, can be found [here]({% link configuration.md %}). +Before you start creating data structures, you should configure Part-DB to your needs by changing possible configuration +options. +This is done either via changing the `.env.local` file in a direct installation or by changing the env variables in +your `docker-compose.yaml` file. +A list of possible configuration options can be found [here]({% link configuration.md %}). ## Change password, Set up Two-Factor-Authentication & Customize User settings -If you have not already done, you should change your user password. You can do this in the user settings (available in the navigation bar drop down with the user symbol). +If you have not already done so, you should change your user password. You can do this in the user settings (available in +the navigation bar drop-down with the user symbol). ![image]({% link assets/getting_started/change_password.png %}) -There you can also find the option, to set up Two Factor Authentication methods like Google Authenticator. Using this is highly recommended (especially if you have admin permissions) to increase the security of your account. (Two Factor Authentication even can be enforced for all members of a user group) +There you can also find the option, to set up Two-Factor Authentication methods like Google Authenticator. Using this is +highly recommended (especially if you have admin permissions) to increase the security of your account. (Two-factor authentication +even can be enforced for all members of a user group) -In the user settings panel you can change account infos like your username, your first and last name (which will be shown alongside your username to identify you better), department information and your email address. The email address is used to send password reset mails, if your system is configured to use this. +In the user settings panel, you can change account info like your username, your first and last name (which will be +shown alongside your username to identify you better), department information, and your email address. The email address +is used to send password reset mails if your system is configured to use this. ![image]({% link assets/getting_started/user_settings.png %}) -In the configuration tab you can also override global settings, like your preferred UI language (which will automatically be applied after login), the timezone you are in (and in which times will be shown for you), your preferred currency (all money values will be shown converted to this to you, if possible) and the theme that should be used. +In the configuration tab you can also override global settings, like your preferred UI language (which will +automatically be applied after login), the timezone you are in (and in which times will be shown for you), your +preferred currency (all money values will be shown converted to this to you, if possible) and the theme that should be +used. ## (Optional) Customize homepage banner -The banner which is shown on the homepage, can be customized/changed by changing the `config/banner.md` file with a text editor. You can use markdown and (safe) HTML here, to style and customize the banner. -You can even use Latex style equations by wrapping the expressions into `$` (like `$E=mc^2$`, which is rendered inline: $E=mc^2$) or `$$` (like `$$E=mc^2$$`) which will be rendered as a block, like so: $$E=mc^2$$ +The banner which is shown on the homepage, can be customized/changed by changing the `config/banner.md` file with a text +editor. You can use markdown and (safe) HTML here, to style and customize the banner. +You can even use LaTeX-style equations by wrapping the expressions into `$` (like `$E=mc^2$`, which is rendered inline: +$E=mc^2$) or `$$` (like `$$E=mc^2$$`) which will be rendered as a block, like so: $$E=mc^2$$ ## Create groups, users and customize permissions ### Users -When logged in as administrator, you can open the users menu in the `Tools` section of the sidebar under `System -> Users`. -At this page you can create new users, change their passwords and settings and change their permissions. -For each user which should use Part-DB you should setup a own account, so that tracking of what user did what works properly. +When logged in as administrator, you can open the users menu in the `Tools` section of the sidebar +under `System -> Users`. +On this page you can create new users, change their passwords and settings, and change their permissions. +For each user who should use Part-DB you should set up their own account so that tracking of what user did works +properly. ![image]({% link assets/getting_started/user_admin.png %}) - -You should check the permissions for every user and ensure that they are in the intended way, and no user has more permissions than he needs. -For each capability you can choose between allow, forbid and inherit. In the last case, the permission is determined by the group a user has (if no group is chosen, it equals forbid) +You should check the permissions for every user and ensure that they are in the intended way, and no user has more +permissions than he needs. +For each capability, you can choose between allow, forbid, and inherit. In the last case, the permission is determined by +the group a user has (if no group is chosen, it equals forbid) ![image]({% link assets/getting_started/user_permissions.png %}) - ### Anonymous user -The `anonymous` user is special, as its settings and permissions are used for everybody who is not logged in. By default the anonymous user has read capabilities for your parts. If your Part-DB instance is publicly available you maybe want to restrict the permissions. +The `anonymous` user is special, as its settings and permissions are used for everybody who is not logged in. By default, +the anonymous user has read capabilities for your parts. If your Part-DB instance is publicly available you maybe want +to restrict the permissions. ### Groups -If you have many users which should share the same permissions, it is useful to define the permissions using user groups, which you can create and edit in the `System -> Groups` menu. +If you have many users who should share the same permissions, it is useful to define the permissions using user +groups, which you can create and edit in the `System -> Groups` menu. -By default 3 groups are defined: -* `readonly` which users have only have read permissions (like viewing, searching parts, attachments, etc.) +By default, 3 groups are defined: + +* `readonly` which users only have read permissions (like viewing, searching parts, attachments, etc.) * `users` which users also have rights to edit/delete/create elements -* `admin` which users can do administrative operations (like creating new users, show global system log, etc.) +* `admin` which users can do administrative operations (like creating new users, showing global system log, etc.) -Users only use the setting of a capability from a group, if the user has a group associated and the capability on the user is set to `inherit` (which is the default if creating a new user). You can override the permissions settings of a group per user by explicitly settings the permission at the user. - -Groups are organized as trees, meaning a group can have parent and child permissions and child groups can inherit permissions from their parents. -To inherit the permissions from a parent group set the capability to inherit, otherwise set it explicitly to override the parents permission. +Users only use the setting of a capability from a group, if the user has a group associated and the capability on the +user is set to `inherit` (which is the default if creating a new user). You can override the permissions settings of a +group per user by explicitly setting the permission of the user. +Groups are organized as trees, meaning a group can have parent and child permissions and child groups can inherit +permissions from their parents. +To inherit the permissions from a parent group set the capability to inherit, otherwise, set it explicitly to override +the parents' permission. ## Create Attachment types -Every attachment (that is an file associated with a part, data structure, etc.) must have an attachment type. They can be used to group attachments logically, like differentiating between datasheets, pictures and other documents. +Every attachment (that is a file associated with a part, data structure, etc.) must have an attachment type. They can +be used to group attachments logically, like differentiating between datasheets, pictures, and other documents. You can create/edit attachment types in the tools sidebar under "Edit -> Attachment types": ![image]({% link assets/getting_started/attachment_type_admin.png %}) - -Depending on your usecase different entries here make sense. For part mananagment the following (additional) entries maybe make sense: + +Depending on your use case different entries here make sense. For part management the following (additional) entries may make sense: * Datasheets (restricted to pdfs, Allowed filetypes: `application/pdf`) * Pictures (for generic pictures of components, storage locations, etc., Allowed filetypes: `image/*` -For every attachment type a list of allowed file types, which can be uploaded to an attachment with this attachment type, can be defined. You can either pass a list of allowed file extensions (e.g. `.pdf, .zip, .docx`) and/or a list of [Mime Types](https://en.wikipedia.org/wiki/Media_type) (e.g. `application/pdf, image/jpeg`) or a combination of both here. To allow all browser supported images, you can use `image/*` wildcard here. +For every attachment type a list of allowed file types, which can be uploaded to an attachment with this attachment +type, can be defined. You can either pass a list of allowed file extensions (e.g. `.pdf, .zip, .docx`) and/or a list +of [Mime Types](https://en.wikipedia.org/wiki/Media_type) (e.g. `application/pdf, image/jpeg`) or a combination of both +here. To allow all browser-supported images, you can use `image/*` wildcard here. ## (Optional) Create Currencies -If you want to save priceinformations for parts in a currency different to your global currency (by default Euro), you have to define the additional currencies you want to use under `Edit -> Currencies`: +If you want to save price information for parts in a currency different from your global currency (by default Euro), you +have to define the additional currencies you want to use under `Edit -> Currencies`: ![image]({% link assets/getting_started/currencies_admin.png %}) -You create a new currency, name it however you want (it is recommended to use the official name of the currency) and select the currency ISO code from the list and save it. The currency symbol is determined automatically from chose ISO code. -You can define a exchange rate in terms of your base currency (e.g. how much euros is one unit of your currency worth) to convert the currencies values in your preferred display currency automatically. - +You create a new currency, name it however you want (it is recommended to use the official name of the currency), +select the currency ISO code from the list, and save it. The currency symbol is determined automatically from the chosen ISO +code. +You can define an exchange rate in terms of your base currency (e.g. how many euros is one unit of your currency worth) +to convert the currency values in your preferred display currency automatically. ## (Optional) Create Measurement Units -By default Part-DB assumes that the parts in inventory can be counted by individual indivisible pieces, like LEDs in a box or books in a shelf. -However if you want to manage things, that are divisible and and the instock is described by a physical quantity, like length for cables, or volumina of a liquid, you have to define additional measurement units. +By default, Part-DB assumes that the parts in inventory can be counted by individual indivisible pieces, like LEDs in a +box or books on a shelf. +However, if you want to manage things, that are divisible and the stock is described by a physical quantity, like +length for cables, or volumes of a liquid, you have to define additional measurement units. This is possible under `Edit -> Measurement Units`: ![image]({% link assets/getting_started/units_admin.png %}) -You can give the measurement unit a name and an optional unit symbol (like `m` for meters) which is shown when quantities in this unit are displayed. The option `Use SI prefix` is useful for almost all physical quantities, as big and small numbers are automatically formatted with SI-prefixes (like 1.5kg instead 1500 grams). +You can give the measurement unit a name and an optional unit symbol (like `m` for meters) which is shown when +quantities in this unit are displayed. The option `Use SI prefix` is useful for almost all physical quantities, as big +and small numbers are automatically formatted with SI prefixes (like 1.5kg instead 1500 grams). -The measurement unit can be selected for each part individually, by setting the option in the advanced tab of a part`s edit menu. +The measurement unit can be selected for each part individually, by setting the option in the advanced tab of a part`s +edit menu. ## Create Categories -A category is used to group parts logically by their function (e.g. all NPN transistors would be put in a "NPN-Transistors" category). +A category is used to group parts logically by their function (e.g. all NPN transistors would be put in a " +NPN-Transistors" category). Categories are hierarchical structures meaning that you can create logical trees to group categories together. See [Concepts]({% link concepts.md %}) for an example tree structure. @@ -121,43 +155,51 @@ Every part has to be assigned to a category, so you should create at least one c ## (Optional) Create Footprints -Footprints are used to describe the physical shape of a part, like a resistor or a capacitor. -They can be used to group parts by their physical shape and to find parts with in the same package. +Footprints are used to describe the physical shape of a part, like a resistor or a capacitor. +They can be used to group parts by their physical shape and to find parts within the same package. You can create/edit footprints in the tools sidebar under "Edit -> Footprints". -It is useful to create footprints for the most common packages, like SMD resistors, capacitors, etc. to make it easier to find parts with the same footprint. -You should create these as a tree structure, so that you can group footprints by their type. +It is useful to create footprints for the most common packages, like SMD resistors, capacitors, etc. to make it easier +to find parts with the same footprint. +You should create these as a tree structure so that you can group footprints by their type. See [Concepts]({% link concepts.md %}) for an example tree structure. -You can define attachments here which are associated with the footprint. The attachment set as preview image, will be +You can define attachments here which are associated with the footprint. The attachment set as the preview image, will be used whenever a visual representation of the footprint is needed (e.g. in the part list). -For many common footprints, you can use the built-in footprints, which can be found in the "Builtin footprint image gallery", which you can find in the tools menu. -Type the name of the image you want to use in the URL field of the attachment and select the image from the dropdown menu. +For many common footprints, you can use the built-in footprints, which can be found in the "Builtin footprint image +gallery", which you can find in the "tools" menu. +Type the name of the image you want to use in the URL field of the attachment and select the image from the dropdown +menu. ## (Optional) Create Storage locations -A storelocation represents a place where parts can be stored. +A storage location represents a place where parts can be stored. You can create/edit storage locations in the tools sidebar under "Edit -> Storage locations". ## (Optional) Create Manufacturers and suppliers -You can create/edit [manufacturers]({% link concepts.md %}#manufacturers) and [suppliers]({% link concepts.md %}#suppliers) in the tools sidebar under "Edit -> Manufacturers" and "Edit -> Suppliers". +You can create/edit [manufacturers]({% link concepts.md %}#manufacturers) and [suppliers]({% link concepts.md +%}#suppliers) in the tools sidebar under "Edit -> Manufacturers" and "Edit -> Suppliers". ## Create parts -You are now ready to create your first part. You can do this by clicking either by clicking "Edit -> New Part" in the tools sidebar tree -or by clicking the "Create new Part" above the (empty) part list, after clicking on one of your newly created categories. +You are now ready to create your first part. You can do this by clicking either by clicking "Edit -> New Part" in the +tools sidebar tree +or by clicking the "Create new Part" above the (empty) part list, after clicking on one of your newly created +categories. You will be presented with a form where you can enter the basic information about your part: ![image]({% link assets/getting_started/new_part.png %}) You have to enter at least a name for the part and choose a category for it, the other fields are optional. -However, it is recommended to fill out as much information as possible, as this will make it easier to find the part later. +However, it is recommended to fill out as much information as possible, as this will make it easier to find the part +later. You can choose from your created datastructures to add manufacturer information, supplier information, etc. to the part. You can also create new datastructures on the fly, if you want to add additional information to the part, by typing the -name of the new datastructure in the field and select the "New ..." option in the dropdown menu. See [tips]({% link usage/tips_tricks.md %}) for more information. \ No newline at end of file +name of the new datastructure in the field and select the "New ..." option in the dropdown menu. See [tips]({% link +usage/tips_tricks.md %}) for more information. \ No newline at end of file diff --git a/docs/usage/import_export.md b/docs/usage/import_export.md index 09e4b163..e43936cc 100644 --- a/docs/usage/import_export.md +++ b/docs/usage/import_export.md @@ -7,97 +7,155 @@ parent: Usage # Import & Export data -Part-DB offers the possibility to import existing data (parts, datastructures, etc.) from existing datasources into Part-DB. Data can also be exported from Part-DB into various formats. +Part-DB offers the possibility to import existing data (parts, data structures, etc.) from existing data sources into +Part-DB. Data can also be exported from Part-DB into various formats. ## Import {: .note } -> As data import is a very powerful feature and can easily fill up your database with lots of data, import is by default only available for -> administrators. If you want to allow other users to import data, or can not import data, check the permissions of the user. You can enable import for each data structure +> As data import is a very powerful feature and can easily fill up your database with lots of data, import is by default +> only available for +> administrators. If you want to allow other users to import data, or can not import data, check the permissions of the +> user. You can enable import for each data structure > individually in the permissions settings. -If you want to import data from PartKeepr you might want to look into the [PartKeepr migration guide]({% link upgrade_legacy.md %}). +If you want to import data from PartKeepr you might want to look into the [PartKeepr migration guide]({% link +upgrade_legacy.md %}). ### Import parts -Part-DB supports the import of parts from CSV files and other formats. This can be used to import existing parts from other databases or datasources into Part-DB. The import can be done via the "Tools -> Import parts" page, which you can find in the "Tools" sidebar panel. +Part-DB supports the import of parts from CSV files and other formats. This can be used to import existing parts from +other databases or data sources into Part-DB. The import can be done via the "Tools -> Import parts" page, which you can +find in the "Tools" sidebar panel. {: .important } -> When importing data, the data is immediatley written to database during the import process, when the data is formally valid. -> You will not be able to check the data before it is written to the database, so you should review the data before using the import tool. +> When importing data, the data is immediately written to database during the import process, when the data is formally +> valid. +> You will not be able to check the data before it is written to the database, so you should review the data before +> using the import tool. -You can upload the file which should be imported here and choose various options on how the data should be treated: -* **Format**: By default "auto" is selected here and Part-DB will try to detect the format of the file automatically based on its file extension. If you want to force a specific format or Part-DB can not auto-detect the format, you can select it here. -* **CSV delimiter**: If you upload an CSV file, you can select the delimiter character which is used to separate the columns in the CSV file. Depending on the CSV file, this might be a comma (`,`), semicolon (`;`). -* **Category override**: You can select (or create) a category here, to which all imported parts should be assigned, no matter what was specified in the import file. This can be useful if you want to assign all imports to a certain category or if no category is specified in the data. If you leave this field empty, the category will be determined by the import file (or the export will error, if no category is specified). -* **Mark all imported parts as "Needs review"**: If this is selected, all imported parts will be marked as "Needs review" after the import. This can be useful if you want to review all imported parts before using them. -* **Create unknown datastructures**: If this is selected Part-DB will create new datastructures (like categories, manufacturers, etc.) if no datastructure(s) with the same name and path already exists. If this is not selected, only existing datastructures will be used and if no matching datastrucure is found, the imported parts field will be empty. -* **Path delimiter**: Part-DB allows you to create/select nested datastructures (like categories, manufacturers, etc.) by using a path (e.g. `Category 1->Category 1.1`, which will select/create the `Category 1.1` whose parent is `Category 1`). This path is separated by the path delimiter. If you want to use a different path delimiter than the default one (which is `>`), you can select it here. -* **Abort on validation error**: If this is selected, the import will be aborted if a validation error occurs (e.g. if a required field is empty) for any of the imported parts and validation errors will be shown on top of the page. If this is not selected, the import will continue for the other parts and only the invalid parts will be skipped. +You can upload the file that should be imported here and choose various options on how the data should be treated: -After you have selected the options, you can start the import by clicking the "Import" button. When the import is finished, you will see the results of the import in the lower half of the page. You find a table with the imported parts (including links to them) there. +* **Format**: By default "auto" is selected here and Part-DB will try to detect the format of the file automatically + based on its file extension. If you want to force a specific format or Part-DB can not auto-detect the format, you can + select it here. +* **CSV delimiter**: If you upload a CSV file, you can select the delimiter character which is used to separate the + columns in the CSV file. Depending on the CSV file, this might be a comma (`,`) or semicolon (`;`). +* **Category override**: You can select (or create) a category here, to which all imported parts should be assigned, no + matter what was specified in the import file. This can be useful if you want to assign all imports to a certain + category or if no category is specified in the data. If you leave this field empty, the category will be determined by + the import file (or the export will error, if no category is specified). +* **Mark all imported parts as "Needs review"**: If this is selected, all imported parts will be marked as "Needs + review" after the import. This can be useful if you want to review all imported parts before using them. +* **Create unknown data structures**: If this is selected Part-DB will create new data structures (like categories, + manufacturers, etc.) if no data structure(s) with the same name and path already exists. If this is not selected, only + existing data structures will be used and if no matching data strucure is found, the imported parts field will be empty. +* **Path delimiter**: Part-DB allows you to create/select nested data structures (like categories, manufacturers, etc.) + by using a path (e.g. `Category 1->Category 1.1`, which will select/create the `Category 1.1` whose parent + is `Category 1`). This path is separated by the path delimiter. If you want to use a different path delimiter than the + default one (which is `>`), you can select it here. +* **Abort on validation error**: If this is selected, the import will be aborted if a validation error occurs (e.g. if a + required field is empty) for any of the imported parts and validation errors will be shown on top of the page. If this + is not selected, the import will continue for the other parts and only the invalid parts will be skipped. + +After you have selected the options, you can start the import by clicking the "Import" button. When the import is +finished, you will see the results of the import in the lower half of the page. You can find a table with the imported +parts (including links to them) there. #### Fields description -For the importing of parts, you can use the following fields which will be imported into each part. Please note that the field names are case sensitive (so `name` is not the same as `Name`). All fields (besides name) are optional, so you can leave them empty or do not include the column in your file. +For the importing of parts, you can use the following fields which will be imported into each part. Please note that the +field names are case-sensitive (so `name` is not the same as `Name`). All fields (besides name) are optional, so you can +leave them empty or do not include the column in your file. * **`name`** (required): The name of the part. This is the only required field, all other fields are optional. * **`description`**: The description of the part, you can use markdown/HTML syntax here for rich text formatting. * **`notes`** or **`comment`**: The notes of the part, you can use markdown/HTML syntax here for rich text formatting. -* **`category`**: The category of the part. This can be a path (e.g. `Category 1->Category 1.1`), which will select/create the `Category 1.1` whose parent is `Category 1`. If you want to use a different path delimiter than the default one (which is `->`), you can select it in the import options. If the category does not exist and the option "Create unknown datastructures" is selected, it will be created. +* **`category`**: The category of the part. This can be a path (e.g. `Category 1->Category 1.1`), which will + select/create the `Category 1.1` whose parent is `Category 1`. If you want to use a different path delimiter than the + default one (which is `->`), you can select it in the import options. If the category does not exist and the option " + Create unknown datastructures" is selected, it will be created. * **`footprint`**: The footprint of the part. Can be a path similar to the category field. * **`favorite`**: If this is set to `1`, the part will be marked as favorite. * **`manufacturer`**: The manufacturer of the part. Can be a path similar to the category field. * **`manufacturer_product_number`** or **`mpn`**: The manufacturer product number of the part. -* **`manufacturer_product_url`: The URL to the product page of the manufacturer of the part. -* **`manufacturing_status`**: The manufacturing status of the part, must be one of the following values: `announced`, `active`, `nrfnd`, `eol`, `discontinued` or left empty. +* **`manufacturer_product_url`**: The URL to the product page of the manufacturer of the part. +* **`manufacturing_status`**: The manufacturing status of the part, must be one of the following + values: `announced`, `active`, `nrfnd`, `eol`, `discontinued` or left empty. * **`needs_review`** or **`needs_review`**: If this is set to `1`, the part will be marked as "needs review". -* **`tags`**: A comma separated list of tags for the part. +* **`tags`**: A comma-separated list of tags for the part. * **`mass`**: The mass of the part in grams. * **`ipn`**: The IPN (Item Part Number) of the part. * **`minamount`**: The minimum amount of the part which should be in stock. * **`partUnit`**: The measurement unit of the part to use. Can be a path similar to the category field. -With the following fields you can specify storage locations and amount / quantiy in stock of the part. An PartLot will be created automatically from the data and assigned to the part. The following fields are helpers for an easy import for parts at one storage location. If you need to create a Part with multiple PartLots you have to use JSON format (or CSV) with nested objects: +With the following fields, you can specify storage locations and amount/quantity in stock of the part. A PartLot will +be created automatically from the data and assigned to the part. The following fields are helpers for an easy import of +parts at one storage location. If you need to create a Part with multiple PartLots you have to use JSON format (or CSV) +with nested objects: -**`storage_location`** or **`storelocation`**: The storage location of the part. Can be a path similar to the category field. -**`amount`**, **`quantity`** or **`instock`**: The amount of the part in stock. If this value is not set, the part lot will be marked with "unknown amount" +**`storage_location`** or **`storelocation`**: The storage location of the part. Can be a path similar to the category +field. +**`amount`**, **`quantity`** or **`instock`**: The amount of the part in stock. If this value is not set, the part lot +will be marked with "unknown amount" -The following fields can be used to specify the supplier/distributor, supplier product number and the price of the part. This is only possible for a single supplier/distributor and price with this fields. If you need to specify multiple suppliers/distributors or prices, you have to use JSON format (or CSV) with nested objects. -**Please note that the supplier fields is required, if you want to import prices or supplier product numbers.**. If the supplier is not specified, the price and supplier product number fields will be ignored: +The following fields can be used to specify the supplier/distributor, supplier product number, and the price of the part. +This is only possible for a single supplier/distributor and price with these fields. If you need to specify multiple +suppliers/distributors or prices, you have to use JSON format (or CSV) with nested objects. +**Please note that the supplier fields is required, if you want to import prices or supplier product numbers**. If the +supplier is not specified, the price and supplier product number fields will be ignored: * **`supplier`**: The supplier of the part. Can be a path similar to the category field. * **`supplier_product_number`** or **`supplier_part_number`** or * **`spn`**: The supplier product number of the part. * **`price`**: The price of the part in the base currency of the database (by default euro). #### Example data -Here you can find some example data for the import of parts, you can use it as a template for your own import (especially the CSV file). + +Here you can find some example data for the import of parts, you can use it as a template for your own import ( +especially the CSV file). * [Part import CSV example]({% link assets/usage/import_export/part_import_example.csv %}) with all possible fields ## Export -By default every user, who can read the datastructure, can also export the data of this datastructure, as this does not give the user any additional information. +By default, every user, who can read the datastructure, can also export the data of this datastructure, as this does not +give the user any additional information. ### Exporting data structures (categories, manufacturers, etc.) -You can export data structures (like categories, manufacturers, etc.) in the respective edit page (e.g. Tools Panel -> Edit -> Category). -If you select a certain datastructure from your list, you can export it (and optionally all sub-datastructures) in the "Export" tab. -If you want to export all datastructures of a certain type (e.g. all categories in your database), you can select the "Export all" function in the "Import / Export" tab of the "new element" page. + +You can export data structures (like categories, manufacturers, etc.) in the respective edit page (e.g. Tools Panel -> +Edit -> Category). +If you select a certain data structure from your list, you can export it (and optionally all sub data structures) in the " +Export" tab. +If you want to export all data structures of a certain type (e.g. all categories in your database), you can select the " +Export all" function in the "Import / Export" tab of the "new element" page. You can select between the following export formats: -* **CSV** (Comma Separated Values): A semicolon separated list of values, where every line represents an element. This format can be imported into Excel or LibreOffice Calc and is easy to work with. However it does not support nested datastructures or sub data (like parameters, attachments, etc.), very well (many columns are generated, as every possible sub data is exported as a separate column). -* **JSON** (JavaScript Object Notation): A text-based format, which is easy to work with programming laguages. It supports nested datastructures and sub data (like parameters, attachments, etc.) very well. However it is not easy to work with in Excel or LibreOffice Calc and you maybe need to write some code to work with the exported data efficiently. -* **YAML** (Yet another Markup Language): Very similar to JSON -* **XML** (Extensible Markup Language): Good support with nested datastructures. Similar usecase as JSON and YAML. -Also you can select between the following export levels: +* **CSV** (Comma Separated Values): A semicolon-separated list of values, where every line represents an element. This + format can be imported into Excel or LibreOffice Calc and is easy to work with. However, it does not support nested + data structures or sub data (like parameters, attachments, etc.), very well (many columns are generated, as every + possible sub-data is exported as a separate column). +* **JSON** (JavaScript Object Notation): A text-based format, which is easy to work with programming languages. It + supports nested data structures and sub-data (like parameters, attachments, etc.) very well. However, it is not easy to + work with in Excel or LibreOffice Calc and you may need to write some code to work with the exported data + efficiently. +* **YAML** (Yet Another Markup Language): Very similar to JSON +* **XML** (Extensible Markup Language): Good support with nested data structures. Similar use cases as JSON and YAML. + +Also, you can select between the following export levels: + * **Simple**: This will only export very basic information about the name (like the name, or description for parts) -* **Extended**: This will export all commonly used information about this datastructure (like notes, options, etc) -* **Full**: This will export all available information about this datastructure (like all parameters, attachments) +* **Extended**: This will export all commonly used information about this data structure (like notes, options, etc.) +* **Full**: This will export all available information about this data structure (like all parameters, attachments) -Please note that the level will also be applied to all sub data or children elements. So if you select "Full" for a part, all the associated categories, manufacturers, footprints, etc. will also be exported with all available information, this can lead to very large export files. +Please note that the level will also be applied to all sub-data or children elements. So if you select "Full" for a +part, all the associated categories, manufacturers, footprints, etc. will also be exported with all available +information, this can lead to very large export files. ### Exporting parts -You can export parts in all part tables. Select the parts you want via the checkbox in the table line and select the export format and level in the appearing menu. -See the section about exporting datastructures for more information about the export formats and levels. \ No newline at end of file +You can export parts in all part tables. Select the parts you want via the checkbox in the table line and select the +export format and level in the appearing menu. + +See the section about exporting data structures for more information about the export formats and levels. \ No newline at end of file diff --git a/docs/usage/information_provider_system.md b/docs/usage/information_provider_system.md index b1a69187..8de83a8e 100644 --- a/docs/usage/information_provider_system.md +++ b/docs/usage/information_provider_system.md @@ -6,135 +6,268 @@ parent: Usage # Information provider system -Part-DB can create parts based on information from external sources: For example with the right setup you can just search for a part number -and Part-DB will query selected distributors and manufacturers for the part and create a part with the information it found. -This way your Part-DB parts automatically get datasheet links, prices, parameters and more, with just a few clicks. +Part-DB can create parts based on information from external sources: For example, with the right setup you can just +search for a part number +and Part-DB will query selected distributors and manufacturers for the part and create a part with the information it +found. +This way your Part-DB parts automatically get datasheet links, prices, parameters, and more, with just a few clicks. ## Usage -Before you can use the information provider system, you have to configure at least one information provider, which act as data source. +Before you can use the information provider system, you have to configure at least one information provider, which act +as data source. See below for a list of available information providers and available configuration options. -For many providers it is enough, to setup the API keys in the env configuration, some require an additional OAuth connection. -You can list all enabled information providers in the browser at `https://your-partdb-instance.tld/tools/info_providers/providers` (you need the right permission for it, see below). +For many providers it is enough, to set up the API keys in the env configuration, some require an additional OAuth +connection. +You can list all enabled information providers in the browser +at `https://your-partdb-instance.tld/tools/info_providers/providers` (you need the right permission for it, see below). -To use the information provider system, your user need to have the right permissions. Go to the permission management page of +To use the information provider system, your user need to have the right permissions. Go to the permission management +page of a user or a group and assign the permissions of the "Info providers" group in the "Miscellaneous" tab. -If you have the required permission you will find in the sidebar in the "Tools" section the entry "Create part from info provider". -Click this and you will land on a search page. Enter the part number you want to search for and select the information providers you want to use. +If you have the required permission you will find in the sidebar in the "Tools" section the entry "Create part from info +provider". +Click this and you will land on a search page. Enter the part number you want to search for and select the information +providers you want to use. -After you click Search, you will be presented with the results and can select the result that fits best. -With a click on the blue plus button, you will be redirected to the part creation page with the information already filled in. +After you click Search, you will be presented with the results and can select the result that fits best. +With a click on the blue plus button, you will be redirected to the part creation page with the information already +filled in. ![image]({% link assets/usage/information_provider_system/animation.gif %}) +If you want to update an existing part, go to the parts info page and click on the "Update from info provider" button in +the tools tab. You will be redirected to a search page, where you can search the info providers to automatically update this +part. + ## Alternative names -Part-DB tries to automatically find existing elements from your database for the information it got from the providers for fields like manufacturer, footprint, etc. -For this it searches for a element with the same name (case-insensitive) as the information it got from the provider. So e.g. if the provider returns "EXAMPLE CORP" as manufacturer, +Part-DB tries to automatically find existing elements from your database for the information it got from the providers +for fields like manufacturer, footprint, etc. +For this, it searches for an element with the same name (case-insensitive) as the information it got from the provider. So +e.g. if the provider returns "EXAMPLE CORP" as the manufacturer, Part-DB will automatically select the element with the name "Example Corp" from your database. -As the names of these fields differ from provider to provider (and maybe not even normalized for the same provider), you +As the names of these fields differ from provider to provider (and maybe not even normalized for the same provider), you can define multiple alternative names for an element (on their editing page). -For example if define a manufacturer "Example Corp" with the alternative names "Example Corp.", "Example Corp", "Example Corp. Inc." and "Example Corporation", +For example, if you define a manufacturer "Example Corp" with the alternative names "Example Corp.", "Example Corp", "Example +Corp. Inc." and "Example Corporation", then the provider can return any of these names and Part-DB will still automatically select the right element. -If Part-DB finds no matching element, it will automatically create a new one, when you do not change the value before saving. +If Part-DB finds no matching element, it will automatically create a new one, when you do not change the value before +saving. ## Attachment types The information provider system uses attachment types to differentiate between datasheets and image attachments. -For this it will create a "Datasheet" and "Image" attachment type on the first run. You can change the names of these +For this it will create a "Datasheet" and "Image" attachment type on the first run. You can change the names of these types in the attachment type settings (as long as you keep the "Datasheet"/"Image" in the alternative names field). -If you already have attachment types for images and datasheets and want the information provider system to use them, you can +If you already have attachment types for images and datasheets and want the information provider system to use them, you +can add the alternative names "Datasheet" and "Image" to the alternative names field of the attachment types. ## Data providers The system tries to be as flexible as possible, so many different information sources can be used. Each information source is called am "info provider" and handles the communication with the external source. -The providers are just a driver which handles the communication with the different external sources and converts them into a common format Part-DB understands. +The providers are just a driver that handles the communication with the different external sources and converts them +into a common format Part-DB understands. That way it is pretty easy to create new providers as they just need to do very little work. -Normally the providers utilize an API of a service, and you need to create a account at the provider and get an API key. -Also there are limits on how many requests you can do per day or months, depending on the provider and your contract with them. +Normally the providers utilize an API of a service, and you need to create an account at the provider and get an API key. +Also, there are limits on how many requests you can do per day or month, depending on the provider and your contract +with them. The following providers are currently available and shipped with Part-DB: (All trademarks are property of their respective owners. Part-DB is not affiliated with any of the companies.) -### Ocotpart -The Octopart provider uses the [Octopart / Nexar API](https://nexar.com/api) to search for parts and getting informations. -To use it you have to create an account at Nexar and create a new application on the [Nexar Portal](https://portal.nexar.com/). -The name does not matter, but it is important that the application has access to the "Supply" scope. -In the Authorization tab, you will find the client ID and client secret, which you have to enter in the Part-DB env configuration (see below). +### Octopart -Please note that the Nexar API in the free plan is limited to 1000 results per month. -That means if you search for a keyword and results in 10 parts, then 10 will be substracted from your monthly limit. You can see your current usage on the Nexar portal. -Part-DB caches the search results internally, so if you have searched for a part before, it will not count against your monthly limit again, when you create it from the search results. +The Octopart provider uses the [Octopart / Nexar API](https://nexar.com/api) to search for parts and get information. +To use it you have to create an account at Nexar and create a new application on +the [Nexar Portal](https://portal.nexar.com/). +The name does not matter, but it is important that the application has access to the "Supply" scope. +In the Authorization tab, you will find the client ID and client secret, which you have to put in the Part-DB env +configuration (see below). -Following env configuration options are available: +Please note that the Nexar API in the free plan is limited to 1000 results per month. +That means if you search for a keyword and results in 10 parts, then 10 will be subtracted from your monthly limit. You +can see your current usage on the Nexar portal. +Part-DB caches the search results internally, so if you have searched for a part before, it will not count against your +monthly limit again, when you create it from the search results. + +The following env configuration options are available: * `PROVIDER_OCTOPART_CLIENT_ID`: The client ID you got from Nexar (mandatory) -* `PROVIDER_OCTOPART_CLIENT_SECRET`: The client secret you got from Nexar (mandatory) -* `PROVIDER_OCTOPART_CURRENCY`: The currency you want to get prices in if available (optional, 3 letter ISO-code, default: `EUR`). If an offer is only available in a certain currency, -Part-DB will save the prices in their native currency, and you can use Part-DB currency conversion feature to convert it to your preferred currency. -* `PROVIDER_OCOTPART_COUNTRY`: The country you want to get prices in if available (optional, 2 letter ISO-code, default: `DE`). To get correct prices, you have to set this and the currency setting to the correct value. -* `PROVIDER_OCTOPART_SEARCH_LIMIT`: The maximum number of results to return per search (optional, default: `10`). This affects how quickly your monthly limit is used up. -* `PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS`: If set to `true`, only offers from [authorized sellers](https://octopart.com/authorized) will be returned (optional, default: `false`). +* `PROVIDER_OCTOPART_SECRET`: The client secret you got from Nexar (mandatory) +* `PROVIDER_OCTOPART_CURRENCY`: The currency you want to get prices in if available (optional, 3 letter ISO-code, + default: `EUR`). If an offer is only available in a certain currency, + Part-DB will save the prices in their native currency, and you can use Part-DB currency conversion feature to convert + it to your preferred currency. +* `PROVIDER_OCTOPART_COUNTRY`: The country you want to get prices in if available (optional, 2 letter ISO-code, + default: `DE`). To get the correct prices, you have to set this and the currency setting to the correct value. +* `PROVIDER_OCTOPART_SEARCH_LIMIT`: The maximum number of results to return per search (optional, default: `10`). This + affects how quickly your monthly limit is used up. +* `PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS`: If set to `true`, only offers + from [authorized sellers](https://octopart.com/authorized) will be returned (optional, default: `false`). + +**Attention**: If you change the Octopart clientID after you have already used the provider, you have to remove the +OAuth token in the Part-DB database. Remove the entry in the table `oauth_tokens` with the name `ip_octopart_oauth`. ### Digi-Key -The Digi-Key provider uses the [Digi-Key API](https://developer.digikey.com/) to search for parts and getting shopping information from [Digi-Key](https://www.digikey.com/). -To use it you have to create an account at Digi-Key and get an API key on the [Digi-Key API page](https://developer.digikey.com/). -You must create an organization there and create a "Production app". Most settings are not important, you just have to grant access to the "Product Information" API. -You will get an Client ID and a Client Secret, which you have to enter in the Part-DB env configuration (see below). -Following env configuration options are available: +The Digi-Key provider uses the [Digi-Key API](https://developer.digikey.com/) to search for parts and get shopping +information from [Digi-Key](https://www.digikey.com/). +To use it you have to create an account at Digi-Key and get an API key on +the [Digi-Key API page](https://developer.digikey.com/). +You must create an organization there and create a "Production app". Most settings are not important, you just have to +grant access to the "Product Information" API. +You will get a Client ID and a Client Secret, which you have to put in the Part-DB env configuration (see below). + +The following env configuration options are available: + * `PROVIDER_DIGIKEY_CLIENT_ID`: The client ID you got from Digi-Key (mandatory) -* `PROVIDER_DIGIKEY_CLIENT_SECRET`: The client secret you got from Digi-Key (mandatory) +* `PROVIDER_DIGIKEY_SECRET`: The client secret you got from Digi-Key (mandatory) * `PROVIDER_DIGIKEY_CURRENCY`: The currency you want to get prices in (optional, default: `EUR`) * `PROVIDER_DIGIKEY_LANGUAGE`: The language you want to get the descriptions in (optional, default: `en`) * `PROVIDER_DIGIKEY_COUNTRY`: The country you want to get the prices for (optional, default: `DE`) -The Digi-Key provider needs an additional OAuth connection. To do this, go to the information provider list (`https://your-partdb-instance.tld/tools/info_providers/providers`), -go the Digi-Key provider (in the disabled page) and click on the "Connect OAuth" button. You will be redirected to Digi-Key, where you have to login and grant access to the app. +The Digi-Key provider needs an additional OAuth connection. To do this, go to the information provider +list (`https://your-partdb-instance.tld/tools/info_providers/providers`), +go to Digi-Key provider (in the disabled page), and click on the "Connect OAuth" button. You will be redirected to +Digi-Key, where you have to log in and grant access to the app. To do this your user needs the "Manage OAuth tokens" permission from the "System" section in the "System" tab. -The OAuth connection should only be needed once, but if you have any problems with the provider, just click the button again, to establish a new connection. +The OAuth connection should only be needed once, but if you have any problems with the provider, just click the button +again, to establish a new connection. ### TME -The TME provider use the API of [TME](https://www.tme.eu/) to search for parts and getting shopping information from them. -To use it you have to create an account at TME and get an API key on the [TME API page](https://developers.tme.eu/en/). -You have to generate a new anonymous key there and enter the key and secret in the Part-DB env configuration (see below). -Following env configuration options are available: -* `PROVIDER_TME_API_KEY`: The API key you got from TME (mandatory) -* `PROVIDER_TME_API_SECRET`: The API secret you got from TME (mandatory) +The TME provider uses the API of [TME](https://www.tme.eu/) to search for parts and getting shopping information from +them. +To use it you have to create an account at TME and get an API key on the [TME API page](https://developers.tme.eu/en/). +You have to generate a new anonymous key there and enter the key and secret in the Part-DB env configuration (see +below). + +The following env configuration options are available: + +* `PROVIDER_TME_KEY`: The API key you got from TME (mandatory) +* `PROVIDER_TME_SECRET`: The API secret you got from TME (mandatory) * `PROVIDER_TME_CURRENCY`: The currency you want to get prices in (optional, default: `EUR`) -* `PROVIDER_TME_LANGUAGE`: The language you want to get the descriptions in (`en`, `de` and `pl`) (optional, default: `en`) +* `PROVIDER_TME_LANGUAGE`: The language you want to get the descriptions in (`en`, `de` and `pl`) (optional, + default: `en`) * `PROVIDER_TME_COUNTRY`: The country you want to get the prices for (optional, default: `DE`) -* `PROVIDER_TME_GET_GROSS_PRICES`: If this is set to `1` the prices will be gross prices (including tax), otherwise net prices (optional, default: `0`) +* `PROVIDER_TME_GET_GROSS_PRICES`: If this is set to `1` the prices will be gross prices (including tax), otherwise net + prices (optional, default: `0`) ### Farnell / Element14 / Newark -The Farnell provider uses the [Farnell API](https://partner.element14.com/) to search for parts and getting shopping information from [Farnell](https://www.farnell.com/). -You have to create an account at Farnell and get an API key on the [Farnell API page](https://partner.element14.com/). -Register a new application there (settings does not matter, as long as you select the "Product Search API") and you will get an API key. + +The Farnell provider uses the [Farnell API](https://partner.element14.com/) to search for parts and getting shopping +information from [Farnell](https://www.farnell.com/). +You have to create an account at Farnell and get an API key on the [Farnell API page](https://partner.element14.com/). +Register a new application there (settings does not matter, as long as you select the "Product Search API") and you will +get an API key. + +The following env configuration options are available: + +* `PROVIDER_ELEMENT14_KEY`: The API key you got from Farnell (mandatory) +* `PROVIDER_ELEMENT14_STORE_ID`: The store ID you want to use. This decides the language of results, currency and + country of prices (optional, default: `de.farnell.com`, + see [here](https://partner.element14.com/docs/Product_Search_API_REST__Description) for available values) + +### Mouser + +The Mouser provider uses the [Mouser API](https://www.mouser.de/api-home/) to search for parts and getting shopping +information from [Mouser](https://www.mouser.com/). +You have to create an account at Mouser and register for an API key for the Search API on +the [Mouser API page](https://www.mouser.de/api-home/). +You will receive an API token, which you have to put in the Part-DB env configuration (see below): +At the registration you choose a country, language, and currency in which you want to get the results. + +*Attention*: Currently (January 2024) the mouser API seems to be somewhat broken, in the way that it does not return any +information about datasheets and part specifications. Therefore Part-DB can not retrieve them, even if they are shown +at the mouser page. See [issue #503](https://github.com/Part-DB/Part-DB-server/issues/503) for more info. Following env configuration options are available: -* `PROVIDER_ELEMENT14_KEY`: The API key you got from Farnell (mandatory) -* `PROVIDER_ELEMENT14_STORE_ID`: The store ID you want to use. This decides the language of results, currency and country of prices (optional, default: `de.farnell.com`, see [here](https://partner.element14.com/docs/Product_Search_API_REST__Description) for availailable values) +* `PROVIDER_MOUSER_KEY`: The API key you got from Mouser (mandatory) +* `PROVIDER_MOUSER_SEARCH_LIMIT`: The maximum number of results to return per search (maximum 50) +* `PROVIDER_MOUSER_SEARCH_OPTION`: You can choose an option here to restrict the search results to RoHs compliant and + available parts. Possible values are `None`, `Rohs`, `InStock`, `RohsAndInStock`. +* `PROVIDER_MOUSER_SEARCH_WITH_SIGNUP_LANGUAGE`: A bit of an obscure option. The original description of Mouser is: Used + when searching for keywords in the language specified when you signed up for Search API. + +### LCSC + +[LCSC](https://www.lcsc.com/) is a Chinese distributor of electronic parts. It does not offer a public API, but the LCSC +webshop uses an internal JSON based API to render the page. Part-DB can use this inofficial API to get part information +from LCSC. + +**Please note, that the use of this internal API is not intended or endorsed by LCS and it could break at any time. So use it at your own risk.** + +An API key is not required, it is enough to enable the provider using the following env configuration options: + +* `PROVIDER_LCSC_ENABLED`: Set this to `1` to enable the LCSC provider +* `PROVIDER_LCSC_CURRENCY`: The currency you want to get prices in (see LCSC webshop for available currencies, default: `EUR`) + +### OEMsecrets + +The oemsecrets provider uses the [oemsecrets API](https://www.oemsecrets.com/) to search for parts and getting shopping +information from them. Similar to octopart it aggregates offers from different distributors. + +You can apply for a free API key on the [oemsecrets API page](https://www.oemsecrets.com/api/) and put the key you get +in the Part-DB env configuration (see below). + +The following env configuration options are available: + +* `PROVIDER_OEMSECRETS_KEY`: The API key you got from oemsecrets (mandatory) +* `PROVIDER_OEMSECRETS_COUNTRY_CODE`: The two-letter code of the country you want to get the prices for +* `PROVIDER_OEMSECRETS_CURRENCY`: The currency you want to get prices in (optional, default: `EUR`) +* `PROVIDER_OEMSECRETS_ZERO_PRICE`: If set to `1`, parts with a price of 0 will be included in the search results, otherwise + they will be excluded (optional, default: `0`) +* `PROVIDER_OEMSECRETS_SET_PARAM`: If set to `1`, the provider will try to extract parameters from the part description +* `PROVIDER_OEMSECRETS_SORT_CRITERIA`: The criteria to sort the search results by. If set to 'C', it further sorts by +completeness (prioritizing items with the most detailed information). If set to 'M', it further sorts by manufacturer name. +If set to any other value, no sorting is performed. + +### Reichelt + +The reichelt provider uses webscraping from [reichelt.com](https://reichelt.com/) to get part information. +This is not an official API and could break at any time. So use it at your own risk. + +The following env configuration options are available: +* `PROVIDER_REICHELT_ENABLED`: Set this to `1` to enable the Reichelt provider +* `PROVIDER_REICHELT_CURRENCY`: The currency you want to get prices in. Only possible for countries which use Non-EUR (optional, default: `EUR`) +* `PROVIDER_REICHELT_COUNTRY`: The country you want to get the prices for (optional, default: `DE`) +* `PROVIDER_REICHELT_LANGUAGE`: The language you want to get the descriptions in (optional, default: `en`) +* `PROVIDER_REICHELT_INCLUDE_VAT`: If set to `1`, the prices will be gross prices (including tax), otherwise net prices (optional, default: `1`) + +### Pollin + +The pollin provider uses webscraping from [pollin.de](https://www.pollin.de/) to get part information. +This is not an official API and could break at any time. So use it at your own risk. + +The following env configuration options are available: +* `PROVIDER_POLLIN_ENABLED`: Set this to `1` to enable the Pollin provider ### Custom provider -To create a custom provider, you have to create a new class implementing the `InfoProviderInterface` interface. As long as it is a valid Symfony service, it will be automatically loaded and can be used. -Besides some metadata functions, you have to implement the `searchByKeyword()` and `getDetails()` functions, which do the actual API requests and return the information to Part-DB. + +To create a custom provider, you have to create a new class implementing the `InfoProviderInterface` interface. As long +as it is a valid Symfony service, it will be automatically loaded and can be used. +Besides some metadata functions, you have to implement the `searchByKeyword()` and `getDetails()` functions, which do +the actual API requests and return the information to Part-DB. See the existing providers for examples. If you created a new provider, feel free to create a pull request to add it to the Part-DB core. ## Result caching + To reduce the number of API calls against the providers, the results are cached: + * The search results (exact search term) are cached for 7 days * The product details are cached for 4 days -If you need a fresh result, you can clear the cache by running `php .\bin\console cache:pool:clear info_provider.cache` on the command line. -The default `php bin/console cache:clear` also clears the result cache, as it clears all caches. \ No newline at end of file +If you need a fresh result, you can clear the cache by running `php .\bin\console cache:pool:clear info_provider.cache` +on the command line. +The default `php bin/console cache:clear` also clears the result cache, as it clears all caches. diff --git a/docs/usage/keybindings.md b/docs/usage/keybindings.md index f3224b89..771d7684 100644 --- a/docs/usage/keybindings.md +++ b/docs/usage/keybindings.md @@ -9,104 +9,107 @@ parent: Usage This page lists all the keybindings of Part-DB. Currently, there are only the special character keybindings. ## Special characters -Using the keybindings below (Alt + key) you can insert special characters into the text fields of Part-DB. This works on all text and search fields in Part-DB. + +Using the keybindings below (Alt + key) you can insert special characters into the text fields of Part-DB. This works on +all text and search fields in Part-DB. ### Greek letters -| Key | Character | -|---------------------|---------------------| -| **Alt + a** | α (Alpha) | -| **Alt + Shift + A** | Α (Alpha uppercase) | -| **Alt + b** | β (Beta) | -| **Alt + Shift + B** | Β (Beta uppercase) | -| **Alt + g** | γ (Gamma) | -| **Alt + Shift + G** | Γ (Gamma uppercase) | -| **Alt + d** | δ (Delta) | -| **Alt + Shift + D** | Δ (Delta uppercase) | -| **Alt + e** | ε (Epsilon) | +| Key | Character | +|---------------------|-----------------------| +| **Alt + a** | α (Alpha) | +| **Alt + Shift + A** | Α (Alpha uppercase) | +| **Alt + b** | β (Beta) | +| **Alt + Shift + B** | Β (Beta uppercase) | +| **Alt + g** | γ (Gamma) | +| **Alt + Shift + G** | Γ (Gamma uppercase) | +| **Alt + d** | δ (Delta) | +| **Alt + Shift + D** | Δ (Delta uppercase) | +| **Alt + e** | ε (Epsilon) | | **Alt + Shift + E** | Ε (Epsilon uppercase) | -| **Alt + z** | ζ (Zeta) | -| **Alt + Shift + Z** | Ζ (Zeta uppercase) | -| **Alt + h** | η (Eta) | -| **Alt + Shift + H** | Η (Eta uppercase) | -| **Alt + q** | θ (Theta) | -| **Alt + Shift + Q** | Θ (Theta uppercase) | -| **Alt + i** | ι (Iota) | -| **Alt + Shift + I** | Ι (Iota uppercase) | -| **Alt + k** | κ (Kappa) | -| **Alt + Shift + K** | Κ (Kappa uppercase) | -| **Alt + l** | λ (Lambda) | -| **Alt + Shift + L** | Λ (Lambda uppercase) | -| **Alt + m** | μ (Mu) | -| **Alt + Shift + M** | Μ (Mu uppercase) | -| **Alt + n** | ν (Nu) | -| **Alt + Shift + N** | Ν (Nu uppercase) | -| **Alt + x** | ξ (Xi) | -| **Alt + Shift + x** | Ξ (Xi uppercase) | -| **Alt + o** | ο (Omicron) | +| **Alt + z** | ζ (Zeta) | +| **Alt + Shift + Z** | Ζ (Zeta uppercase) | +| **Alt + h** | η (Eta) | +| **Alt + Shift + H** | Η (Eta uppercase) | +| **Alt + q** | θ (Theta) | +| **Alt + Shift + Q** | Θ (Theta uppercase) | +| **Alt + i** | ι (Iota) | +| **Alt + Shift + I** | Ι (Iota uppercase) | +| **Alt + k** | κ (Kappa) | +| **Alt + Shift + K** | Κ (Kappa uppercase) | +| **Alt + l** | λ (Lambda) | +| **Alt + Shift + L** | Λ (Lambda uppercase) | +| **Alt + m** | μ (Mu) | +| **Alt + Shift + M** | Μ (Mu uppercase) | +| **Alt + n** | ν (Nu) | +| **Alt + Shift + N** | Ν (Nu uppercase) | +| **Alt + x** | ξ (Xi) | +| **Alt + Shift + x** | Ξ (Xi uppercase) | +| **Alt + o** | ο (Omicron) | | **Alt + Shift + O** | Ο (Omicron uppercase) | -| **Alt + p** | π (Pi) | -| **Alt + Shift + P** | Π (Pi uppercase) | -| **Alt + r** | ρ (Rho) | -| **Alt + Shift + R** | Ρ (Rho uppercase) | -| **Alt + s** | σ (Sigma) | -| **Alt + Shift + S** | Σ (Sigma uppercase) | -| **Alt + t** | τ (Tau) | -| **Alt + Shift + T** | Τ (Tau uppercase) | -| **Alt + u** | υ (Upsilon) | +| **Alt + p** | π (Pi) | +| **Alt + Shift + P** | Π (Pi uppercase) | +| **Alt + r** | ρ (Rho) | +| **Alt + Shift + R** | Ρ (Rho uppercase) | +| **Alt + s** | σ (Sigma) | +| **Alt + Shift + S** | Σ (Sigma uppercase) | +| **Alt + t** | τ (Tau) | +| **Alt + Shift + T** | Τ (Tau uppercase) | +| **Alt + u** | υ (Upsilon) | | **Alt + Shift + U** | Υ (Upsilon uppercase) | -| **Alt + f** | φ (Phi) | -| **Alt + Shift + F** | Φ (Phi uppercase) | -| **Alt + y** | ψ (Psi) | -| **Alt + Shift + Y** | Ψ (Psi uppercase) | -| **Alt + c** | χ (Chi) | -| **Alt + Shift + C** | Χ (Chi uppercase) | -| **Alt + w** | ω (Omega) | -| **Alt + Shift + W** | Ω (Omega uppercase) | +| **Alt + f** | φ (Phi) | +| **Alt + Shift + F** | Φ (Phi uppercase) | +| **Alt + y** | ψ (Psi) | +| **Alt + Shift + Y** | Ψ (Psi uppercase) | +| **Alt + c** | χ (Chi) | +| **Alt + Shift + C** | Χ (Chi uppercase) | +| **Alt + w** | ω (Omega) | +| **Alt + Shift + W** | Ω (Omega uppercase) | ### Mathematical symbols -| Key | Character | -|----------------------|-------------------------------------------| -| **Alt + 1** | ∑ (Sum symbol) | -| **Alt + Shift + 1** | ∏ (Product symbol) | -| **Alt + 2** | ∫ (Integral symbol) | -| **Alt + Shift + 2** | ∂ (Partial derivation) | -| **Alt + 3** | ≤ (Less or equal symbol) | -| **Alt + Shift + 3** | ≥ (Greater or equal symbol) | -| **Alt + 4** | ∞ (Infinity symbol) | -| **Alt + Shift + 4** | ∅ (Empty set symbol) | -| **Alt + 5** | ≈ (Approximatley) | -| **Alt + Shift + 5** | ≠ (Not equal symbol) | -| **Alt + 6** | ∈ (Element of) | -| **Alt + Shift + 6** | ∉ (Not element of) | -| **Alt + 7** | ∨ (Logical or) | -| **Alt + Shift + 7** | ∧ (Logical and) | -| **Alt + 8** | ∠ (Angle symbol) | -| **Alt + Shift + 8** | ∝ (Proportional to) | -| **Alt + 9** | √ (Square root) | -| **Alt + Shift + 9** | ∛ (Cube root) | -| **Alt + 0** | ± (Plus minus) | -| **Alt + Shift + 0** | ∓ (Minus plus) | +| Key | Character | +|---------------------|-----------------------------| +| **Alt + 1** | ∑ (Sum symbol) | +| **Alt + Shift + 1** | ∏ (Product symbol) | +| **Alt + 2** | ∫ (Integral symbol) | +| **Alt + Shift + 2** | ∂ (Partial derivation) | +| **Alt + 3** | ≤ (Less or equal symbol) | +| **Alt + Shift + 3** | ≥ (Greater or equal symbol) | +| **Alt + 4** | ∞ (Infinity symbol) | +| **Alt + Shift + 4** | ∅ (Empty set symbol) | +| **Alt + 5** | ≈ (Approximately) | +| **Alt + Shift + 5** | ≠ (Not equal symbol) | +| **Alt + 6** | ∈ (Element of) | +| **Alt + Shift + 6** | ∉ (Not element of) | +| **Alt + 7** | ∨ (Logical or) | +| **Alt + Shift + 7** | ∧ (Logical and) | +| **Alt + 8** | ∠ (Angle symbol) | +| **Alt + Shift + 8** | ∝ (Proportional to) | +| **Alt + 9** | √ (Square root) | +| **Alt + Shift + 9** | ∛ (Cube root) | +| **Alt + 0** | ± (Plus minus) | +| **Alt + Shift + 0** | ∓ (Minus plus) | ### Currency symbols -Please not the following keybindings are bound to a specific keycode. The key character is not the same on all keyboards. +Please note, the following keybindings are bound to a specific keycode. The key character is not the same on all +keyboards. It is given here for a US keyboard layout. For a German keyboard layout, replace ; with ö, and ' with ä. -| Key | Character | -|---------------------------------|---------------------------| -| **Alt + ;** (code 192) | € (Euro currency symbol) | -| **Alt + Shift + ;** (code 192) | £ (Pound currency symbol) | -| **Alt + '** (code 222) | ¥ (Yen currency symbol) | +| Key | Character | +|---------------------------------|----------------------------| +| **Alt + ;** (code 192) | € (Euro currency symbol) | +| **Alt + Shift + ;** (code 192) | £ (Pound currency symbol) | +| **Alt + '** (code 222) | ¥ (Yen currency symbol) | | **Alt + Shift + '** (code 222) | $ (Dollar currency symbol) | - ### Others -Please not the following keybindings are bound to a specific keycode. The key character is not the same on all keyboards. +Please note the following keybindings are bound to a specific keycode. The key character is not the same on all +keyboards. It is given here for a US keyboard layout. For a German keyboard layout, replace `[` with `0`, and `]` with `´`. @@ -114,6 +117,6 @@ For a German keyboard layout, replace `[` with `0`, and `]` with `´`. | Key | Character | |--------------------------------|--------------------| | **Alt + [** (code 219) | © (Copyright char) | -| **Alt + Shift + [** (code 219) | (Registered char) | +| **Alt + Shift + [** (code 219) | ® (Registered char) | | **Alt + ]** (code 221) | ™ (Trademark char) | -| **Alt + Shift + ]** (code 221) | (Degree char) | +| **Alt + Shift + ]** (code 221) | ° (Degree char) | diff --git a/docs/usage/labels.md b/docs/usage/labels.md index 35c6d317..e84f4d7f 100644 --- a/docs/usage/labels.md +++ b/docs/usage/labels.md @@ -6,103 +6,268 @@ parent: Usage # Labels -Part-DB support the generation and printing of labels for parts, part lots and storelocation. -You can use the "Tools -> Labelgenerator" menu entry to create labels, or click the label generation link on the part. +Part-DB support the generation and printing of labels for parts, part lots and storage locations. +You can use the "Tools -> Label generator" menu entry to create labels or click the label generation link on the part. -You can define label templates by creating Label profiles. This way you can create many similar looking labels with for +You can define label templates by creating Label profiles. This way you can create many similar-looking labels with for many parts. -The content of the labels is defined by the templates content field. You can use the WYSIWYG editor to create and style the content (or write HTML code). +The content of the labels is defined by the template's content field. You can use the WYSIWYG editor to create and style +the content (or write HTML code). Using the "Label placeholder" menu in the editor, you can insert placeholders for the data of the parts. It will be replaced by the concrete data when the label is generated. - + ## Label placeholders + A placeholder has the format `[[PLACEHOLDER]]` and will be filled with the concrete data by Part-DB. -You can use the "Placeholders" dropdown in content editor, to automatically insert the placeholders. +You can use the "Placeholders" dropdown in the content editor, to automatically insert the placeholders. ### Common -| Placeholder | Description | Example | -|---|---|---| -| `[[USERNAME]]` | The user name of the currently logged in user | admin | -| `[[USERNAME_FULL]]` | The full name of the current user | John Doe (@admin) | -| `[[DATETIME]]` | The current date and time in the selected locale | 31.12.2017, 18:34:11 | -| `[[DATE]]` | The current date in the selected locale | 31.12.2017 | -| `[[TIME]]` | The current time in the selected locale | 18:34:11 | -| `[[INSTALL_NAME]]` | The name of the current installation (see $config['partdb_title']) | Part-DB | -| `[[INSTANCE_URL]]` | The URL of the current installation | https://demo.part-db.de | +| Placeholder | Description | Example | +|---------------------|--------------------------------------------------------------------|-------------------------| +| `[[USERNAME]]` | The user name of the currently logged in user | admin | +| `[[USERNAME_FULL]]` | The full name of the current user | John Doe (@admin) | +| `[[DATETIME]]` | The current date and time in the selected locale | 31.12.2017, 18:34:11 | +| `[[DATE]]` | The current date in the selected locale | 31.12.2017 | +| `[[TIME]]` | The current time in the selected locale | 18:34:11 | +| `[[INSTALL_NAME]]` | The name of the current installation (see $config['partdb_title']) | Part-DB | +| `[[INSTANCE_URL]]` | The URL of the current installation | https://demo.part-db.de | ### Parts -| Placeholder | Description | Example | -|---|---|---| -| `[[ID]]` | The internal ID of the part | 24 | -| `[[NAME]]` | The name of the part | ATMega328 | -| `[[CATEGORY]]` | The name of the category (without path) | AVRs | -| `[[CATEGORY_FULL]]` | The full path of the category | Aktiv->MCUs->AVRs | -| `[[MANUFACTURER]]` | The name of the manufacturer | Atmel | -| `[[MANUFACTURER_FULL]]` | The full path of the manufacturer | Halbleiterhersteller->Atmel | -| `[[FOOTPRINT]]` | The name of the footprint (without path) | DIP-32 | -| `[[FOOTPRINT_FULL]]` | The full path of the footprint | Bedrahtet->DIP->DIP-32 | -| `[[MASS]]` | The mass of the part | 123.4 g | -| `[[MPN]]` | The manufacturer product number | BC547ACT | -| `[[TAGS]]` | The tags of the part | SMD, Tag1 | -| `[[M_STATUS]]` | The manufacturing status of the part | Active | -| `[[DESCRIPTION]]` | The rich text description of the part | *NPN* | -| `[[DESCRIPTION_T]]` | The description as plain text | NPN | -| `[[COMMENT]]` | The rich text comment of the part | | -| `[[COMMENT_T]]` | The comment as plain text | | -| `[[LAST_MODIFIED]]` | The datetime when the element was last modified | 2/26/16, 5:38 PM | -| `[[CREATION_DATE]]` | The datetime when the element was created | 2/26/16, 5:38 PM | +| Placeholder | Description | Example | +|-------------------------|-------------------------------------------------|-----------------------------| +| `[[ID]]` | The internal ID of the part | 24 | +| `[[NAME]]` | The name of the part | ATMega328 | +| `[[CATEGORY]]` | The name of the category (without path) | AVRs | +| `[[CATEGORY_FULL]]` | The full path of the category | Aktiv->MCUs->AVRs | +| `[[MANUFACTURER]]` | The name of the manufacturer | Atmel | +| `[[MANUFACTURER_FULL]]` | The full path of the manufacturer | Halbleiterhersteller->Atmel | +| `[[FOOTPRINT]]` | The name of the footprint (without path) | DIP-32 | +| `[[FOOTPRINT_FULL]]` | The full path of the footprint | Bedrahtet->DIP->DIP-32 | +| `[[MASS]]` | The mass of the part | 123.4 g | +| `[[MPN]]` | The manufacturer product number | BC547ACT | +| `[[TAGS]]` | The tags of the part | SMD, Tag1 | +| `[[M_STATUS]]` | The manufacturing status of the part | Active | +| `[[DESCRIPTION]]` | The rich text description of the part | *NPN* | +| `[[DESCRIPTION_T]]` | The description as plain text | NPN | +| `[[COMMENT]]` | The rich text comment of the part | | +| `[[COMMENT_T]]` | The comment as plain text | | +| `[[LAST_MODIFIED]]` | The datetime when the element was last modified | 2/26/16, 5:38 PM | +| `[[CREATION_DATE]]` | The datetime when the element was created | 2/26/16, 5:38 PM | ### Part lot -| Placeholder | Description | Example | -|---|---|---| -| `[[LOT_ID]]` | Part lot ID | 123 | -| `[[LOT_NAME]]` | Part lot name | | -| `[[LOT_COMMENT]]` | Part lot comment | | -| `[[EXPIRATION_DATE]]` | Expiration date of the part lot | | -| `[[AMOUNT]]` | The amount of parts in this lot | 12 | -| `[[LOCATION]]` | The storage location of this part lot | Location A | -| `[[LOCATION_FULL]]` | The full path of the storage location | Location -> Location A | +| Placeholder | Description | Example | +|-----------------------|---------------------------------------|------------------------| +| `[[LOT_ID]]` | Part lot ID | 123 | +| `[[LOT_NAME]]` | Part lot name | | +| `[[LOT_COMMENT]]` | Part lot comment | | +| `[[EXPIRATION_DATE]]` | Expiration date of the part lot | | +| `[[AMOUNT]]` | The amount of parts in this lot | 12 | +| `[[LOCATION]]` | The storage location of this part lot | Location A | +| `[[LOCATION_FULL]]` | The full path of the storage location | Location -> Location A | ### Storelocation -| Placeholder | Description | Example | -|---|---|---| -| `[[ID]]` | ID of the storage location | | -| `[[NAME]]` | Name of the storage location | Location A | -| `[[FULL_PATH]]` | The full path of the storage location | Location -> Location A | -| `[[PARENT]]` | The name of the parent location | Location | -| `[[PARENT_FULL_PATH]]` | The full path of the storage location | | -| `[[COMMENT]]` | The comment of the storage location | | -| `[[COMMENT_T]]` | The plain text version of the comment | -| `[[LAST_MODIFIED]]` | The datetime when the element was last modified | 2/26/16, 5:38 PM | -| `[[CREATION_DATE]]` | The datetime when the element was created | 2/26/16, 5:38 PM | +| Placeholder | Description | Example | +|------------------------|-------------------------------------------------|------------------------| +| `[[ID]]` | ID of the storage location | | +| `[[NAME]]` | Name of the storage location | Location A | +| `[[FULL_PATH]]` | The full path of the storage location | Location -> Location A | +| `[[PARENT]]` | The name of the parent location | Location | +| `[[PARENT_FULL_PATH]]` | The full path of the storage location | | +| `[[COMMENT]]` | The comment of the storage location | | +| `[[COMMENT_T]]` | The plain text version of the comment | +| `[[LAST_MODIFIED]]` | The datetime when the element was last modified | 2/26/16, 5:38 PM | +| `[[CREATION_DATE]]` | The datetime when the element was created | 2/26/16, 5:38 PM | ## Twig mode -If you select "Twig" in parser mode under advanced settings, you can input a twig template in the lines field (activate source mode). You can use most of the twig tags and filters listed in [offical documentation](https://twig.symfony.com/doc/3.x/). +If you select "Twig" in parser mode under advanced settings, you can input a twig template in the lines field (activate +source mode). You can use most of the twig tags and filters listed +in [official documentation](https://twig.symfony.com/doc/3.x/). -The following variables are in injected into Twig and can be accessed using `{% raw %}{{ variable }}` (or `{% raw %}{{ variable.property }}{% endraw %}`): +Twig allows you for much more complex and dynamic label generation. You can use loops, conditions, and functions to create +the label content and you can access almost all data Part-DB offers. The label templates are evaluated in a special sandboxed environment, +where only certain operations are allowed. Only read access to entities is allowed. However as it circumvents Part-DB normal permission system, +the twig mode is only available to users with the "Twig mode" permission. -| Variable name | Description | -|--------------------------------------| ----------- | -| `{% raw %}{{ element }}{% endraw %}` | The target element, selected in label dialog | -| `{% raw %}{{ user }}{% endraw %}` | The current logged in user. Null if you are not logged in | -| `{% raw %}{{ install_title }}{% endraw %}` | The name of the current Part-DB instance (similar to [[INSTALL_NAME]] placeholder). | -| `{% raw %}{{ page }}{% endraw %}` | The page number (the nth-element for which the label is generated | +The following variables are in injected into Twig and can be accessed using `{% raw %}{{ variable }}{% endraw %}` ( +or `{% raw %}{{ variable.property }}{% endraw %}`): +| Variable name | Description | +|--------------------------------------------|--------------------------------------------------------------------------------------| +| `{% raw %}{{ element }}{% endraw %}` | The target element, selected in label dialog. | +| `{% raw %}{{ user }}{% endraw %}` | The current logged in user. Null if you are not logged in | +| `{% raw %}{{ install_title }}{% endraw %}` | The name of the current Part-DB instance (similar to [[INSTALL_NAME]] placeholder). | +| `{% raw %}{{ page }}{% endraw %}` | The page number (the nth-element for which the label is generated | +| `{% raw %}{{ last_page }}{% endraw %}` | The page number of the last element. Equals the number of all pages / element labels | +| `{% raw %}{{ paper_width }}{% endraw %}` | The width of the label paper in mm | +| `{% raw %}{{ paper_height }}{% endraw %}` | The height of the label paper in mm | + +### Use the placeholders in twig mode + +You can use the placeholders described above in the twig mode on `element` using the `{% raw %}{{ placeholder('PLACEHOLDER', element) }}{% endraw %}` +function or the ``{{ "[[PLACEHOLDER]]"|placeholders(element) }}`` filter: + +```twig +{% raw %} +{# The function can be used to get the a single placeholder value of an element, if the placeholder does not exist, null is returned #} +{{ placeholder('[[NAME]]', element) }} + +{# The filter can be used to replace all placeholders in a string with the values of the element #} +{{ "[[NAME]]: [[DESCRIPTION]]"|placeholders(element) }} + +{# Using the apply environment every placeholder in the apply block will be replaced automatically #} +{% apply placeholders(element) %} + [[NAME]]: [[DESCRIPTION]] +{% endapply %} + +{# If the block contains HTML use placeholders(element)|raw to prevent escaping of the HTML #} +{% apply placeholders(element)|raw %} + [[NAME]]: [[DESCRIPTION]] +{% endapply %} + +{% endraw %} +``` + +### Important entity fields in twig mode + +In twig mode you have access to many fields of the entity you are generating the label for and their associated entities. +Following are some important fields of the entities listed. See the [SandboxedTwigFactory service](https://github.com/Part-DB/Part-DB-server/blob/master/src/Services/LabelSystem/SandboxedTwigFactory.php) for the full list of allowed class methods. + +Please not that the field names might change in the future. + +#### Part + +| Field name | Description | +|---------------------|-----------------------------------------------------------------------------------------------| +| `id` | The internal ID of the part | +| `name` | The name of the part | +| `category` | The category of the part | +| `manufacturer` | The manufacturer of the part | +| `footprint` | The footprint of the part | +| `mass` | The mass of the part | +| `ManufacturerProductNumber` | The manufacturer product number of the part | +| `tags` | The tags of the part | +| `description` | The rich text (markdown) description of the part | +| `comment` | The rich text (markdown) comment of the part | +| `lastModified` | The datetime object when the part was last modified | +| `creationDate` | The datetime object when the part was created | +| `ipn` | The internal part number of the part | +| `partUnit` | The unit of the part | +| `amountSum` | The sum of the amount of all part lots of this part | +| `amountUnknwon` | Bool: True if there is at least one part lot with unknown amount | +| `partLots` | The part lots of the part | +| `parameters` | The parameters of the part | +| `orderdetails` | The order details of the part as array of Orderdetails | + +#### Part lot + +| Field name | Description | +|---------------------|-----------------------------------------------------------------------------------------------| +| `id` | The internal ID of the part lot | +| `name` | The name of the part lot | +| `comment` | The rich text (markdown) comment of the part lot | +| `expirationDate` | The expiration date of the part lot (as Datetime object) | +| `amount` | The amount of parts in this lot | +| `storageLocation` | The storage location of this part lot | +| `part` | The part of this part lot | +| `needsRefill` | Bool: True if the part lot needs a refill | +| `expired` | Bool: True if the part lot is expired | +| `vendorBarcode` | The vendor barcode field of the lot | + +#### Structural entities like categories, manufacturers, footprints, and storage locations + +| Field name | Description | +|---------------------|-----------------------------------------------------------------------------------------------| +| `id` | The internal ID of the entity | +| `name` | The name of the entity | +| `comment` | The rich text (markdown) comment of the entity | +| `parent` | The parent entity of the entity | +| `children` | The children entities of the entity | +| `lastModified` | The datetime object when the entity was last modified | +| `creationDate` | The datetime object when the entity was created | +| `level` | The level of the entity in the hierarchy | +| `fullPath` | The full path of the entity (you can pass the delimiter as parameter) | +| `pathArray` | The path of the entity as array of strings | + +#### Orderdetails + +| Field name | Description | +|---------------------|-----------------------------------------------------------------------------------------------| +| `id` | The internal ID of the order detail | +| `part` | The part of the order detail | +| `supplier` | The supplier/distributor of the order detail | +| `obsolete` | Bool: True if the order detail is obsolete | +| `pricedetails` | The price details of the order detail as array of Pricedetails | + +#### Pricedetails + +| Field name | Description | +|---------------------|-----------------------------------------------------------------------------------------------| +| `id` | The internal ID of the price detail | +| `price` | The price of the price detail | +| `currency` | The currency of the price detail | +| `currencyIsoCode` | The ISO code of the used currency | +| `pricePerUnit` | The price per unit of the price detail | +| `priceRelatedQuantity` | The related quantity of the price detail | +| `minDiscountQuantity` | The minimum discount quantity of the price detail | + +#### User + +| Field name | Description | +|---------------------|-----------------------------------------------------------------------------------------------| +| `id` | The internal ID of the user | +| `username` | The username of the user | +| `email` | The email of the user | +| `fullName` | The full name of the user | +| `lastName` | The last name of the user | +| `firstName` | The first name of the user | +| `department` | The department of the user | + + +### Part-DB specific twig functions and filters + +Part-DB offers some custom twig functions and filters, which can be used in the twig mode and ease the rendering of +certain data: + +#### Functions + +| Function name | Description | +|----------------------------------------------|-----------------------------------------------------------------------------------------------| +| `placeholder(placeholder, element)` | Get the value of a placeholder of an element | +| `entity_type(element)` | Get the type of an entity as string | +| `entity_url(element, type)` | Get the URL to a specific entity type page (e.g. `info`, `edit`, etc.) | +| `barcode_svg(content, type)` | Generate a barcode SVG from the content and type (e.g. `QRCODE`, `CODE128` etc.). A svg string is returned, which you need to data uri encode to inline it. | + +### Filters + +| Filter name | Description | +|----------------------------------------------|-----------------------------------------------------------------------------------------------| +| `format_bytes` | Format a byte count to a human readable string | +| `format_money(price, currency)` | Format a price to a human readable string with the currency | +| `format_amount(amount, unit)` | Format an amount to a human readable string with the unit object | +| `format_si(value, unit_str)` | Format a value using SI prefixes and the given unit string | +| `placeholders(element)` | Replace all placeholders in a string with the values of the element | ## Use custom fonts for PDF labels -You can use your own fonts for label generation. To do this, put the TTF files of the fonts you want to use into the `assets/fonts/dompdf` folder. -The filename will be used as name for the font family and you can use a `_bold` (or `_b`), `_italic` (or `_i`) or `_bold_italic` (or `_bi`) suffix to define -different styles of the font. So for example, if you copy the file `myfont.ttf` and `myfont_bold.ttf` into the `assets/fonts/dompdf` folder, you can use the font family `myfont` with regular and bold style. -Afterwards regenerate cache with `php bin/console cache:clear`, so the new fonts will be available for label generation. -The fonts will not be availble from the UI directly, you have to use it in the HTML directly either by defining a `style="font-family: 'myfont';"` attribute on the HTML element or by using a CSS class. -You can define the font globally for the label, by adding following statement to the "Additional styles (CSS)" option in the label generator settings: +You can use your own fonts for label generation. To do this, put the TTF files of the fonts you want to use into +the `assets/fonts/dompdf` folder. +The filename will be used as name for the font family, and you can use a `_bold` (or `_b`), `_italic` (or `_i`) +or `_bold_italic` (or `_bi`) suffix to define +different styles of the font. So for example, if you copy the file `myfont.ttf` and `myfont_bold.ttf` into +the `assets/fonts/dompdf` folder, you can use the font family `myfont` with regular and bold style. +Afterward regenerate cache with `php bin/console cache:clear`, so the new fonts will be available for label generation. + +The fonts will not be available from the UI directly, you have to use it in the HTML directly either by defining +a `style="font-family: 'myfont';"` attribute on the HTML element or by using a CSS class. +You can define the font globally for the label, by adding following statement to the "Additional styles (CSS)" option in +the label generator settings: + ```css * { font-family: 'myfont'; @@ -110,9 +275,15 @@ You can define the font globally for the label, by adding following statement to ``` ## Non-latin characters in PDF labels -The default used font (DejaVu) does not support all characters. Especially characters from non-latin languages like Chinese, Japanese, Korean, Arabic, Hebrew, Cyrillic, etc. are not supported. -For this we use [Unifont](http://unifoundry.com/unifont.html) as fallback font. This font supports all (or most) unicode characters, but is not as beautiful as DejaVu. -If you want to use a different (more beautiful) font, you can use the [custom fonts](#use-custom-fonts-for-pdf-labels) feature. -There is the [Noto](https://www.google.com/get/noto/) font family from Google, which supports a lot of languages and is available in different styles (regular, bold, italic, bold-italic). -For example you can use [Noto CJK](https://github.com/notofonts/noto-cjk) for more beautful Chinese, Japanese and Korean characters. \ No newline at end of file +The default used font (DejaVu) does not support all characters. Especially characters from non-latin languages like +Chinese, Japanese, Korean, Arabic, Hebrew, Cyrillic, etc. are not supported. +For this, we use [Unifont](http://unifoundry.com/unifont.html) as fallback font. This font supports all (or most) Unicode +characters but is not as beautiful as DejaVu. + +If you want to use a different (more beautiful) font, you can use the [custom fonts](#use-custom-fonts-for-pdf-labels) +feature. +There is the [Noto](https://www.google.com/get/noto/) font family from Google, which supports a lot of languages and is +available in different styles (regular, bold, italic, bold-italic). +For example, you can use [Noto CJK](https://github.com/notofonts/noto-cjk) for more beautiful Chinese, Japanese, +and Korean characters. \ No newline at end of file diff --git a/docs/usage/tips_tricks.md b/docs/usage/tips_tricks.md index 81a31ec1..d033cbe8 100644 --- a/docs/usage/tips_tricks.md +++ b/docs/usage/tips_tricks.md @@ -8,42 +8,49 @@ parent: Usage Following you can find miscellaneous tips and tricks for using Part-DB. -## Create datastructures directly from part edit page +## Create data structures directly from part edit page -Instead of first creating a category, manufacturer, footprint, etc. and then creating the part, you can create the -datastructures directly from the part edit page: Just type the name of the datastructure you want to create into the -select field on the part edit page and press "Create new ...". The new datastructure will be created, when you save +Instead of first creating a category, manufacturer, footprint, etc., and then creating the part, you can create the +data structures directly from the part edit page: Just type the name of the data structure you want to create into the +select field on the part edit page and press "Create new ...". The new data structure will be created when you save the part changes. -You can create also create nested datastructures this way. For example, if you want to create a new category "AVRs", +You can create also create nested data structures this way. For example, if you want to create a new category "AVRs", as a subcategory of "MCUs", you can just type "MCUs->AVRs" into the category select field and press "Create new". The new category "AVRs" will be created as a subcategory of "MCUs". If the category "MCUs" does not exist, it will be created too. -## Builtin footprint images -Part-DB includes several builtin images for common footprints. You can use these images in your footprint datastructures, -by creating an attachment on the datastructure and selecting it as preview image. +## Built-in footprint images + +Part-DB includes several built-in images for common footprints. You can use these images in your footprint +data structures, +by creating an attachment on the data structure and selecting it as the preview image. Type the name of the footprint image you want to use into the URL field of the attachment and select it from the -dropdown menu. You can find a gallery of all builtin footprint images and their names in the "Builtin footprint image gallery", -which you can find in the "Tools" menu (you maybe need to give your user the permission to access this tool). +dropdown menu. You can find a gallery of all builtin footprint images and their names in the "Builtin footprint image +gallery", +which you can find in the "Tools" menu (you may need to give your user the permission to access this tool). ## Parametric search -In the "parameters" tab of the filter panel on parts list page, you can define constraints, which parameter values -have to fullfill. This allows you to search for parts with specific parameters (or parameter ranges), for example you + +In the "parameters" tab of the filter panel on parts list page, you can define constraints, and which parameter values +have to fulfill. This allows you to search for parts with specific parameters (or parameter ranges), for example, you can search for all parts with a voltage rating of greater than 5 V. -## View own users permissions +## View own user's permissions + If you want to see which permissions your user has, you can find a list of the permissions in the "Permissions" panel on the user info page. ## Use LaTeX equations -You can use LaTeX equations everywhere where markdown is supported (for example in the description or notes field of a part). + +You can use LaTeX equations everywhere where markdown is supported (for example in the description or notes field of a +part). [KaTeX](https://katex.org/) is used to render the equations. You can find a list of supported features in the [KaTeX documentation](https://katex.org/docs/supported.html). -To input a LaTeX equation, you have to wrap it in a pair of dollar signs (`$`). Single dollar signs mark inline equations, -double dollar signs mark displayed equations (which will be its own line and centered). For example, the following equation -will be rendered as an inline equation: +To input a LaTeX equation, you have to wrap it in a pair of dollar signs (`$`). Single dollar signs mark inline +equations, double dollar signs mark displayed equations (which will be their own line and centered). +For example, the following equation will be rendered as an inline equation: ``` $E=mc^2$ @@ -56,7 +63,8 @@ $$E=mc^2$$ ``` ## Update currency exchange rates automatically -Part-DB can update the currency exchange rates of all defined currencies programatically + +Part-DB can update the currency exchange rates of all defined currencies programmatically by calling the `php bin/console partdb:currencies:update-exchange-rates`. If you call this command regularly (e.g. with a cronjob), you can keep the exchange rates up-to-date. @@ -65,11 +73,26 @@ Please note that if you use a base currency, which is not the Euro, you have to free API used by default only supports the Euro as base currency. ## Enforce log comments + On almost any editing operation it is possible to add a comment describing, what or why you changed something. -This comment will be written to change log and can be viewed later. -If you want to enforce your users to add comments to certain operations, you can do this by setting the `ENFORCE_CHANGE_COMMENTS_FOR` option. +This comment will be written to changelog and can be viewed later. +If you want to force your users to add comments to certain operations, you can do this by setting +the `ENFORCE_CHANGE_COMMENTS_FOR` option. See the configuration reference for more information. ## Personal stocks and stock locations -For makerspaces and universities with a lot of users, where each user can have his own stock, which only he should be able to access, you can assign -the user as "owner" of a part lot. This way, only him is allowed to add or remove parts from this lot. \ No newline at end of file + +For maker spaces and universities with a lot of users, where each user can have his own stock, which only he should be +able to access, you can assign +the user as "owner" of a part lot. This way, only he is allowed to add or remove parts from this lot. + +## Update notifications + +Part-DB can show you a notification that there is a newer version than currently installed available. The notification +will be shown on the homepage and the server info page. +It is only be shown to users which has the `Show available Part-DB updates` permission. + +For the notification to work, Part-DB queries the GitHub API every 2 days to check for new releases. No data is sent to +GitHub besides the metadata required for the connection (so the public IP address of your computer running Part-DB). +If you don't want Part-DB to query the GitHub API, or if your server can not reach the internet, you can disable the +update notifications by setting the `CHECK_FOR_UPDATES` option to `false`. \ No newline at end of file diff --git a/migrations/Version1.php b/migrations/Version1.php index f1389801..fc4c7b2e 100644 --- a/migrations/Version1.php +++ b/migrations/Version1.php @@ -160,7 +160,7 @@ EOD; 21840,21840,21840,21840,21840,21520,21520,21520,20480,21520,20480, 20480,20480,20480,20480,21504,20480), ( - 2,'admin', '${admin_pw}','','', + 2,'admin', '$admin_pw','','', '','',1,1,21845,21845,21845,21,85,21,349525,21845,21845,21845,21845 ,21845,21845,21845,21845,21845,21845,21845,21845,21845,21845,21845, 21845,21845,21845,21845,21845,21845); @@ -235,4 +235,14 @@ EOD; { $this->warnIf(true, "Migration not needed for SQLite. Skipping..."); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20190902140506.php b/migrations/Version20190902140506.php index 38939b5b..8984cb06 100644 --- a/migrations/Version20190902140506.php +++ b/migrations/Version20190902140506.php @@ -69,6 +69,12 @@ final class Version20190902140506 extends AbstractMultiPlatformMigration //For attachments $this->addSql('DELETE FROM `attachements` WHERE attachements.class_name = "Part" AND (SELECT COUNT(parts.id) FROM parts WHERE parts.id = attachements.element_id) = 0;'); + //Add perms_labels column to groups table if not existing (it was not created in certain legacy versions) + //This prevents the migration failing (see https://github.com/Part-DB/Part-DB-server/issues/366 and https://github.com/Part-DB/Part-DB-server/issues/67) + if (!$this->doesColumnExist('groups', 'perms_labels')) { + $this->addSql('ALTER TABLE `groups` ADD `perms_labels` SMALLINT NOT NULL AFTER `perms_tools`'); + } + /************************************************************************************************************** * Doctrine generated SQL **************************************************************************************************************/ @@ -228,8 +234,8 @@ final class Version20190902140506 extends AbstractMultiPlatformMigration 'orderdetails', 'pricedetails', 'storelocations', 'suppliers', ]; foreach ($tables as $table) { - $this->addSql("UPDATE ${table} SET datetime_added = NOW() WHERE datetime_added = '0000-00-00 00:00:00'"); - $this->addSql("UPDATE ${table} SET last_modified = datetime_added WHERE last_modified = '0000-00-00 00:00:00'"); + $this->addSql("UPDATE $table SET datetime_added = NOW() WHERE datetime_added = '0000-00-00 00:00:00'"); + $this->addSql("UPDATE $table SET last_modified = datetime_added WHERE last_modified = '0000-00-00 00:00:00'"); } //Set the dbVersion to a high value, to prevent the old Part-DB versions to upgrade DB! @@ -374,4 +380,14 @@ final class Version20190902140506 extends AbstractMultiPlatformMigration { $this->warnIf(true, "Migration not needed for SQLite. Skipping..."); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20190913141126.php b/migrations/Version20190913141126.php index 58093338..31eed64a 100644 --- a/migrations/Version20190913141126.php +++ b/migrations/Version20190913141126.php @@ -88,4 +88,14 @@ final class Version20190913141126 extends AbstractMultiPlatformMigration { $this->warnIf(true, "Migration not needed for SQLite. Skipping..."); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20190924113252.php b/migrations/Version20190924113252.php index fe7c9c8b..8221c686 100644 --- a/migrations/Version20190924113252.php +++ b/migrations/Version20190924113252.php @@ -179,4 +179,14 @@ final class Version20190924113252 extends AbstractMultiPlatformMigration { $this->warnIf(true, "Migration not needed for SQLite. Skipping..."); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20191214153125.php b/migrations/Version20191214153125.php index 9a61c10d..83803d13 100644 --- a/migrations/Version20191214153125.php +++ b/migrations/Version20191214153125.php @@ -65,4 +65,14 @@ final class Version20191214153125 extends AbstractMultiPlatformMigration { $this->warnIf(true, "Migration not needed for SQLite. Skipping..."); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20200126191823.php b/migrations/Version20200126191823.php index c093a4d7..cf362ea5 100644 --- a/migrations/Version20200126191823.php +++ b/migrations/Version20200126191823.php @@ -68,4 +68,14 @@ final class Version20200126191823 extends AbstractMultiPlatformMigration { $this->warnIf(true, "Migration not needed for SQLite. Skipping..."); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20200311204104.php b/migrations/Version20200311204104.php index 2a90b62c..daa6fd28 100644 --- a/migrations/Version20200311204104.php +++ b/migrations/Version20200311204104.php @@ -56,4 +56,14 @@ final class Version20200311204104 extends AbstractMultiPlatformMigration { $this->warnIf(true, "Migration not needed for SQLite. Skipping..."); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20200409130946.php b/migrations/Version20200409130946.php index 72bdda9c..ef2dc7ab 100644 --- a/migrations/Version20200409130946.php +++ b/migrations/Version20200409130946.php @@ -42,4 +42,14 @@ final class Version20200409130946 extends AbstractMultiPlatformMigration { $this->warnIf(true, "Migration not needed for SQLite. Skipping..."); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20200502161750.php b/migrations/Version20200502161750.php index 93bb0d00..55117541 100644 --- a/migrations/Version20200502161750.php +++ b/migrations/Version20200502161750.php @@ -163,4 +163,14 @@ EOD; $this->addSql('DROP TABLE u2f_keys'); $this->addSql('DROP TABLE "users"'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20220925162725.php b/migrations/Version20220925162725.php index 0f04f04e..21ac8946 100644 --- a/migrations/Version20220925162725.php +++ b/migrations/Version20220925162725.php @@ -535,4 +535,14 @@ final class Version20220925162725 extends AbstractMultiPlatformMigration $this->addSql('CREATE INDEX IDX_1483A5E938248176 ON "users" (currency_id)'); $this->addSql('CREATE INDEX IDX_1483A5E96DEDCEC2 ON "users" (id_preview_attachement)'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20221003212851.php b/migrations/Version20221003212851.php index 3a7379ca..81e33c0e 100644 --- a/migrations/Version20221003212851.php +++ b/migrations/Version20221003212851.php @@ -47,4 +47,14 @@ final class Version20221003212851 extends AbstractMultiPlatformMigration { $this->addSql('DROP TABLE webauthn_keys'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20221114193325.php b/migrations/Version20221114193325.php index d80cc1d2..9766ccf3 100644 --- a/migrations/Version20221114193325.php +++ b/migrations/Version20221114193325.php @@ -4,24 +4,20 @@ declare(strict_types=1); namespace DoctrineMigrations; -use App\Entity\UserSystem\PermissionData; use App\Migration\AbstractMultiPlatformMigration; -use App\Security\Interfaces\HasPermissionsInterface; +use App\Migration\WithPermPresetsTrait; use App\Services\UserSystem\PermissionPresetsHelper; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Schema\Schema; -use Doctrine\Migrations\AbstractMigration; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; /** * Auto-generated Migration: Please modify to your needs! */ final class Version20221114193325 extends AbstractMultiPlatformMigration implements ContainerAwareInterface { - private ?ContainerInterface $container = null; - private ?PermissionPresetsHelper $permission_presets_helper = null; + use WithPermPresetsTrait; public function __construct(Connection $connection, LoggerInterface $logger) { @@ -33,34 +29,6 @@ final class Version20221114193325 extends AbstractMultiPlatformMigration impleme return 'Update the permission system to the new system. Please note that all permissions will be reset!'; } - private function getJSONPermDataFromPreset(string $preset): string - { - if ($this->permission_presets_helper === null) { - throw new \RuntimeException('PermissionPresetsHelper not set! There seems to be some issue with the dependency injection!'); - } - - //Create a virtual user on which we can apply the preset - $user = new class implements HasPermissionsInterface { - - public PermissionData $perm_data; - - public function __construct() - { - $this->perm_data = new PermissionData(); - } - - public function getPermissions(): PermissionData - { - return $this->perm_data; - } - }; - - //Apply the preset to the virtual user - $this->permission_presets_helper->applyPreset($user, $preset); - - //And return the json data - return json_encode($user->getPermissions()); - } private function addDataMigrationAndWarning(): void { @@ -83,9 +51,12 @@ final class Version20221114193325 extends AbstractMultiPlatformMigration impleme //Reset the permissions of the admin user, to allow admin permissions (like the admins group) $this->addSql("UPDATE `users` SET permissions_data = '$admin' WHERE id = 2;"); + //This warning should not be needed, anymore, as almost everybody should have updated to the new version by now, and this warning would just irritate new users of the software + /* $this->logger->warning('!!! All permissions were reset! Please change them to the desired state, immediately !!!'); $this->logger->warning('!!! For security reasons all users (except the admin user) were disabled. Login with admin user and reenable other users after checking their permissions !!!'); $this->logger->warning('!!! For more infos see: https://github.com/Part-DB/Part-DB-symfony/discussions/193 !!!'); + */ } public function mySQLUp(Schema $schema): void @@ -161,11 +132,15 @@ final class Version20221114193325 extends AbstractMultiPlatformMigration impleme $this->addSql('CREATE INDEX user_idx_username ON "users" (name)'); } - public function setContainer(ContainerInterface $container = null) + + + public function postgreSQLUp(Schema $schema): void { - if ($container) { - $this->container = $container; - $this->permission_presets_helper = $container->get(PermissionPresetsHelper::class); - } + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); } } diff --git a/migrations/Version20221204004815.php b/migrations/Version20221204004815.php index 20e151db..c6c7b6ab 100644 --- a/migrations/Version20221204004815.php +++ b/migrations/Version20221204004815.php @@ -55,4 +55,14 @@ final class Version20221204004815 extends AbstractMultiPlatformMigration $this->addSql('CREATE INDEX parts_idx_datet_name_last_id_needs ON "parts" (datetime_added, name, last_modified, id, needs_review)'); $this->addSql('CREATE INDEX parts_idx_name ON "parts" (name)'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20221216224745.php b/migrations/Version20221216224745.php index 63bb535e..9ac3b8ba 100644 --- a/migrations/Version20221216224745.php +++ b/migrations/Version20221216224745.php @@ -67,6 +67,15 @@ final class Version20221216224745 extends AbstractMultiPlatformMigration $this->addSql('CREATE INDEX log_idx_type ON log (type)'); $this->addSql('CREATE INDEX log_idx_type_target ON log (type, target_type, target_id)'); $this->addSql('CREATE INDEX log_idx_datetime ON log (datetime)'); + } + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); } } diff --git a/migrations/Version20230108165410.php b/migrations/Version20230108165410.php index 4124a95a..90f6314e 100644 --- a/migrations/Version20230108165410.php +++ b/migrations/Version20230108165410.php @@ -320,4 +320,14 @@ final class Version20230108165410 extends AbstractMultiPlatformMigration $this->addSql('ALTER TABLE projects RENAME TO devices'); $this->addSql('ALTER TABLE project_bom_entries RENAME TO device_parts'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20230219225340.php b/migrations/Version20230219225340.php index 94e08963..2740c85e 100644 --- a/migrations/Version20230219225340.php +++ b/migrations/Version20230219225340.php @@ -521,4 +521,14 @@ final class Version20230219225340 extends AbstractMultiPlatformMigration $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); } + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + } diff --git a/migrations/Version20230220221024.php b/migrations/Version20230220221024.php index 01d65d51..b2209351 100644 --- a/migrations/Version20230220221024.php +++ b/migrations/Version20230220221024.php @@ -37,4 +37,14 @@ final class Version20230220221024 extends AbstractMultiPlatformMigration { $this->addSql('ALTER TABLE `users` DROP saml_user'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20230402170923.php b/migrations/Version20230402170923.php index 016a10d0..3325afb6 100644 --- a/migrations/Version20230402170923.php +++ b/migrations/Version20230402170923.php @@ -297,4 +297,14 @@ final class Version20230402170923 extends AbstractMultiPlatformMigration $this->addSql('DROP TABLE __temp__webauthn_keys'); $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20230408170059.php b/migrations/Version20230408170059.php index 88be7798..e3662e16 100644 --- a/migrations/Version20230408170059.php +++ b/migrations/Version20230408170059.php @@ -49,4 +49,14 @@ final class Version20230408170059 extends AbstractMultiPlatformMigration $this->addSql('CREATE INDEX IDX_1483A5E9EA7100A1 ON "users" (id_preview_attachment)'); $this->addSql('CREATE INDEX user_idx_username ON "users" (name)'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20230408213957.php b/migrations/Version20230408213957.php index 976a79db..47807126 100644 --- a/migrations/Version20230408213957.php +++ b/migrations/Version20230408213957.php @@ -434,4 +434,14 @@ final class Version20230408213957 extends AbstractMultiPlatformMigration $this->addSql('DROP TABLE __temp__webauthn_keys'); $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20230417211732.php b/migrations/Version20230417211732.php index 7fef77eb..5fa3b5f7 100644 --- a/migrations/Version20230417211732.php +++ b/migrations/Version20230417211732.php @@ -45,4 +45,14 @@ final class Version20230417211732 extends AbstractMultiPlatformMigration { //As we done nothing, we don't need to implement this method. } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20230528000149.php b/migrations/Version20230528000149.php index 05830937..5e742383 100644 --- a/migrations/Version20230528000149.php +++ b/migrations/Version20230528000149.php @@ -62,4 +62,14 @@ final class Version20230528000149 extends AbstractMultiPlatformMigration $this->addSql('DROP TABLE __temp__webauthn_keys'); $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20230716184033.php b/migrations/Version20230716184033.php index adf3e83c..7c0d8a12 100644 --- a/migrations/Version20230716184033.php +++ b/migrations/Version20230716184033.php @@ -348,4 +348,14 @@ final class Version20230716184033 extends AbstractMultiPlatformMigration $this->addSql('DROP TABLE __temp__webauthn_keys'); $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20230730131708.php b/migrations/Version20230730131708.php index 88b49460..a12c3b8d 100644 --- a/migrations/Version20230730131708.php +++ b/migrations/Version20230730131708.php @@ -99,4 +99,14 @@ final class Version20230730131708 extends AbstractMultiPlatformMigration $this->addSql('CREATE INDEX parts_idx_name ON "parts" (name)'); $this->addSql('CREATE INDEX parts_idx_ipn ON "parts" (ipn)'); } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } } diff --git a/migrations/Version20230816213201.php b/migrations/Version20230816213201.php new file mode 100644 index 00000000..d776da26 --- /dev/null +++ b/migrations/Version20230816213201.php @@ -0,0 +1,54 @@ +addSql('CREATE TABLE api_tokens (id INT AUTO_INCREMENT NOT NULL, user_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, valid_until DATETIME DEFAULT NULL, token VARCHAR(68) NOT NULL, level SMALLINT NOT NULL, last_time_used DATETIME DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, UNIQUE INDEX UNIQ_2CAD560E5F37A13B (token), INDEX IDX_2CAD560EA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE api_tokens ADD CONSTRAINT FK_2CAD560EA76ED395 FOREIGN KEY (user_id) REFERENCES `users` (id)'); + } + + public function mySQLDown(Schema $schema): void + { + $this->addSql('ALTER TABLE api_tokens DROP FOREIGN KEY FK_2CAD560EA76ED395'); + $this->addSql('DROP TABLE api_tokens'); + } + + public function sqLiteUp(Schema $schema): void + { + $this->addSql('CREATE TABLE api_tokens (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, valid_until DATETIME DEFAULT NULL, token VARCHAR(68) NOT NULL, level SMALLINT NOT NULL, last_time_used DATETIME DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_2CAD560EA76ED395 FOREIGN KEY (user_id) REFERENCES "users" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_2CAD560E5F37A13B ON api_tokens (token)'); + $this->addSql('CREATE INDEX IDX_2CAD560EA76ED395 ON api_tokens (user_id)'); + } + + public function sqLiteDown(Schema $schema): void + { + $this->addSql('DROP TABLE api_tokens'); + } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } +} diff --git a/migrations/Version20231114223101.php b/migrations/Version20231114223101.php new file mode 100644 index 00000000..c06cb279 --- /dev/null +++ b/migrations/Version20231114223101.php @@ -0,0 +1,81 @@ +addSql('CREATE TABLE part_association (id INT AUTO_INCREMENT NOT NULL, owner_id INT NOT NULL, other_id INT NOT NULL, type SMALLINT NOT NULL, other_type VARCHAR(255) DEFAULT NULL, comment LONGTEXT DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, INDEX IDX_61B952E07E3C61F9 (owner_id), INDEX IDX_61B952E0998D9879 (other_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE part_association ADD CONSTRAINT FK_61B952E07E3C61F9 FOREIGN KEY (owner_id) REFERENCES `parts` (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE part_association ADD CONSTRAINT FK_61B952E0998D9879 FOREIGN KEY (other_id) REFERENCES `parts` (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE part_lots ADD vendor_barcode VARCHAR(255) DEFAULT NULL'); + $this->addSql('CREATE INDEX part_lots_idx_barcode ON part_lots (vendor_barcode)'); + } + + public function mySQLDown(Schema $schema): void + { + $this->addSql('ALTER TABLE part_association DROP FOREIGN KEY FK_61B952E07E3C61F9'); + $this->addSql('ALTER TABLE part_association DROP FOREIGN KEY FK_61B952E0998D9879'); + $this->addSql('DROP TABLE part_association'); + $this->addSql('DROP INDEX part_lots_idx_barcode ON part_lots'); + $this->addSql('ALTER TABLE part_lots DROP vendor_barcode'); + } + + public function sqLiteUp(Schema $schema): void + { + $this->addSql('CREATE TABLE part_association (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, owner_id INTEGER NOT NULL, other_id INTEGER NOT NULL, type SMALLINT NOT NULL, other_type VARCHAR(255) DEFAULT NULL, comment CLOB DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_61B952E07E3C61F9 FOREIGN KEY (owner_id) REFERENCES "parts" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_61B952E0998D9879 FOREIGN KEY (other_id) REFERENCES "parts" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('CREATE INDEX IDX_61B952E07E3C61F9 ON part_association (owner_id)'); + $this->addSql('CREATE INDEX IDX_61B952E0998D9879 ON part_association (other_id)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__part_lots AS SELECT id, id_store_location, id_part, id_owner, description, comment, expiration_date, instock_unknown, amount, needs_refill, last_modified, datetime_added FROM part_lots'); + $this->addSql('DROP TABLE part_lots'); + $this->addSql('CREATE TABLE part_lots (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_store_location INTEGER DEFAULT NULL, id_part INTEGER NOT NULL, id_owner INTEGER DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, expiration_date DATETIME DEFAULT NULL, instock_unknown BOOLEAN NOT NULL, amount DOUBLE PRECISION NOT NULL, needs_refill BOOLEAN NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, vendor_barcode VARCHAR(255) DEFAULT NULL, CONSTRAINT FK_EBC8F9435D8F4B37 FOREIGN KEY (id_store_location) REFERENCES storelocations (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EBC8F943C22F6CC4 FOREIGN KEY (id_part) REFERENCES parts (id) ON UPDATE NO ACTION ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EBC8F94321E5A74C FOREIGN KEY (id_owner) REFERENCES users (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO part_lots (id, id_store_location, id_part, id_owner, description, comment, expiration_date, instock_unknown, amount, needs_refill, last_modified, datetime_added) SELECT id, id_store_location, id_part, id_owner, description, comment, expiration_date, instock_unknown, amount, needs_refill, last_modified, datetime_added FROM __temp__part_lots'); + $this->addSql('DROP TABLE __temp__part_lots'); + $this->addSql('CREATE INDEX IDX_EBC8F94321E5A74C ON part_lots (id_owner)'); + $this->addSql('CREATE INDEX IDX_EBC8F943C22F6CC4 ON part_lots (id_part)'); + $this->addSql('CREATE INDEX IDX_EBC8F9435D8F4B37 ON part_lots (id_store_location)'); + $this->addSql('CREATE INDEX part_lots_idx_instock_un_expiration_id_part ON part_lots (instock_unknown, expiration_date, id_part)'); + $this->addSql('CREATE INDEX part_lots_idx_needs_refill ON part_lots (needs_refill)'); + $this->addSql('CREATE INDEX part_lots_idx_barcode ON part_lots (vendor_barcode)'); + } + + public function sqLiteDown(Schema $schema): void + { + $this->addSql('DROP TABLE part_association'); + $this->addSql('CREATE TEMPORARY TABLE __temp__part_lots AS SELECT id, id_store_location, id_part, id_owner, description, comment, expiration_date, instock_unknown, amount, needs_refill, last_modified, datetime_added FROM part_lots'); + $this->addSql('DROP TABLE part_lots'); + $this->addSql('CREATE TABLE part_lots (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_store_location INTEGER DEFAULT NULL, id_part INTEGER NOT NULL, id_owner INTEGER DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, expiration_date DATETIME DEFAULT NULL, instock_unknown BOOLEAN NOT NULL, amount DOUBLE PRECISION NOT NULL, needs_refill BOOLEAN NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_EBC8F9435D8F4B37 FOREIGN KEY (id_store_location) REFERENCES "storelocations" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EBC8F943C22F6CC4 FOREIGN KEY (id_part) REFERENCES "parts" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EBC8F94321E5A74C FOREIGN KEY (id_owner) REFERENCES "users" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO part_lots (id, id_store_location, id_part, id_owner, description, comment, expiration_date, instock_unknown, amount, needs_refill, last_modified, datetime_added) SELECT id, id_store_location, id_part, id_owner, description, comment, expiration_date, instock_unknown, amount, needs_refill, last_modified, datetime_added FROM __temp__part_lots'); + $this->addSql('DROP TABLE __temp__part_lots'); + $this->addSql('CREATE INDEX IDX_EBC8F9435D8F4B37 ON part_lots (id_store_location)'); + $this->addSql('CREATE INDEX IDX_EBC8F943C22F6CC4 ON part_lots (id_part)'); + $this->addSql('CREATE INDEX IDX_EBC8F94321E5A74C ON part_lots (id_owner)'); + $this->addSql('CREATE INDEX part_lots_idx_instock_un_expiration_id_part ON part_lots (instock_unknown, expiration_date, id_part)'); + $this->addSql('CREATE INDEX part_lots_idx_needs_refill ON part_lots (needs_refill)'); + } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } +} diff --git a/migrations/Version20231130180903.php b/migrations/Version20231130180903.php new file mode 100644 index 00000000..0eccb5aa --- /dev/null +++ b/migrations/Version20231130180903.php @@ -0,0 +1,98 @@ +addSql('ALTER TABLE categories ADD eda_info_reference_prefix VARCHAR(255) DEFAULT NULL, ADD eda_info_invisible TINYINT(1) DEFAULT NULL, ADD eda_info_exclude_from_bom TINYINT(1) DEFAULT NULL, ADD eda_info_exclude_from_board TINYINT(1) DEFAULT NULL, ADD eda_info_exclude_from_sim TINYINT(1) DEFAULT NULL, ADD eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE footprints ADD eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD eda_info_reference_prefix VARCHAR(255) DEFAULT NULL, ADD eda_info_value VARCHAR(255) DEFAULT NULL, ADD eda_info_invisible TINYINT(1) DEFAULT NULL, ADD eda_info_exclude_from_bom TINYINT(1) DEFAULT NULL, ADD eda_info_exclude_from_board TINYINT(1) DEFAULT NULL, ADD eda_info_exclude_from_sim TINYINT(1) DEFAULT NULL, ADD eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL, ADD eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL'); + } + + public function mySQLDown(Schema $schema): void + { + $this->addSql('ALTER TABLE `categories` DROP eda_info_reference_prefix, DROP eda_info_invisible, DROP eda_info_exclude_from_bom, DROP eda_info_exclude_from_board, DROP eda_info_exclude_from_sim, DROP eda_info_kicad_symbol'); + $this->addSql('ALTER TABLE `footprints` DROP eda_info_kicad_footprint'); + $this->addSql('ALTER TABLE `parts` DROP eda_info_reference_prefix, DROP eda_info_value, DROP eda_info_invisible, DROP eda_info_exclude_from_bom, DROP eda_info_exclude_from_board, DROP eda_info_exclude_from_sim, DROP eda_info_kicad_symbol, DROP eda_info_kicad_footprint'); + } + + public function sqLiteUp(Schema $schema): void + { + $this->addSql('ALTER TABLE categories ADD COLUMN eda_info_reference_prefix VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE categories ADD COLUMN eda_info_invisible BOOLEAN DEFAULT NULL'); + $this->addSql('ALTER TABLE categories ADD COLUMN eda_info_exclude_from_bom BOOLEAN DEFAULT NULL'); + $this->addSql('ALTER TABLE categories ADD COLUMN eda_info_exclude_from_board BOOLEAN DEFAULT NULL'); + $this->addSql('ALTER TABLE categories ADD COLUMN eda_info_exclude_from_sim BOOLEAN DEFAULT NULL'); + $this->addSql('ALTER TABLE categories ADD COLUMN eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE footprints ADD COLUMN eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD COLUMN eda_info_reference_prefix VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD COLUMN eda_info_value VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD COLUMN eda_info_invisible BOOLEAN DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD COLUMN eda_info_exclude_from_bom BOOLEAN DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD COLUMN eda_info_exclude_from_board BOOLEAN DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD COLUMN eda_info_exclude_from_sim BOOLEAN DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD COLUMN eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD COLUMN eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL'); + } + + public function sqLiteDown(Schema $schema): void + { + $this->addSql('CREATE TEMPORARY TABLE __temp__categories AS SELECT id, parent_id, id_preview_attachment, name, last_modified, datetime_added, comment, not_selectable, alternative_names, partname_hint, partname_regex, disable_footprints, disable_manufacturers, disable_autodatasheets, disable_properties, default_description, default_comment FROM "categories"'); + $this->addSql('DROP TABLE "categories"'); + $this->addSql('CREATE TABLE "categories" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names CLOB DEFAULT NULL, partname_hint CLOB NOT NULL, partname_regex CLOB NOT NULL, disable_footprints BOOLEAN NOT NULL, disable_manufacturers BOOLEAN NOT NULL, disable_autodatasheets BOOLEAN NOT NULL, disable_properties BOOLEAN NOT NULL, default_description CLOB NOT NULL, default_comment CLOB NOT NULL, CONSTRAINT FK_3AF34668727ACA70 FOREIGN KEY (parent_id) REFERENCES "categories" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_3AF34668EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO "categories" (id, parent_id, id_preview_attachment, name, last_modified, datetime_added, comment, not_selectable, alternative_names, partname_hint, partname_regex, disable_footprints, disable_manufacturers, disable_autodatasheets, disable_properties, default_description, default_comment) SELECT id, parent_id, id_preview_attachment, name, last_modified, datetime_added, comment, not_selectable, alternative_names, partname_hint, partname_regex, disable_footprints, disable_manufacturers, disable_autodatasheets, disable_properties, default_description, default_comment FROM __temp__categories'); + $this->addSql('DROP TABLE __temp__categories'); + $this->addSql('CREATE INDEX IDX_3AF34668727ACA70 ON "categories" (parent_id)'); + $this->addSql('CREATE INDEX IDX_3AF34668EA7100A1 ON "categories" (id_preview_attachment)'); + $this->addSql('CREATE INDEX category_idx_name ON "categories" (name)'); + $this->addSql('CREATE INDEX category_idx_parent_name ON "categories" (parent_id, name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__footprints AS SELECT id, parent_id, id_preview_attachment, id_footprint_3d, name, last_modified, datetime_added, comment, not_selectable, alternative_names FROM "footprints"'); + $this->addSql('DROP TABLE "footprints"'); + $this->addSql('CREATE TABLE "footprints" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, id_footprint_3d INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names CLOB DEFAULT NULL, CONSTRAINT FK_A34D68A2727ACA70 FOREIGN KEY (parent_id) REFERENCES "footprints" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_A34D68A2EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_A34D68A232A38C34 FOREIGN KEY (id_footprint_3d) REFERENCES "attachments" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO "footprints" (id, parent_id, id_preview_attachment, id_footprint_3d, name, last_modified, datetime_added, comment, not_selectable, alternative_names) SELECT id, parent_id, id_preview_attachment, id_footprint_3d, name, last_modified, datetime_added, comment, not_selectable, alternative_names FROM __temp__footprints'); + $this->addSql('DROP TABLE __temp__footprints'); + $this->addSql('CREATE INDEX IDX_A34D68A2727ACA70 ON "footprints" (parent_id)'); + $this->addSql('CREATE INDEX IDX_A34D68A2EA7100A1 ON "footprints" (id_preview_attachment)'); + $this->addSql('CREATE INDEX IDX_A34D68A232A38C34 ON "footprints" (id_footprint_3d)'); + $this->addSql('CREATE INDEX footprint_idx_name ON "footprints" (name)'); + $this->addSql('CREATE INDEX footprint_idx_parent_name ON "footprints" (parent_id, name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__parts AS SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated FROM "parts"'); + $this->addSql('DROP TABLE "parts"'); + $this->addSql('CREATE TABLE "parts" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_preview_attachment INTEGER DEFAULT NULL, id_category INTEGER NOT NULL, id_footprint INTEGER DEFAULT NULL, id_part_unit INTEGER DEFAULT NULL, id_manufacturer INTEGER DEFAULT NULL, order_orderdetails_id INTEGER DEFAULT NULL, built_project_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, needs_review BOOLEAN NOT NULL, tags CLOB NOT NULL, mass DOUBLE PRECISION DEFAULT NULL, ipn VARCHAR(100) DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, visible BOOLEAN NOT NULL, favorite BOOLEAN NOT NULL, minamount DOUBLE PRECISION NOT NULL, manufacturer_product_url CLOB NOT NULL, manufacturer_product_number VARCHAR(255) NOT NULL, manufacturing_status VARCHAR(255) DEFAULT NULL, order_quantity INTEGER NOT NULL, manual_order BOOLEAN NOT NULL, provider_reference_provider_key VARCHAR(255) DEFAULT NULL, provider_reference_provider_id VARCHAR(255) DEFAULT NULL, provider_reference_provider_url VARCHAR(255) DEFAULT NULL, provider_reference_last_updated DATETIME DEFAULT NULL, CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES "categories" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES "footprints" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES "manufacturers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES "orderdetails" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO "parts" (id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated) SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated FROM __temp__parts'); + $this->addSql('DROP TABLE __temp__parts'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON "parts" (ipn)'); + $this->addSql('CREATE INDEX IDX_6940A7FEEA7100A1 ON "parts" (id_preview_attachment)'); + $this->addSql('CREATE INDEX IDX_6940A7FE5697F554 ON "parts" (id_category)'); + $this->addSql('CREATE INDEX IDX_6940A7FE7E371A10 ON "parts" (id_footprint)'); + $this->addSql('CREATE INDEX IDX_6940A7FE2626CEF9 ON "parts" (id_part_unit)'); + $this->addSql('CREATE INDEX IDX_6940A7FE1ECB93AE ON "parts" (id_manufacturer)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON "parts" (order_orderdetails_id)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON "parts" (built_project_id)'); + $this->addSql('CREATE INDEX parts_idx_datet_name_last_id_needs ON "parts" (datetime_added, name, last_modified, id, needs_review)'); + $this->addSql('CREATE INDEX parts_idx_name ON "parts" (name)'); + $this->addSql('CREATE INDEX parts_idx_ipn ON "parts" (ipn)'); + } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } +} diff --git a/migrations/Version20240427222442.php b/migrations/Version20240427222442.php new file mode 100644 index 00000000..92b2733d --- /dev/null +++ b/migrations/Version20240427222442.php @@ -0,0 +1,75 @@ +addSql('ALTER TABLE webauthn_keys ADD backup_eligible TINYINT(1) DEFAULT NULL, ADD backup_status TINYINT(1) DEFAULT NULL, ADD uv_initialized TINYINT(1) DEFAULT NULL, ADD last_time_used DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\''); + } + + public function mySQLDown(Schema $schema): void + { + $this->addSql('ALTER TABLE webauthn_keys DROP backup_eligible, DROP backup_status, DROP uv_initialized, DROP last_time_used'); + } + + public function sqLiteUp(Schema $schema): void + { + $this->addSql('CREATE TEMPORARY TABLE __temp__webauthn_keys AS SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added, other_ui FROM webauthn_keys'); + $this->addSql('DROP TABLE webauthn_keys'); + $this->addSql('CREATE TABLE webauthn_keys (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, public_key_credential_id CLOB NOT NULL --(DC2Type:base64) + , type VARCHAR(255) NOT NULL, transports CLOB NOT NULL --(DC2Type:array) + , attestation_type VARCHAR(255) NOT NULL, trust_path CLOB NOT NULL --(DC2Type:trust_path) + , aaguid CLOB NOT NULL --(DC2Type:aaguid) + , credential_public_key CLOB NOT NULL --(DC2Type:base64) + , user_handle VARCHAR(255) NOT NULL, counter INTEGER NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, other_ui CLOB DEFAULT NULL --(DC2Type:array) + , backup_eligible BOOLEAN DEFAULT NULL, backup_status BOOLEAN DEFAULT NULL, uv_initialized BOOLEAN DEFAULT NULL, last_time_used DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) + , CONSTRAINT FK_799FD143A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO webauthn_keys (id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added, other_ui) SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added, other_ui FROM __temp__webauthn_keys'); + $this->addSql('DROP TABLE __temp__webauthn_keys'); + $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); + } + + public function sqLiteDown(Schema $schema): void + { + $this->addSql('CREATE TEMPORARY TABLE __temp__webauthn_keys AS SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, other_ui, name, last_modified, datetime_added FROM webauthn_keys'); + $this->addSql('DROP TABLE webauthn_keys'); + $this->addSql('CREATE TABLE webauthn_keys (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, public_key_credential_id CLOB NOT NULL -- +(DC2Type:base64) + , type VARCHAR(255) NOT NULL, transports CLOB NOT NULL -- +(DC2Type:array) + , attestation_type VARCHAR(255) NOT NULL, trust_path CLOB NOT NULL -- +(DC2Type:trust_path) + , aaguid CLOB NOT NULL -- +(DC2Type:aaguid) + , credential_public_key CLOB NOT NULL -- +(DC2Type:base64) + , user_handle VARCHAR(255) NOT NULL, counter INTEGER NOT NULL, other_ui CLOB DEFAULT NULL -- +(DC2Type:array) + , name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_799FD143A76ED395 FOREIGN KEY (user_id) REFERENCES "users" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO webauthn_keys (id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, other_ui, name, last_modified, datetime_added) SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, other_ui, name, last_modified, datetime_added FROM __temp__webauthn_keys'); + $this->addSql('DROP TABLE __temp__webauthn_keys'); + $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); + } + + public function postgreSQLUp(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->warnIf(true, "Migration not needed for Postgres. Skipping..."); + } +} diff --git a/migrations/Version20240606203053.php b/migrations/Version20240606203053.php new file mode 100644 index 00000000..83370ad6 --- /dev/null +++ b/migrations/Version20240606203053.php @@ -0,0 +1,654 @@ +addSql("CREATE COLLATION numeric (provider = icu, locale = 'en-u-kn-true');"); + + $this->addSql('CREATE TABLE api_tokens (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, valid_until TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, token VARCHAR(68) NOT NULL, level SMALLINT NOT NULL, last_time_used TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, user_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_2CAD560E5F37A13B ON api_tokens (token)'); + $this->addSql('CREATE INDEX IDX_2CAD560EA76ED395 ON api_tokens (user_id)'); + $this->addSql('CREATE TABLE "attachment_types" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, filetype_filter TEXT NOT NULL, parent_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_EFAED719727ACA70 ON "attachment_types" (parent_id)'); + $this->addSql('CREATE INDEX IDX_EFAED719EA7100A1 ON "attachment_types" (id_preview_attachment)'); + $this->addSql('CREATE INDEX attachment_types_idx_name ON "attachment_types" (name)'); + $this->addSql('CREATE INDEX attachment_types_idx_parent_name ON "attachment_types" (parent_id, name)'); + $this->addSql('CREATE TABLE "attachments" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, original_filename VARCHAR(255) DEFAULT NULL, path VARCHAR(255) NOT NULL, show_in_table BOOLEAN NOT NULL, type_id INT NOT NULL, class_name VARCHAR(255) NOT NULL, element_id INT NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_47C4FAD6C54C8C93 ON "attachments" (type_id)'); + $this->addSql('CREATE INDEX IDX_47C4FAD61F1F2A24 ON "attachments" (element_id)'); + $this->addSql('CREATE INDEX attachments_idx_id_element_id_class_name ON "attachments" (id, element_id, class_name)'); + $this->addSql('CREATE INDEX attachments_idx_class_name_id ON "attachments" (class_name, id)'); + $this->addSql('CREATE INDEX attachment_name_idx ON "attachments" (name)'); + $this->addSql('CREATE INDEX attachment_element_idx ON "attachments" (class_name, element_id)'); + $this->addSql('CREATE TABLE "categories" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, partname_hint TEXT NOT NULL, partname_regex TEXT NOT NULL, disable_footprints BOOLEAN NOT NULL, disable_manufacturers BOOLEAN NOT NULL, disable_autodatasheets BOOLEAN NOT NULL, disable_properties BOOLEAN NOT NULL, default_description TEXT NOT NULL, default_comment TEXT NOT NULL, eda_info_reference_prefix VARCHAR(255) DEFAULT NULL, eda_info_invisible BOOLEAN DEFAULT NULL, eda_info_exclude_from_bom BOOLEAN DEFAULT NULL, eda_info_exclude_from_board BOOLEAN DEFAULT NULL, eda_info_exclude_from_sim BOOLEAN DEFAULT NULL, eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL, parent_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_3AF34668727ACA70 ON "categories" (parent_id)'); + $this->addSql('CREATE INDEX IDX_3AF34668EA7100A1 ON "categories" (id_preview_attachment)'); + $this->addSql('CREATE INDEX category_idx_name ON "categories" (name)'); + $this->addSql('CREATE INDEX category_idx_parent_name ON "categories" (parent_id, name)'); + $this->addSql('CREATE TABLE currencies (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, exchange_rate NUMERIC(11, 5) DEFAULT NULL, iso_code VARCHAR(255) NOT NULL, parent_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_37C44693727ACA70 ON currencies (parent_id)'); + $this->addSql('CREATE INDEX IDX_37C44693EA7100A1 ON currencies (id_preview_attachment)'); + $this->addSql('CREATE INDEX currency_idx_name ON currencies (name)'); + $this->addSql('CREATE INDEX currency_idx_parent_name ON currencies (parent_id, name)'); + $this->addSql('CREATE TABLE "footprints" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL, parent_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, id_footprint_3d INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_A34D68A2727ACA70 ON "footprints" (parent_id)'); + $this->addSql('CREATE INDEX IDX_A34D68A2EA7100A1 ON "footprints" (id_preview_attachment)'); + $this->addSql('CREATE INDEX IDX_A34D68A232A38C34 ON "footprints" (id_footprint_3d)'); + $this->addSql('CREATE INDEX footprint_idx_name ON "footprints" (name)'); + $this->addSql('CREATE INDEX footprint_idx_parent_name ON "footprints" (parent_id, name)'); + $this->addSql('CREATE TABLE "groups" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, enforce_2fa BOOLEAN NOT NULL, permissions_data JSON NOT NULL, parent_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_F06D3970727ACA70 ON "groups" (parent_id)'); + $this->addSql('CREATE INDEX IDX_F06D3970EA7100A1 ON "groups" (id_preview_attachment)'); + $this->addSql('CREATE INDEX group_idx_name ON "groups" (name)'); + $this->addSql('CREATE INDEX group_idx_parent_name ON "groups" (parent_id, name)'); + $this->addSql('CREATE TABLE label_profiles (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, show_in_dropdown BOOLEAN NOT NULL, options_width DOUBLE PRECISION NOT NULL, options_height DOUBLE PRECISION NOT NULL, options_barcode_type VARCHAR(255) NOT NULL, options_picture_type VARCHAR(255) NOT NULL, options_supported_element VARCHAR(255) NOT NULL, options_additional_css TEXT NOT NULL, options_lines_mode VARCHAR(255) NOT NULL, options_lines TEXT NOT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_C93E9CF5EA7100A1 ON label_profiles (id_preview_attachment)'); + $this->addSql('CREATE TABLE log (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, username VARCHAR(255) NOT NULL, datetime TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, level SMALLINT NOT NULL, target_id INT NOT NULL, target_type SMALLINT NOT NULL, extra JSON NOT NULL, id_user INT DEFAULT NULL, type SMALLINT NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_8F3F68C56B3CA4B ON log (id_user)'); + $this->addSql('CREATE INDEX log_idx_type ON log (type)'); + $this->addSql('CREATE INDEX log_idx_type_target ON log (type, target_type, target_id)'); + $this->addSql('CREATE INDEX log_idx_datetime ON log (datetime)'); + $this->addSql('CREATE TABLE "manufacturers" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(255) NOT NULL, auto_product_url VARCHAR(255) NOT NULL, parent_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_94565B12727ACA70 ON "manufacturers" (parent_id)'); + $this->addSql('CREATE INDEX IDX_94565B12EA7100A1 ON "manufacturers" (id_preview_attachment)'); + $this->addSql('CREATE INDEX manufacturer_name ON "manufacturers" (name)'); + $this->addSql('CREATE INDEX manufacturer_idx_parent_name ON "manufacturers" (parent_id, name)'); + $this->addSql('CREATE TABLE "measurement_units" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, unit VARCHAR(255) DEFAULT NULL, is_integer BOOLEAN NOT NULL, use_si_prefix BOOLEAN NOT NULL, parent_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_F5AF83CF727ACA70 ON "measurement_units" (parent_id)'); + $this->addSql('CREATE INDEX IDX_F5AF83CFEA7100A1 ON "measurement_units" (id_preview_attachment)'); + $this->addSql('CREATE INDEX unit_idx_name ON "measurement_units" (name)'); + $this->addSql('CREATE INDEX unit_idx_parent_name ON "measurement_units" (parent_id, name)'); + $this->addSql('CREATE TABLE oauth_tokens (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, token TEXT DEFAULT NULL, expires_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, refresh_token TEXT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE UNIQUE INDEX oauth_tokens_unique_name ON oauth_tokens (name)'); + $this->addSql('CREATE TABLE "orderdetails" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, supplierpartnr VARCHAR(255) NOT NULL, obsolete BOOLEAN NOT NULL, supplier_product_url TEXT NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, part_id INT NOT NULL, id_supplier INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_489AFCDC4CE34BEC ON "orderdetails" (part_id)'); + $this->addSql('CREATE INDEX IDX_489AFCDCCBF180EB ON "orderdetails" (id_supplier)'); + $this->addSql('CREATE INDEX orderdetails_supplier_part_nr ON "orderdetails" (supplierpartnr)'); + $this->addSql('CREATE TABLE parameters (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, symbol VARCHAR(255) NOT NULL, value_min DOUBLE PRECISION DEFAULT NULL, value_typical DOUBLE PRECISION DEFAULT NULL, value_max DOUBLE PRECISION DEFAULT NULL, unit VARCHAR(255) NOT NULL, value_text VARCHAR(255) NOT NULL, param_group VARCHAR(255) NOT NULL, type SMALLINT NOT NULL, element_id INT NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_69348FE1F1F2A24 ON parameters (element_id)'); + $this->addSql('CREATE INDEX parameter_name_idx ON parameters (name)'); + $this->addSql('CREATE INDEX parameter_group_idx ON parameters (param_group)'); + $this->addSql('CREATE INDEX parameter_type_element_idx ON parameters (type, element_id)'); + $this->addSql('CREATE TABLE part_association (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, type SMALLINT NOT NULL, other_type VARCHAR(255) DEFAULT NULL, comment TEXT DEFAULT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, owner_id INT NOT NULL, other_id INT NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_61B952E07E3C61F9 ON part_association (owner_id)'); + $this->addSql('CREATE INDEX IDX_61B952E0998D9879 ON part_association (other_id)'); + $this->addSql('CREATE TABLE part_lots (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, description TEXT NOT NULL, comment TEXT NOT NULL, expiration_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, instock_unknown BOOLEAN NOT NULL, amount DOUBLE PRECISION NOT NULL, needs_refill BOOLEAN NOT NULL, vendor_barcode VARCHAR(255) DEFAULT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, id_store_location INT DEFAULT NULL, id_part INT NOT NULL, id_owner INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_EBC8F9435D8F4B37 ON part_lots (id_store_location)'); + $this->addSql('CREATE INDEX IDX_EBC8F943C22F6CC4 ON part_lots (id_part)'); + $this->addSql('CREATE INDEX IDX_EBC8F94321E5A74C ON part_lots (id_owner)'); + $this->addSql('CREATE INDEX part_lots_idx_instock_un_expiration_id_part ON part_lots (instock_unknown, expiration_date, id_part)'); + $this->addSql('CREATE INDEX part_lots_idx_needs_refill ON part_lots (needs_refill)'); + $this->addSql('CREATE INDEX part_lots_idx_barcode ON part_lots (vendor_barcode)'); + $this->addSql('CREATE TABLE "parts" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, needs_review BOOLEAN NOT NULL, tags TEXT NOT NULL, mass DOUBLE PRECISION DEFAULT NULL, ipn VARCHAR(100) DEFAULT NULL, description TEXT NOT NULL, comment TEXT NOT NULL, visible BOOLEAN NOT NULL, favorite BOOLEAN NOT NULL, minamount DOUBLE PRECISION NOT NULL, manufacturer_product_url TEXT NOT NULL, manufacturer_product_number VARCHAR(255) NOT NULL, manufacturing_status VARCHAR(255) DEFAULT NULL, order_quantity INT NOT NULL, manual_order BOOLEAN NOT NULL, provider_reference_provider_key VARCHAR(255) DEFAULT NULL, provider_reference_provider_id VARCHAR(255) DEFAULT NULL, provider_reference_provider_url VARCHAR(255) DEFAULT NULL, provider_reference_last_updated TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, eda_info_reference_prefix VARCHAR(255) DEFAULT NULL, eda_info_value VARCHAR(255) DEFAULT NULL, eda_info_invisible BOOLEAN DEFAULT NULL, eda_info_exclude_from_bom BOOLEAN DEFAULT NULL, eda_info_exclude_from_board BOOLEAN DEFAULT NULL, eda_info_exclude_from_sim BOOLEAN DEFAULT NULL, eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL, eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, id_category INT NOT NULL, id_footprint INT DEFAULT NULL, id_part_unit INT DEFAULT NULL, id_manufacturer INT DEFAULT NULL, order_orderdetails_id INT DEFAULT NULL, built_project_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON "parts" (ipn)'); + $this->addSql('CREATE INDEX IDX_6940A7FEEA7100A1 ON "parts" (id_preview_attachment)'); + $this->addSql('CREATE INDEX IDX_6940A7FE5697F554 ON "parts" (id_category)'); + $this->addSql('CREATE INDEX IDX_6940A7FE7E371A10 ON "parts" (id_footprint)'); + $this->addSql('CREATE INDEX IDX_6940A7FE2626CEF9 ON "parts" (id_part_unit)'); + $this->addSql('CREATE INDEX IDX_6940A7FE1ECB93AE ON "parts" (id_manufacturer)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON "parts" (order_orderdetails_id)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON "parts" (built_project_id)'); + $this->addSql('CREATE INDEX parts_idx_datet_name_last_id_needs ON "parts" (datetime_added, name, last_modified, id, needs_review)'); + $this->addSql('CREATE INDEX parts_idx_name ON "parts" (name)'); + $this->addSql('CREATE INDEX parts_idx_ipn ON "parts" (ipn)'); + $this->addSql('CREATE TABLE "pricedetails" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, price NUMERIC(11, 5) NOT NULL, price_related_quantity DOUBLE PRECISION NOT NULL, min_discount_quantity DOUBLE PRECISION NOT NULL, manual_input BOOLEAN NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, id_currency INT DEFAULT NULL, orderdetails_id INT NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_C68C4459398D64AA ON "pricedetails" (id_currency)'); + $this->addSql('CREATE INDEX IDX_C68C44594A01DDC7 ON "pricedetails" (orderdetails_id)'); + $this->addSql('CREATE INDEX pricedetails_idx_min_discount ON "pricedetails" (min_discount_quantity)'); + $this->addSql('CREATE INDEX pricedetails_idx_min_discount_price_qty ON "pricedetails" (min_discount_quantity, price_related_quantity)'); + $this->addSql('CREATE TABLE project_bom_entries (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, quantity DOUBLE PRECISION NOT NULL, mountnames TEXT NOT NULL, name VARCHAR(255) DEFAULT NULL, comment TEXT NOT NULL, price NUMERIC(11, 5) DEFAULT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, id_device INT DEFAULT NULL, id_part INT DEFAULT NULL, price_currency_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_1AA2DD312F180363 ON project_bom_entries (id_device)'); + $this->addSql('CREATE INDEX IDX_1AA2DD31C22F6CC4 ON project_bom_entries (id_part)'); + $this->addSql('CREATE INDEX IDX_1AA2DD313FFDCD60 ON project_bom_entries (price_currency_id)'); + $this->addSql('CREATE TABLE projects (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, order_quantity INT NOT NULL, status VARCHAR(64) DEFAULT NULL, order_only_missing_parts BOOLEAN NOT NULL, description TEXT NOT NULL, parent_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_5C93B3A4727ACA70 ON projects (parent_id)'); + $this->addSql('CREATE INDEX IDX_5C93B3A4EA7100A1 ON projects (id_preview_attachment)'); + $this->addSql('CREATE TABLE "storelocations" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, is_full BOOLEAN NOT NULL, only_single_part BOOLEAN NOT NULL, limit_to_existing_parts BOOLEAN NOT NULL, part_owner_must_match BOOLEAN DEFAULT false NOT NULL, parent_id INT DEFAULT NULL, storage_type_id INT DEFAULT NULL, id_owner INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_7517020727ACA70 ON "storelocations" (parent_id)'); + $this->addSql('CREATE INDEX IDX_7517020B270BFF1 ON "storelocations" (storage_type_id)'); + $this->addSql('CREATE INDEX IDX_751702021E5A74C ON "storelocations" (id_owner)'); + $this->addSql('CREATE INDEX IDX_7517020EA7100A1 ON "storelocations" (id_preview_attachment)'); + $this->addSql('CREATE INDEX location_idx_name ON "storelocations" (name)'); + $this->addSql('CREATE INDEX location_idx_parent_name ON "storelocations" (parent_id, name)'); + $this->addSql('CREATE TABLE "suppliers" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, comment TEXT NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names TEXT DEFAULT NULL, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(255) NOT NULL, auto_product_url VARCHAR(255) NOT NULL, shipping_costs NUMERIC(11, 5) DEFAULT NULL, parent_id INT DEFAULT NULL, default_currency_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_AC28B95C727ACA70 ON "suppliers" (parent_id)'); + $this->addSql('CREATE INDEX IDX_AC28B95CECD792C0 ON "suppliers" (default_currency_id)'); + $this->addSql('CREATE INDEX IDX_AC28B95CEA7100A1 ON "suppliers" (id_preview_attachment)'); + $this->addSql('CREATE INDEX supplier_idx_name ON "suppliers" (name)'); + $this->addSql('CREATE INDEX supplier_idx_parent_name ON "suppliers" (parent_id, name)'); + $this->addSql('CREATE TABLE u2f_keys (key_handle VARCHAR(128) NOT NULL, public_key VARCHAR(255) NOT NULL, certificate TEXT NOT NULL, counter VARCHAR(255) NOT NULL, id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, user_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_4F4ADB4BA76ED395 ON u2f_keys (user_id)'); + $this->addSql('CREATE UNIQUE INDEX user_unique ON u2f_keys (user_id, key_handle)'); + $this->addSql('CREATE TABLE "users" (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, disabled BOOLEAN NOT NULL, config_theme VARCHAR(255) DEFAULT NULL, pw_reset_token VARCHAR(255) DEFAULT NULL, config_instock_comment_a TEXT NOT NULL, config_instock_comment_w TEXT NOT NULL, about_me TEXT NOT NULL, trusted_device_cookie_version INT NOT NULL, backup_codes JSON NOT NULL, google_authenticator_secret VARCHAR(255) DEFAULT NULL, config_timezone VARCHAR(255) DEFAULT NULL, config_language VARCHAR(255) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, show_email_on_profile BOOLEAN DEFAULT false NOT NULL, department VARCHAR(255) DEFAULT NULL, last_name VARCHAR(255) DEFAULT NULL, first_name VARCHAR(255) DEFAULT NULL, need_pw_change BOOLEAN NOT NULL, password VARCHAR(255) DEFAULT NULL, settings JSON NOT NULL, backup_codes_generation_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, pw_reset_expires TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, saml_user BOOLEAN NOT NULL, name VARCHAR(180) NOT NULL, permissions_data JSON NOT NULL, group_id INT DEFAULT NULL, id_preview_attachment INT DEFAULT NULL, currency_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E95E237E06 ON "users" (name)'); + $this->addSql('CREATE INDEX IDX_1483A5E9FE54D947 ON "users" (group_id)'); + $this->addSql('CREATE INDEX IDX_1483A5E9EA7100A1 ON "users" (id_preview_attachment)'); + $this->addSql('CREATE INDEX IDX_1483A5E938248176 ON "users" (currency_id)'); + $this->addSql('CREATE INDEX user_idx_username ON "users" (name)'); + $this->addSql('CREATE TABLE webauthn_keys (public_key_credential_id TEXT NOT NULL, type VARCHAR(255) NOT NULL, transports TEXT NOT NULL, attestation_type VARCHAR(255) NOT NULL, trust_path JSON NOT NULL, aaguid TEXT NOT NULL, credential_public_key TEXT NOT NULL, user_handle VARCHAR(255) NOT NULL, counter INT NOT NULL, other_ui TEXT DEFAULT NULL, backup_eligible BOOLEAN DEFAULT NULL, backup_status BOOLEAN DEFAULT NULL, uv_initialized BOOLEAN DEFAULT NULL, id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(255) NOT NULL, last_time_used TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, user_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); + $this->addSql('ALTER TABLE api_tokens ADD CONSTRAINT FK_2CAD560EA76ED395 FOREIGN KEY (user_id) REFERENCES "users" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "attachment_types" ADD CONSTRAINT FK_EFAED719727ACA70 FOREIGN KEY (parent_id) REFERENCES "attachment_types" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "attachment_types" ADD CONSTRAINT FK_EFAED719EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "attachments" ADD CONSTRAINT FK_47C4FAD6C54C8C93 FOREIGN KEY (type_id) REFERENCES "attachment_types" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "categories" ADD CONSTRAINT FK_3AF34668727ACA70 FOREIGN KEY (parent_id) REFERENCES "categories" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "categories" ADD CONSTRAINT FK_3AF34668EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE currencies ADD CONSTRAINT FK_37C44693727ACA70 FOREIGN KEY (parent_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE currencies ADD CONSTRAINT FK_37C44693EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "footprints" ADD CONSTRAINT FK_A34D68A2727ACA70 FOREIGN KEY (parent_id) REFERENCES "footprints" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "footprints" ADD CONSTRAINT FK_A34D68A2EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "footprints" ADD CONSTRAINT FK_A34D68A232A38C34 FOREIGN KEY (id_footprint_3d) REFERENCES "attachments" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "groups" ADD CONSTRAINT FK_F06D3970727ACA70 FOREIGN KEY (parent_id) REFERENCES "groups" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "groups" ADD CONSTRAINT FK_F06D3970EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE label_profiles ADD CONSTRAINT FK_C93E9CF5EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE log ADD CONSTRAINT FK_8F3F68C56B3CA4B FOREIGN KEY (id_user) REFERENCES "users" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "manufacturers" ADD CONSTRAINT FK_94565B12727ACA70 FOREIGN KEY (parent_id) REFERENCES "manufacturers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "manufacturers" ADD CONSTRAINT FK_94565B12EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "measurement_units" ADD CONSTRAINT FK_F5AF83CF727ACA70 FOREIGN KEY (parent_id) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "measurement_units" ADD CONSTRAINT FK_F5AF83CFEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "orderdetails" ADD CONSTRAINT FK_489AFCDC4CE34BEC FOREIGN KEY (part_id) REFERENCES "parts" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "orderdetails" ADD CONSTRAINT FK_489AFCDCCBF180EB FOREIGN KEY (id_supplier) REFERENCES "suppliers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE part_association ADD CONSTRAINT FK_61B952E07E3C61F9 FOREIGN KEY (owner_id) REFERENCES "parts" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE part_association ADD CONSTRAINT FK_61B952E0998D9879 FOREIGN KEY (other_id) REFERENCES "parts" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE part_lots ADD CONSTRAINT FK_EBC8F9435D8F4B37 FOREIGN KEY (id_store_location) REFERENCES "storelocations" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE part_lots ADD CONSTRAINT FK_EBC8F943C22F6CC4 FOREIGN KEY (id_part) REFERENCES "parts" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE part_lots ADD CONSTRAINT FK_EBC8F94321E5A74C FOREIGN KEY (id_owner) REFERENCES "users" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "parts" ADD CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "parts" ADD CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES "categories" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "parts" ADD CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES "footprints" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "parts" ADD CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "parts" ADD CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES "manufacturers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "parts" ADD CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES "orderdetails" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "parts" ADD CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "pricedetails" ADD CONSTRAINT FK_C68C4459398D64AA FOREIGN KEY (id_currency) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "pricedetails" ADD CONSTRAINT FK_C68C44594A01DDC7 FOREIGN KEY (orderdetails_id) REFERENCES "orderdetails" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE project_bom_entries ADD CONSTRAINT FK_1AA2DD312F180363 FOREIGN KEY (id_device) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE project_bom_entries ADD CONSTRAINT FK_1AA2DD31C22F6CC4 FOREIGN KEY (id_part) REFERENCES "parts" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE project_bom_entries ADD CONSTRAINT FK_1AA2DD313FFDCD60 FOREIGN KEY (price_currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE projects ADD CONSTRAINT FK_5C93B3A4727ACA70 FOREIGN KEY (parent_id) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE projects ADD CONSTRAINT FK_5C93B3A4EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "storelocations" ADD CONSTRAINT FK_7517020727ACA70 FOREIGN KEY (parent_id) REFERENCES "storelocations" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "storelocations" ADD CONSTRAINT FK_7517020B270BFF1 FOREIGN KEY (storage_type_id) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "storelocations" ADD CONSTRAINT FK_751702021E5A74C FOREIGN KEY (id_owner) REFERENCES "users" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "storelocations" ADD CONSTRAINT FK_7517020EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "suppliers" ADD CONSTRAINT FK_AC28B95C727ACA70 FOREIGN KEY (parent_id) REFERENCES "suppliers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "suppliers" ADD CONSTRAINT FK_AC28B95CECD792C0 FOREIGN KEY (default_currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "suppliers" ADD CONSTRAINT FK_AC28B95CEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE u2f_keys ADD CONSTRAINT FK_4F4ADB4BA76ED395 FOREIGN KEY (user_id) REFERENCES "users" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "users" ADD CONSTRAINT FK_1483A5E9FE54D947 FOREIGN KEY (group_id) REFERENCES "groups" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "users" ADD CONSTRAINT FK_1483A5E9EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE "users" ADD CONSTRAINT FK_1483A5E938248176 FOREIGN KEY (currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE webauthn_keys ADD CONSTRAINT FK_799FD143A76ED395 FOREIGN KEY (user_id) REFERENCES "users" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + + //Create the initial groups and users + //Retrieve the json representations of the presets + $admin = $this->getJSONPermDataFromPreset(PermissionPresetsHelper::PRESET_ADMIN); + $editor = $this->getJSONPermDataFromPreset(PermissionPresetsHelper::PRESET_EDITOR); + $read_only = $this->getJSONPermDataFromPreset(PermissionPresetsHelper::PRESET_READ_ONLY); + + + $sql = <<addSql($sql); + + //Increase the sequence for the groups, to avoid conflicts later + $this->addSql('SELECT setval(\'groups_id_seq\', 4)'); + + + $admin_pw = $this->getInitalAdminPW(); + + $sql = <<addSql($sql); + + //Increase the sequence for the users, to avoid conflicts later + $this->addSql('SELECT setval(\'users_id_seq\', 3)'); + } + + public function postgreSQLDown(Schema $schema): void + { + $this->addSql('CREATE SCHEMA public'); + $this->addSql('ALTER TABLE api_tokens DROP CONSTRAINT FK_2CAD560EA76ED395'); + $this->addSql('ALTER TABLE "attachment_types" DROP CONSTRAINT FK_EFAED719727ACA70'); + $this->addSql('ALTER TABLE "attachment_types" DROP CONSTRAINT FK_EFAED719EA7100A1'); + $this->addSql('ALTER TABLE "attachments" DROP CONSTRAINT FK_47C4FAD6C54C8C93'); + $this->addSql('ALTER TABLE "categories" DROP CONSTRAINT FK_3AF34668727ACA70'); + $this->addSql('ALTER TABLE "categories" DROP CONSTRAINT FK_3AF34668EA7100A1'); + $this->addSql('ALTER TABLE currencies DROP CONSTRAINT FK_37C44693727ACA70'); + $this->addSql('ALTER TABLE currencies DROP CONSTRAINT FK_37C44693EA7100A1'); + $this->addSql('ALTER TABLE "footprints" DROP CONSTRAINT FK_A34D68A2727ACA70'); + $this->addSql('ALTER TABLE "footprints" DROP CONSTRAINT FK_A34D68A2EA7100A1'); + $this->addSql('ALTER TABLE "footprints" DROP CONSTRAINT FK_A34D68A232A38C34'); + $this->addSql('ALTER TABLE "groups" DROP CONSTRAINT FK_F06D3970727ACA70'); + $this->addSql('ALTER TABLE "groups" DROP CONSTRAINT FK_F06D3970EA7100A1'); + $this->addSql('ALTER TABLE label_profiles DROP CONSTRAINT FK_C93E9CF5EA7100A1'); + $this->addSql('ALTER TABLE log DROP CONSTRAINT FK_8F3F68C56B3CA4B'); + $this->addSql('ALTER TABLE "manufacturers" DROP CONSTRAINT FK_94565B12727ACA70'); + $this->addSql('ALTER TABLE "manufacturers" DROP CONSTRAINT FK_94565B12EA7100A1'); + $this->addSql('ALTER TABLE "measurement_units" DROP CONSTRAINT FK_F5AF83CF727ACA70'); + $this->addSql('ALTER TABLE "measurement_units" DROP CONSTRAINT FK_F5AF83CFEA7100A1'); + $this->addSql('ALTER TABLE "orderdetails" DROP CONSTRAINT FK_489AFCDC4CE34BEC'); + $this->addSql('ALTER TABLE "orderdetails" DROP CONSTRAINT FK_489AFCDCCBF180EB'); + $this->addSql('ALTER TABLE part_association DROP CONSTRAINT FK_61B952E07E3C61F9'); + $this->addSql('ALTER TABLE part_association DROP CONSTRAINT FK_61B952E0998D9879'); + $this->addSql('ALTER TABLE part_lots DROP CONSTRAINT FK_EBC8F9435D8F4B37'); + $this->addSql('ALTER TABLE part_lots DROP CONSTRAINT FK_EBC8F943C22F6CC4'); + $this->addSql('ALTER TABLE part_lots DROP CONSTRAINT FK_EBC8F94321E5A74C'); + $this->addSql('ALTER TABLE "parts" DROP CONSTRAINT FK_6940A7FEEA7100A1'); + $this->addSql('ALTER TABLE "parts" DROP CONSTRAINT FK_6940A7FE5697F554'); + $this->addSql('ALTER TABLE "parts" DROP CONSTRAINT FK_6940A7FE7E371A10'); + $this->addSql('ALTER TABLE "parts" DROP CONSTRAINT FK_6940A7FE2626CEF9'); + $this->addSql('ALTER TABLE "parts" DROP CONSTRAINT FK_6940A7FE1ECB93AE'); + $this->addSql('ALTER TABLE "parts" DROP CONSTRAINT FK_6940A7FE81081E9B'); + $this->addSql('ALTER TABLE "parts" DROP CONSTRAINT FK_6940A7FEE8AE70D9'); + $this->addSql('ALTER TABLE "pricedetails" DROP CONSTRAINT FK_C68C4459398D64AA'); + $this->addSql('ALTER TABLE "pricedetails" DROP CONSTRAINT FK_C68C44594A01DDC7'); + $this->addSql('ALTER TABLE project_bom_entries DROP CONSTRAINT FK_1AA2DD312F180363'); + $this->addSql('ALTER TABLE project_bom_entries DROP CONSTRAINT FK_1AA2DD31C22F6CC4'); + $this->addSql('ALTER TABLE project_bom_entries DROP CONSTRAINT FK_1AA2DD313FFDCD60'); + $this->addSql('ALTER TABLE projects DROP CONSTRAINT FK_5C93B3A4727ACA70'); + $this->addSql('ALTER TABLE projects DROP CONSTRAINT FK_5C93B3A4EA7100A1'); + $this->addSql('ALTER TABLE "storelocations" DROP CONSTRAINT FK_7517020727ACA70'); + $this->addSql('ALTER TABLE "storelocations" DROP CONSTRAINT FK_7517020B270BFF1'); + $this->addSql('ALTER TABLE "storelocations" DROP CONSTRAINT FK_751702021E5A74C'); + $this->addSql('ALTER TABLE "storelocations" DROP CONSTRAINT FK_7517020EA7100A1'); + $this->addSql('ALTER TABLE "suppliers" DROP CONSTRAINT FK_AC28B95C727ACA70'); + $this->addSql('ALTER TABLE "suppliers" DROP CONSTRAINT FK_AC28B95CECD792C0'); + $this->addSql('ALTER TABLE "suppliers" DROP CONSTRAINT FK_AC28B95CEA7100A1'); + $this->addSql('ALTER TABLE u2f_keys DROP CONSTRAINT FK_4F4ADB4BA76ED395'); + $this->addSql('ALTER TABLE "users" DROP CONSTRAINT FK_1483A5E9FE54D947'); + $this->addSql('ALTER TABLE "users" DROP CONSTRAINT FK_1483A5E9EA7100A1'); + $this->addSql('ALTER TABLE "users" DROP CONSTRAINT FK_1483A5E938248176'); + $this->addSql('ALTER TABLE webauthn_keys DROP CONSTRAINT FK_799FD143A76ED395'); + $this->addSql('DROP TABLE api_tokens'); + $this->addSql('DROP TABLE "attachment_types"'); + $this->addSql('DROP TABLE "attachments"'); + $this->addSql('DROP TABLE "categories"'); + $this->addSql('DROP TABLE currencies'); + $this->addSql('DROP TABLE "footprints"'); + $this->addSql('DROP TABLE "groups"'); + $this->addSql('DROP TABLE label_profiles'); + $this->addSql('DROP TABLE log'); + $this->addSql('DROP TABLE "manufacturers"'); + $this->addSql('DROP TABLE "measurement_units"'); + $this->addSql('DROP TABLE oauth_tokens'); + $this->addSql('DROP TABLE "orderdetails"'); + $this->addSql('DROP TABLE parameters'); + $this->addSql('DROP TABLE part_association'); + $this->addSql('DROP TABLE part_lots'); + $this->addSql('DROP TABLE "parts"'); + $this->addSql('DROP TABLE "pricedetails"'); + $this->addSql('DROP TABLE project_bom_entries'); + $this->addSql('DROP TABLE projects'); + $this->addSql('DROP TABLE "storelocations"'); + $this->addSql('DROP TABLE "suppliers"'); + $this->addSql('DROP TABLE u2f_keys'); + $this->addSql('DROP TABLE "users"'); + $this->addSql('DROP TABLE webauthn_keys'); + } + + public function mySQLUp(Schema $schema): void + { + // this up() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE currencies CHANGE exchange_rate exchange_rate NUMERIC(11, 5) DEFAULT NULL'); + //Set empty JSON fields to "{}" to avoid issues with failing JSON validation + $this->addSql('UPDATE `groups` SET permissions_data = "{}" WHERE permissions_data = ""'); + $this->addSql('ALTER TABLE `groups` CHANGE permissions_data permissions_data JSON NOT NULL'); + //Set the empty JSON fields to "{}" to avoid issues with failing JSON validation + $this->addSql('UPDATE `log` SET extra = "{}" WHERE extra = ""'); + $this->addSql('ALTER TABLE `log` CHANGE level level TINYINT NOT NULL, CHANGE extra extra JSON NOT NULL'); + $this->addSql('ALTER TABLE oauth_tokens CHANGE expires_at expires_at DATETIME DEFAULT NULL'); + $this->addSql('ALTER TABLE pricedetails CHANGE price price NUMERIC(11, 5) NOT NULL'); + $this->addSql('ALTER TABLE project_bom_entries CHANGE price price NUMERIC(11, 5) DEFAULT NULL'); + $this->addSql('ALTER TABLE suppliers CHANGE shipping_costs shipping_costs NUMERIC(11, 5) DEFAULT NULL'); + //Set the empty JSON fields to "{}" to avoid issues with failing JSON validation + $this->addSql('UPDATE `users` SET settings = "{}" WHERE settings = ""'); + $this->addSql('UPDATE `users` SET backup_codes = "{}" WHERE backup_codes = ""'); + $this->addSql('UPDATE `users` SET permissions_data = "{}" WHERE permissions_data = ""'); + $this->addSql('ALTER TABLE `users` CHANGE settings settings JSON NOT NULL, CHANGE backup_codes backup_codes JSON NOT NULL, CHANGE permissions_data permissions_data JSON NOT NULL'); + $this->addSql('ALTER TABLE webauthn_keys CHANGE public_key_credential_id public_key_credential_id LONGTEXT NOT NULL, CHANGE transports transports LONGTEXT NOT NULL, CHANGE trust_path trust_path JSON NOT NULL, CHANGE aaguid aaguid TINYTEXT NOT NULL, CHANGE credential_public_key credential_public_key LONGTEXT NOT NULL, CHANGE other_ui other_ui LONGTEXT DEFAULT NULL, CHANGE last_time_used last_time_used DATETIME DEFAULT NULL'); + + // Add the natural sort emulation function to the database (based on this stackoverflow: https://stackoverflow.com/questions/153633/natural-sort-in-mysql/58154535#58154535) + //This version here is wrong, and will be replaced by the correct version in the next migration (we need to use nowdoc instead of heredoc, otherwise the slashes will be wrongly escaped!!) + $this->addSql(<<0, only the first n numbers in the input string will be converted for nat-sort (so strings that differ only after the first n numbers will not nat-sort amongst themselves). + Total sort-ordering is preserved, i.e. if s1!=s2, then NatSortKey(s1,n)!=NatSortKey(s2,n), for any given n. + Numbers may contain ',' as a thousands separator, and '.' as a decimal point. To reverse these (as appropriate for some European locales), the code would require modification. + Numbers preceded by '+' sort with numbers not preceded with either a '+' or '-' sign. + Negative numbers (preceded with '-') sort before positive numbers, but are sorted in order of ascending absolute value (so -7 sorts BEFORE -1001). + Numbers with leading zeros sort after the same number with no (or fewer) leading zeros. + Decimal-part-only numbers (like .75) are recognised, provided the decimal point is not immediately preceded by either another '.', or by a letter-type character. + Numbers with thousand separators sort after the same number without them. + Thousand separators are only recognised in numbers with no leading zeros that don't immediately follow a ',', and when they format the number correctly. + (When not recognised as a thousand separator, a ',' will instead be treated as separating two distinct numbers). + Version-number-like sequences consisting of 3 or more numbers separated by '.' are treated as distinct entities, and each component number will be nat-sorted. + The entire entity will sort after any number beginning with the first component (so e.g. 10.2.1 sorts after both 10 and 10.995, but before 11) + Note that The first number component in an entity like this is also permitted to contain thousand separators. + + To achieve this, numbers within the input string are prefixed and suffixed according to the following format: + - The number is prefixed by a 2-digit base-36 number representing its length, excluding leading zeros. If there is a decimal point, this length only includes the integer part of the number. + - A 3-character suffix is appended after the number (after the decimals if present). + - The first character is a space, or a '+' sign if the number was preceded by '+'. Any preceding '+' sign is also removed from the front of the number. + - This is followed by a 2-digit base-36 number that encodes the number of leading zeros and whether the number was expressed in comma-separated form (e.g. 1,000,000.25 vs 1000000.25) + - The value of this 2-digit number is: (number of leading zeros)*2 + (1 if comma-separated, 0 otherwise) + - For version number sequences, each component number has the prefix in front of it, and the separating dots are removed. + Then there is a single suffix that consists of a ' ' or '+' character, followed by a pair base-36 digits for each number component in the sequence. + + e.g. here is how some simple sample strings get converted: + 'Foo055' --> 'Foo0255 02' + 'Absolute zero is around -273 centigrade' --> 'Absolute zero is around -03273 00 centigrade' + 'The $1,000,000 prize' --> 'The $071000000 01 prize' + '+99.74 degrees' --> '0299.74+00 degrees' + 'I have 0 apples' --> 'I have 00 02 apples' + '.5 is the same value as 0000.5000' --> '00.5 00 is the same value as 00.5000 08' + 'MariaDB v10.3.0018' --> 'MariaDB v02100130218 000004' + + The restriction to numbers of up to 359 digits comes from the fact that the first character of the base-36 prefix MUST be a decimal digit, and so the highest permitted prefix value is '9Z' or 359 decimal. + The code could be modified to handle longer numbers by increasing the size of (both) the prefix and suffix. + A higher base could also be used (by replacing CONV() with a custom function), provided that the collation you are using sorts the "digits" of the base in the correct order, starting with 0123456789. + However, while the maximum number length may be increased this way, note that the technique this function uses is NOT applicable where strings may contain numbers of unlimited length. + + The function definition does not specify the charset or collation to be used for string-type parameters or variables: The default database charset & collation at the time the function is defined will be used. + This is to make the function code more portable. However, there are some important restrictions: + + - Collation is important here only when comparing (or storing) the output value from this function, but it MUST order the characters " +0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" in that order for the natural sort to work. + This is true for most collations, but not all of them, e.g. in Lithuanian 'Y' comes before 'J' (according to Wikipedia). + To adapt the function to work with such collations, replace CONV() in the function code with a custom function that emits "digits" above 9 that are characters ordered according to the collation in use. + + - For efficiency, the function code uses LENGTH() rather than CHAR_LENGTH() to measure the length of strings that consist only of digits 0-9, '.', and ',' characters. + This works for any single-byte charset, as well as any charset that maps standard ASCII characters to single bytes (such as utf8 or utf8mb4). + If using a charset that maps these characters to multiple bytes (such as, e.g. utf16 or utf32), you MUST replace all instances of LENGTH() in the function definition with CHAR_LENGTH() + + Length of the output: + + Each number converted adds 5 characters (2 prefix + 3 suffix) to the length of the string. n is the maximum count of numbers to convert; + This parameter is provided as a means to limit the maximum output length (to input length + 5*n). + If you do not require the total-ordering property, you could edit the code to use suffixes of 1 character (space or plus) only; this would reduce the maximum output length for any given n. + Since a string of length L has at most ((L+1) DIV 2) individual numbers in it (every 2nd character a digit), for n<=0 the maximum output length is (inputlength + 5*((inputlength+1) DIV 2)) + So for the current input length of 100, the maximum output length is 350. + If changing the input length, the output length must be modified according to the above formula. The DECLARE statements for x,y,r, and suf must also be modified, as the code comments indicate. + ****/ + + DECLARE x,y varchar(1000); # need to be same length as input s + DECLARE r varchar(3500) DEFAULT ''; # return value: needs to be same length as return type + DECLARE suf varchar(1001); # suffix for a number or version string. Must be (((inputlength+1) DIV 2)*2 + 1) chars to support version strings (e.g. '1.2.33.5'), though it's usually just 3 chars. (Max version string e.g. 1.2. ... .5 has ((length of input + 1) DIV 2) numeric components) + DECLARE i,j,k int UNSIGNED; + IF n<=0 THEN SET n := -1; END IF; # n<=0 means "process all numbers" + LOOP + SET i := REGEXP_INSTR(s,'\\d'); # find position of next digit + IF i=0 OR n=0 THEN RETURN CONCAT(r,s); END IF; # no more numbers to process -> we're done + SET n := n-1, suf := ' '; + IF i>1 THEN + IF SUBSTRING(s,i-1,1)='.' AND (i=2 OR SUBSTRING(s,i-2,1) RLIKE '[^.\\p{L}\\p{N}\\p{M}\\x{608}\\x{200C}\\x{200D}\\x{2100}-\\x{214F}\\x{24B6}-\\x{24E9}\\x{1F130}-\\x{1F149}\\x{1F150}-\\x{1F169}\\x{1F170}-\\x{1F189}]') AND (SUBSTRING(s,i) NOT RLIKE '^\\d++\\.\\d') THEN SET i:=i-1; END IF; # Allow decimal number (but not version string) to begin with a '.', provided preceding char is neither another '.', nor a member of the unicode character classes: "Alphabetic", "Letter", "Block=Letterlike Symbols" "Number", "Mark", "Join_Control" + IF i>1 AND SUBSTRING(s,i-1,1)='+' THEN SET suf := '+', j := i-1; ELSE SET j := i; END IF; # move any preceding '+' into the suffix, so equal numbers with and without preceding "+" signs sort together + SET r := CONCAT(r,SUBSTRING(s,1,j-1)); SET s = SUBSTRING(s,i); # add everything before the number to r and strip it from the start of s; preceding '+' is dropped (not included in either r or s) + END IF; + SET x := REGEXP_SUBSTR(s,IF(SUBSTRING(s,1,1) IN ('0','.') OR (SUBSTRING(r,-1)=',' AND suf=' '),'^\\d*+(?:\\.\\d++)*','^(?:[1-9]\\d{0,2}(?:,\\d{3}(?!\\d))++|\\d++)(?:\\.\\d++)*+')); # capture the number + following decimals (including multiple consecutive '.' sequences) + SET s := SUBSTRING(s,CHAR_LENGTH(x)+1); # NOTE: CHAR_LENGTH() can be safely used instead of CHAR_LENGTH() here & below PROVIDED we're using a charset that represents digits, ',' and '.' characters using single bytes (e.g. latin1, utf8) + SET i := INSTR(x,'.'); + IF i=0 THEN SET y := ''; ELSE SET y := SUBSTRING(x,i); SET x := SUBSTRING(x,1,i-1); END IF; # move any following decimals into y + SET i := CHAR_LENGTH(x); + SET x := REPLACE(x,',',''); + SET j := CHAR_LENGTH(x); + SET x := TRIM(LEADING '0' FROM x); # strip leading zeros + SET k := CHAR_LENGTH(x); + SET suf := CONCAT(suf,LPAD(CONV(LEAST((j-k)*2,1294) + IF(i=j,0,1),10,36),2,'0')); # (j-k)*2 + IF(i=j,0,1) = (count of leading zeros)*2 + (1 if there are thousands-separators, 0 otherwise) Note the first term is bounded to <= base-36 'ZY' as it must fit within 2 characters + SET i := LOCATE('.',y,2); + IF i=0 THEN + SET r := CONCAT(r,LPAD(CONV(LEAST(k,359),10,36),2,'0'),x,y,suf); # k = count of digits in number, bounded to be <= '9Z' base-36 + ELSE # encode a version number (like 3.12.707, etc) + SET r := CONCAT(r,LPAD(CONV(LEAST(k,359),10,36),2,'0'),x); # k = count of digits in number, bounded to be <= '9Z' base-36 + WHILE CHAR_LENGTH(y)>0 AND n!=0 DO + IF i=0 THEN SET x := SUBSTRING(y,2); SET y := ''; ELSE SET x := SUBSTRING(y,2,i-2); SET y := SUBSTRING(y,i); SET i := LOCATE('.',y,2); END IF; + SET j := CHAR_LENGTH(x); + SET x := TRIM(LEADING '0' FROM x); # strip leading zeros + SET k := CHAR_LENGTH(x); + SET r := CONCAT(r,LPAD(CONV(LEAST(k,359),10,36),2,'0'),x); # k = count of digits in number, bounded to be <= '9Z' base-36 + SET suf := CONCAT(suf,LPAD(CONV(LEAST((j-k)*2,1294),10,36),2,'0')); # (j-k)*2 = (count of leading zeros)*2, bounded to fit within 2 base-36 digits + SET n := n-1; + END WHILE; + SET r := CONCAT(r,y,suf); + END IF; + END LOOP; + END + EOD + ); + + } + + public function mySQLDown(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE currencies CHANGE exchange_rate exchange_rate NUMERIC(11, 5) DEFAULT NULL COMMENT \'(DC2Type:big_decimal)\''); + $this->addSql('ALTER TABLE `groups` CHANGE permissions_data permissions_data LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\''); + $this->addSql('ALTER TABLE log CHANGE level level TINYINT(1) NOT NULL COMMENT \'(DC2Type:tinyint)\', CHANGE extra extra LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\''); + $this->addSql('ALTER TABLE oauth_tokens CHANGE expires_at expires_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\''); + $this->addSql('ALTER TABLE `pricedetails` CHANGE price price NUMERIC(11, 5) NOT NULL COMMENT \'(DC2Type:big_decimal)\''); + $this->addSql('ALTER TABLE project_bom_entries CHANGE price price NUMERIC(11, 5) DEFAULT NULL COMMENT \'(DC2Type:big_decimal)\''); + $this->addSql('ALTER TABLE `suppliers` CHANGE shipping_costs shipping_costs NUMERIC(11, 5) DEFAULT NULL COMMENT \'(DC2Type:big_decimal)\''); + $this->addSql('ALTER TABLE `users` CHANGE backup_codes backup_codes LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', CHANGE settings settings LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', CHANGE permissions_data permissions_data LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\''); + $this->addSql('ALTER TABLE webauthn_keys CHANGE public_key_credential_id public_key_credential_id LONGTEXT NOT NULL COMMENT \'(DC2Type:base64)\', CHANGE transports transports LONGTEXT NOT NULL COMMENT \'(DC2Type:array)\', CHANGE trust_path trust_path LONGTEXT NOT NULL COMMENT \'(DC2Type:trust_path)\', CHANGE aaguid aaguid TINYTEXT NOT NULL COMMENT \'(DC2Type:aaguid)\', CHANGE credential_public_key credential_public_key LONGTEXT NOT NULL COMMENT \'(DC2Type:base64)\', CHANGE other_ui other_ui LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:array)\', CHANGE last_time_used last_time_used DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\''); + + //Drop custom function + $this->addSql('DROP FUNCTION IF EXISTS NatSortKey'); + } + + public function sqLiteUp(Schema $schema): void + { + $this->addSql('CREATE TEMPORARY TABLE __temp__currencies AS SELECT id, parent_id, id_preview_attachment, exchange_rate, iso_code, comment, not_selectable, name, last_modified, datetime_added, alternative_names FROM currencies'); + $this->addSql('DROP TABLE currencies'); + $this->addSql('CREATE TABLE currencies (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, exchange_rate NUMERIC(11, 5) DEFAULT NULL, iso_code VARCHAR(255) NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, alternative_names CLOB DEFAULT NULL, CONSTRAINT FK_37C44693727ACA70 FOREIGN KEY (parent_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_37C44693EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO currencies (id, parent_id, id_preview_attachment, exchange_rate, iso_code, comment, not_selectable, name, last_modified, datetime_added, alternative_names) SELECT id, parent_id, id_preview_attachment, exchange_rate, iso_code, comment, not_selectable, name, last_modified, datetime_added, alternative_names FROM __temp__currencies'); + $this->addSql('DROP TABLE __temp__currencies'); + $this->addSql('CREATE INDEX IDX_37C44693EA7100A1 ON currencies (id_preview_attachment)'); + $this->addSql('CREATE INDEX currency_idx_parent_name ON currencies (parent_id, name)'); + $this->addSql('CREATE INDEX currency_idx_name ON currencies (name)'); + $this->addSql('CREATE INDEX IDX_37C44693727ACA70 ON currencies (parent_id)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__groups AS SELECT id, parent_id, id_preview_attachment, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added, permissions_data, alternative_names FROM groups'); + $this->addSql('DROP TABLE groups'); + $this->addSql('CREATE TABLE groups (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, enforce_2fa BOOLEAN NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, permissions_data CLOB NOT NULL, alternative_names CLOB DEFAULT NULL, CONSTRAINT FK_F06D3970727ACA70 FOREIGN KEY (parent_id) REFERENCES groups (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_F06D3970EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO groups (id, parent_id, id_preview_attachment, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added, permissions_data, alternative_names) SELECT id, parent_id, id_preview_attachment, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added, permissions_data, alternative_names FROM __temp__groups'); + $this->addSql('DROP TABLE __temp__groups'); + $this->addSql('CREATE INDEX IDX_F06D3970EA7100A1 ON groups (id_preview_attachment)'); + $this->addSql('CREATE INDEX IDX_F06D3970727ACA70 ON groups (parent_id)'); + $this->addSql('CREATE INDEX group_idx_name ON groups (name)'); + $this->addSql('CREATE INDEX group_idx_parent_name ON groups (parent_id, name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__log AS SELECT id, id_user, datetime, level, target_id, target_type, extra, type, username FROM log'); + $this->addSql('DROP TABLE log'); + $this->addSql('CREATE TABLE log (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_user INTEGER DEFAULT NULL, datetime DATETIME NOT NULL, level SMALLINT NOT NULL, target_id INTEGER NOT NULL, target_type SMALLINT NOT NULL, extra CLOB NOT NULL, type SMALLINT NOT NULL, username VARCHAR(255) NOT NULL, CONSTRAINT FK_8F3F68C56B3CA4B FOREIGN KEY (id_user) REFERENCES users (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO log (id, id_user, datetime, level, target_id, target_type, extra, type, username) SELECT id, id_user, datetime, level, target_id, target_type, extra, type, username FROM __temp__log'); + $this->addSql('DROP TABLE __temp__log'); + $this->addSql('CREATE INDEX IDX_8F3F68C56B3CA4B ON log (id_user)'); + $this->addSql('CREATE INDEX log_idx_type ON log (type)'); + $this->addSql('CREATE INDEX log_idx_type_target ON log (type, target_type, target_id)'); + $this->addSql('CREATE INDEX log_idx_datetime ON log (datetime)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__oauth_tokens AS SELECT id, token, expires_at, refresh_token, name, last_modified, datetime_added FROM oauth_tokens'); + $this->addSql('DROP TABLE oauth_tokens'); + $this->addSql('CREATE TABLE oauth_tokens (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, token CLOB DEFAULT NULL, expires_at DATETIME DEFAULT NULL, refresh_token CLOB DEFAULT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL)'); + $this->addSql('INSERT INTO oauth_tokens (id, token, expires_at, refresh_token, name, last_modified, datetime_added) SELECT id, token, expires_at, refresh_token, name, last_modified, datetime_added FROM __temp__oauth_tokens'); + $this->addSql('DROP TABLE __temp__oauth_tokens'); + $this->addSql('CREATE UNIQUE INDEX oauth_tokens_unique_name ON oauth_tokens (name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__pricedetails AS SELECT id, id_currency, orderdetails_id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added FROM pricedetails'); + $this->addSql('DROP TABLE pricedetails'); + $this->addSql('CREATE TABLE pricedetails (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_currency INTEGER DEFAULT NULL, orderdetails_id INTEGER NOT NULL, price NUMERIC(11, 5) NOT NULL, price_related_quantity DOUBLE PRECISION NOT NULL, min_discount_quantity DOUBLE PRECISION NOT NULL, manual_input BOOLEAN NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_C68C4459398D64AA FOREIGN KEY (id_currency) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_C68C44594A01DDC7 FOREIGN KEY (orderdetails_id) REFERENCES orderdetails (id) ON UPDATE NO ACTION ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO pricedetails (id, id_currency, orderdetails_id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added) SELECT id, id_currency, orderdetails_id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added FROM __temp__pricedetails'); + $this->addSql('DROP TABLE __temp__pricedetails'); + $this->addSql('CREATE INDEX pricedetails_idx_min_discount_price_qty ON pricedetails (min_discount_quantity, price_related_quantity)'); + $this->addSql('CREATE INDEX pricedetails_idx_min_discount ON pricedetails (min_discount_quantity)'); + $this->addSql('CREATE INDEX IDX_C68C4459398D64AA ON pricedetails (id_currency)'); + $this->addSql('CREATE INDEX IDX_C68C44594A01DDC7 ON pricedetails (orderdetails_id)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__project_bom_entries AS SELECT id, id_device, id_part, price_currency_id, quantity, mountnames, name, comment, price, last_modified, datetime_added FROM project_bom_entries'); + $this->addSql('DROP TABLE project_bom_entries'); + $this->addSql('CREATE TABLE project_bom_entries (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_device INTEGER DEFAULT NULL, id_part INTEGER DEFAULT NULL, price_currency_id INTEGER DEFAULT NULL, quantity DOUBLE PRECISION NOT NULL, mountnames CLOB NOT NULL, name VARCHAR(255) DEFAULT NULL, comment CLOB NOT NULL, price NUMERIC(11, 5) DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_AFC547992F180363 FOREIGN KEY (id_device) REFERENCES projects (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AFC54799C22F6CC4 FOREIGN KEY (id_part) REFERENCES parts (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1AA2DD313FFDCD60 FOREIGN KEY (price_currency_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO project_bom_entries (id, id_device, id_part, price_currency_id, quantity, mountnames, name, comment, price, last_modified, datetime_added) SELECT id, id_device, id_part, price_currency_id, quantity, mountnames, name, comment, price, last_modified, datetime_added FROM __temp__project_bom_entries'); + $this->addSql('DROP TABLE __temp__project_bom_entries'); + $this->addSql('CREATE INDEX IDX_1AA2DD313FFDCD60 ON project_bom_entries (price_currency_id)'); + $this->addSql('CREATE INDEX IDX_1AA2DD312F180363 ON project_bom_entries (id_device)'); + $this->addSql('CREATE INDEX IDX_1AA2DD31C22F6CC4 ON project_bom_entries (id_part)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__suppliers AS SELECT id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added, alternative_names FROM suppliers'); + $this->addSql('DROP TABLE suppliers'); + $this->addSql('CREATE TABLE suppliers (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, default_currency_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, shipping_costs NUMERIC(11, 5) DEFAULT NULL, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(255) NOT NULL, auto_product_url VARCHAR(255) NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, alternative_names CLOB DEFAULT NULL, CONSTRAINT FK_AC28B95C727ACA70 FOREIGN KEY (parent_id) REFERENCES suppliers (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CECD792C0 FOREIGN KEY (default_currency_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO suppliers (id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added, alternative_names) SELECT id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added, alternative_names FROM __temp__suppliers'); + $this->addSql('DROP TABLE __temp__suppliers'); + $this->addSql('CREATE INDEX IDX_AC28B95CEA7100A1 ON suppliers (id_preview_attachment)'); + $this->addSql('CREATE INDEX supplier_idx_parent_name ON suppliers (parent_id, name)'); + $this->addSql('CREATE INDEX supplier_idx_name ON suppliers (name)'); + $this->addSql('CREATE INDEX IDX_AC28B95C727ACA70 ON suppliers (parent_id)'); + $this->addSql('CREATE INDEX IDX_AC28B95CECD792C0 ON suppliers (default_currency_id)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__users AS SELECT id, group_id, currency_id, id_preview_attachment, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added, permissions_data, saml_user, about_me, show_email_on_profile FROM users'); + $this->addSql('DROP TABLE users'); + $this->addSql('CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, group_id INTEGER DEFAULT NULL, currency_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, disabled BOOLEAN NOT NULL, config_theme VARCHAR(255) DEFAULT NULL, pw_reset_token VARCHAR(255) DEFAULT NULL, config_instock_comment_a CLOB NOT NULL, config_instock_comment_w CLOB NOT NULL, trusted_device_cookie_version INTEGER NOT NULL, backup_codes CLOB NOT NULL, google_authenticator_secret VARCHAR(255) DEFAULT NULL, config_timezone VARCHAR(255) DEFAULT NULL, config_language VARCHAR(255) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, department VARCHAR(255) DEFAULT NULL, last_name VARCHAR(255) DEFAULT NULL, first_name VARCHAR(255) DEFAULT NULL, need_pw_change BOOLEAN NOT NULL, password VARCHAR(255) DEFAULT NULL, name VARCHAR(180) NOT NULL, settings CLOB NOT NULL, backup_codes_generation_date DATETIME DEFAULT NULL, pw_reset_expires DATETIME DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, permissions_data CLOB NOT NULL, saml_user BOOLEAN NOT NULL, about_me CLOB NOT NULL, show_email_on_profile BOOLEAN DEFAULT 0 NOT NULL, CONSTRAINT FK_1483A5E9FE54D947 FOREIGN KEY (group_id) REFERENCES groups (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E938248176 FOREIGN KEY (currency_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E9EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO users (id, group_id, currency_id, id_preview_attachment, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added, permissions_data, saml_user, about_me, show_email_on_profile) SELECT id, group_id, currency_id, id_preview_attachment, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added, permissions_data, saml_user, about_me, show_email_on_profile FROM __temp__users'); + $this->addSql('DROP TABLE __temp__users'); + $this->addSql('CREATE INDEX IDX_1483A5E9EA7100A1 ON users (id_preview_attachment)'); + $this->addSql('CREATE INDEX IDX_1483A5E938248176 ON users (currency_id)'); + $this->addSql('CREATE INDEX IDX_1483A5E9FE54D947 ON users (group_id)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E95E237E06 ON users (name)'); + $this->addSql('CREATE INDEX user_idx_username ON users (name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__webauthn_keys AS SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added, other_ui, backup_eligible, backup_status, uv_initialized, last_time_used FROM webauthn_keys'); + $this->addSql('DROP TABLE webauthn_keys'); + $this->addSql('CREATE TABLE webauthn_keys (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, public_key_credential_id CLOB NOT NULL, type VARCHAR(255) NOT NULL, transports CLOB NOT NULL, attestation_type VARCHAR(255) NOT NULL, trust_path CLOB NOT NULL, aaguid CLOB NOT NULL, credential_public_key CLOB NOT NULL, user_handle VARCHAR(255) NOT NULL, counter INTEGER NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, other_ui CLOB DEFAULT NULL, backup_eligible BOOLEAN DEFAULT NULL, backup_status BOOLEAN DEFAULT NULL, uv_initialized BOOLEAN DEFAULT NULL, last_time_used DATETIME DEFAULT NULL, CONSTRAINT FK_799FD143A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO webauthn_keys (id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added, other_ui, backup_eligible, backup_status, uv_initialized, last_time_used) SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added, other_ui, backup_eligible, backup_status, uv_initialized, last_time_used FROM __temp__webauthn_keys'); + $this->addSql('DROP TABLE __temp__webauthn_keys'); + $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); + } + + public function sqLiteDown(Schema $schema): void + { + $this->addSql('CREATE TEMPORARY TABLE __temp__currencies AS SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, exchange_rate, iso_code, parent_id, id_preview_attachment FROM currencies'); + $this->addSql('DROP TABLE currencies'); + $this->addSql('CREATE TABLE currencies (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names CLOB DEFAULT NULL, exchange_rate NUMERIC(11, 5) DEFAULT NULL --(DC2Type:big_decimal) + , iso_code VARCHAR(255) NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, CONSTRAINT FK_37C44693727ACA70 FOREIGN KEY (parent_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_37C44693EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO currencies (id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, exchange_rate, iso_code, parent_id, id_preview_attachment) SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, exchange_rate, iso_code, parent_id, id_preview_attachment FROM __temp__currencies'); + $this->addSql('DROP TABLE __temp__currencies'); + $this->addSql('CREATE INDEX IDX_37C44693727ACA70 ON currencies (parent_id)'); + $this->addSql('CREATE INDEX IDX_37C44693EA7100A1 ON currencies (id_preview_attachment)'); + $this->addSql('CREATE INDEX currency_idx_name ON currencies (name)'); + $this->addSql('CREATE INDEX currency_idx_parent_name ON currencies (parent_id, name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__groups AS SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, enforce_2fa, permissions_data, parent_id, id_preview_attachment FROM "groups"'); + $this->addSql('DROP TABLE "groups"'); + $this->addSql('CREATE TABLE "groups" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names CLOB DEFAULT NULL, enforce_2fa BOOLEAN NOT NULL, permissions_data CLOB NOT NULL --(DC2Type:json) + , parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, CONSTRAINT FK_F06D3970727ACA70 FOREIGN KEY (parent_id) REFERENCES "groups" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_F06D3970EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO "groups" (id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, enforce_2fa, permissions_data, parent_id, id_preview_attachment) SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, enforce_2fa, permissions_data, parent_id, id_preview_attachment FROM __temp__groups'); + $this->addSql('DROP TABLE __temp__groups'); + $this->addSql('CREATE INDEX IDX_F06D3970727ACA70 ON "groups" (parent_id)'); + $this->addSql('CREATE INDEX IDX_F06D3970EA7100A1 ON "groups" (id_preview_attachment)'); + $this->addSql('CREATE INDEX group_idx_name ON "groups" (name)'); + $this->addSql('CREATE INDEX group_idx_parent_name ON "groups" (parent_id, name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__log AS SELECT id, username, datetime, level, target_id, target_type, extra, id_user, type FROM log'); + $this->addSql('DROP TABLE log'); + $this->addSql('CREATE TABLE log (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, username VARCHAR(255) NOT NULL, datetime DATETIME NOT NULL, level BOOLEAN NOT NULL --(DC2Type:tinyint) + , target_id INTEGER NOT NULL, target_type SMALLINT NOT NULL, extra CLOB NOT NULL --(DC2Type:json) + , id_user INTEGER DEFAULT NULL, type SMALLINT NOT NULL, CONSTRAINT FK_8F3F68C56B3CA4B FOREIGN KEY (id_user) REFERENCES "users" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO log (id, username, datetime, level, target_id, target_type, extra, id_user, type) SELECT id, username, datetime, level, target_id, target_type, extra, id_user, type FROM __temp__log'); + $this->addSql('DROP TABLE __temp__log'); + $this->addSql('CREATE INDEX IDX_8F3F68C56B3CA4B ON log (id_user)'); + $this->addSql('CREATE INDEX log_idx_type ON log (type)'); + $this->addSql('CREATE INDEX log_idx_type_target ON log (type, target_type, target_id)'); + $this->addSql('CREATE INDEX log_idx_datetime ON log (datetime)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__oauth_tokens AS SELECT id, name, last_modified, datetime_added, token, expires_at, refresh_token FROM oauth_tokens'); + $this->addSql('DROP TABLE oauth_tokens'); + $this->addSql('CREATE TABLE oauth_tokens (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, token CLOB DEFAULT NULL, expires_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) + , refresh_token CLOB DEFAULT NULL)'); + $this->addSql('INSERT INTO oauth_tokens (id, name, last_modified, datetime_added, token, expires_at, refresh_token) SELECT id, name, last_modified, datetime_added, token, expires_at, refresh_token FROM __temp__oauth_tokens'); + $this->addSql('DROP TABLE __temp__oauth_tokens'); + $this->addSql('CREATE UNIQUE INDEX oauth_tokens_unique_name ON oauth_tokens (name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__pricedetails AS SELECT id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added, id_currency, orderdetails_id FROM "pricedetails"'); + $this->addSql('DROP TABLE "pricedetails"'); + $this->addSql('CREATE TABLE "pricedetails" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, price NUMERIC(11, 5) NOT NULL --(DC2Type:big_decimal) + , price_related_quantity DOUBLE PRECISION NOT NULL, min_discount_quantity DOUBLE PRECISION NOT NULL, manual_input BOOLEAN NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, id_currency INTEGER DEFAULT NULL, orderdetails_id INTEGER NOT NULL, CONSTRAINT FK_C68C4459398D64AA FOREIGN KEY (id_currency) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_C68C44594A01DDC7 FOREIGN KEY (orderdetails_id) REFERENCES "orderdetails" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO "pricedetails" (id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added, id_currency, orderdetails_id) SELECT id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added, id_currency, orderdetails_id FROM __temp__pricedetails'); + $this->addSql('DROP TABLE __temp__pricedetails'); + $this->addSql('CREATE INDEX IDX_C68C4459398D64AA ON "pricedetails" (id_currency)'); + $this->addSql('CREATE INDEX IDX_C68C44594A01DDC7 ON "pricedetails" (orderdetails_id)'); + $this->addSql('CREATE INDEX pricedetails_idx_min_discount ON "pricedetails" (min_discount_quantity)'); + $this->addSql('CREATE INDEX pricedetails_idx_min_discount_price_qty ON "pricedetails" (min_discount_quantity, price_related_quantity)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__project_bom_entries AS SELECT id, quantity, mountnames, name, comment, price, last_modified, datetime_added, id_device, id_part, price_currency_id FROM project_bom_entries'); + $this->addSql('DROP TABLE project_bom_entries'); + $this->addSql('CREATE TABLE project_bom_entries (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, quantity DOUBLE PRECISION NOT NULL, mountnames CLOB NOT NULL, name VARCHAR(255) DEFAULT NULL, comment CLOB NOT NULL, price NUMERIC(11, 5) DEFAULT NULL --(DC2Type:big_decimal) + , last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, id_device INTEGER DEFAULT NULL, id_part INTEGER DEFAULT NULL, price_currency_id INTEGER DEFAULT NULL, CONSTRAINT FK_1AA2DD312F180363 FOREIGN KEY (id_device) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1AA2DD31C22F6CC4 FOREIGN KEY (id_part) REFERENCES "parts" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1AA2DD313FFDCD60 FOREIGN KEY (price_currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO project_bom_entries (id, quantity, mountnames, name, comment, price, last_modified, datetime_added, id_device, id_part, price_currency_id) SELECT id, quantity, mountnames, name, comment, price, last_modified, datetime_added, id_device, id_part, price_currency_id FROM __temp__project_bom_entries'); + $this->addSql('DROP TABLE __temp__project_bom_entries'); + $this->addSql('CREATE INDEX IDX_1AA2DD312F180363 ON project_bom_entries (id_device)'); + $this->addSql('CREATE INDEX IDX_1AA2DD31C22F6CC4 ON project_bom_entries (id_part)'); + $this->addSql('CREATE INDEX IDX_1AA2DD313FFDCD60 ON project_bom_entries (price_currency_id)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__suppliers AS SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, address, phone_number, fax_number, email_address, website, auto_product_url, shipping_costs, parent_id, default_currency_id, id_preview_attachment FROM "suppliers"'); + $this->addSql('DROP TABLE "suppliers"'); + $this->addSql('CREATE TABLE "suppliers" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names CLOB DEFAULT NULL, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(255) NOT NULL, auto_product_url VARCHAR(255) NOT NULL, shipping_costs NUMERIC(11, 5) DEFAULT NULL --(DC2Type:big_decimal) + , parent_id INTEGER DEFAULT NULL, default_currency_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, CONSTRAINT FK_AC28B95C727ACA70 FOREIGN KEY (parent_id) REFERENCES "suppliers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CECD792C0 FOREIGN KEY (default_currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO "suppliers" (id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, address, phone_number, fax_number, email_address, website, auto_product_url, shipping_costs, parent_id, default_currency_id, id_preview_attachment) SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, address, phone_number, fax_number, email_address, website, auto_product_url, shipping_costs, parent_id, default_currency_id, id_preview_attachment FROM __temp__suppliers'); + $this->addSql('DROP TABLE __temp__suppliers'); + $this->addSql('CREATE INDEX IDX_AC28B95C727ACA70 ON "suppliers" (parent_id)'); + $this->addSql('CREATE INDEX IDX_AC28B95CECD792C0 ON "suppliers" (default_currency_id)'); + $this->addSql('CREATE INDEX IDX_AC28B95CEA7100A1 ON "suppliers" (id_preview_attachment)'); + $this->addSql('CREATE INDEX supplier_idx_name ON "suppliers" (name)'); + $this->addSql('CREATE INDEX supplier_idx_parent_name ON "suppliers" (parent_id, name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__users AS SELECT id, last_modified, datetime_added, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, about_me, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, show_email_on_profile, department, last_name, first_name, need_pw_change, password, settings, backup_codes_generation_date, pw_reset_expires, saml_user, name, permissions_data, group_id, id_preview_attachment, currency_id FROM "users"'); + $this->addSql('DROP TABLE "users"'); + $this->addSql('CREATE TABLE "users" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, disabled BOOLEAN NOT NULL, config_theme VARCHAR(255) DEFAULT NULL, pw_reset_token VARCHAR(255) DEFAULT NULL, config_instock_comment_a CLOB NOT NULL, config_instock_comment_w CLOB NOT NULL, about_me CLOB NOT NULL, trusted_device_cookie_version INTEGER NOT NULL, backup_codes CLOB NOT NULL --(DC2Type:json) + , google_authenticator_secret VARCHAR(255) DEFAULT NULL, config_timezone VARCHAR(255) DEFAULT NULL, config_language VARCHAR(255) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, show_email_on_profile BOOLEAN DEFAULT 0 NOT NULL, department VARCHAR(255) DEFAULT NULL, last_name VARCHAR(255) DEFAULT NULL, first_name VARCHAR(255) DEFAULT NULL, need_pw_change BOOLEAN NOT NULL, password VARCHAR(255) DEFAULT NULL, settings CLOB NOT NULL --(DC2Type:json) + , backup_codes_generation_date DATETIME DEFAULT NULL, pw_reset_expires DATETIME DEFAULT NULL, saml_user BOOLEAN NOT NULL, name VARCHAR(180) NOT NULL, permissions_data CLOB NOT NULL --(DC2Type:json) + , group_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, currency_id INTEGER DEFAULT NULL, CONSTRAINT FK_1483A5E9FE54D947 FOREIGN KEY (group_id) REFERENCES "groups" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E9EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E938248176 FOREIGN KEY (currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO "users" (id, last_modified, datetime_added, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, about_me, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, show_email_on_profile, department, last_name, first_name, need_pw_change, password, settings, backup_codes_generation_date, pw_reset_expires, saml_user, name, permissions_data, group_id, id_preview_attachment, currency_id) SELECT id, last_modified, datetime_added, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, about_me, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, show_email_on_profile, department, last_name, first_name, need_pw_change, password, settings, backup_codes_generation_date, pw_reset_expires, saml_user, name, permissions_data, group_id, id_preview_attachment, currency_id FROM __temp__users'); + $this->addSql('DROP TABLE __temp__users'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E95E237E06 ON "users" (name)'); + $this->addSql('CREATE INDEX IDX_1483A5E9FE54D947 ON "users" (group_id)'); + $this->addSql('CREATE INDEX IDX_1483A5E9EA7100A1 ON "users" (id_preview_attachment)'); + $this->addSql('CREATE INDEX IDX_1483A5E938248176 ON "users" (currency_id)'); + $this->addSql('CREATE INDEX user_idx_username ON "users" (name)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__webauthn_keys AS SELECT public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, other_ui, backup_eligible, backup_status, uv_initialized, id, name, last_time_used, last_modified, datetime_added, user_id FROM webauthn_keys'); + $this->addSql('DROP TABLE webauthn_keys'); + $this->addSql('CREATE TABLE webauthn_keys (public_key_credential_id CLOB NOT NULL --(DC2Type:base64) + , type VARCHAR(255) NOT NULL, transports CLOB NOT NULL --(DC2Type:array) + , attestation_type VARCHAR(255) NOT NULL, trust_path CLOB NOT NULL --(DC2Type:trust_path) + , aaguid CLOB NOT NULL --(DC2Type:aaguid) + , credential_public_key CLOB NOT NULL --(DC2Type:base64) + , user_handle VARCHAR(255) NOT NULL, counter INTEGER NOT NULL, other_ui CLOB DEFAULT NULL --(DC2Type:array) + , backup_eligible BOOLEAN DEFAULT NULL, backup_status BOOLEAN DEFAULT NULL, uv_initialized BOOLEAN DEFAULT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, last_time_used DATETIME DEFAULT NULL --(DC2Type:datetime_immutable) + , last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, user_id INTEGER DEFAULT NULL, CONSTRAINT FK_799FD143A76ED395 FOREIGN KEY (user_id) REFERENCES "users" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO webauthn_keys (public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, other_ui, backup_eligible, backup_status, uv_initialized, id, name, last_time_used, last_modified, datetime_added, user_id) SELECT public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, other_ui, backup_eligible, backup_status, uv_initialized, id, name, last_time_used, last_modified, datetime_added, user_id FROM __temp__webauthn_keys'); + $this->addSql('DROP TABLE __temp__webauthn_keys'); + $this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)'); + } +} diff --git a/migrations/Version20240728145604.php b/migrations/Version20240728145604.php new file mode 100644 index 00000000..42309d70 --- /dev/null +++ b/migrations/Version20240728145604.php @@ -0,0 +1,165 @@ +addSql('DROP FUNCTION IF EXISTS NatSortKey'); + + //The difference to the original function is the correct length of the suf variable and correct escaping + //We now use heredoc syntax to avoid escaping issues with the \ (which resulted in "range out of order in character class"). + $this->addSql(<<<'EOD' + CREATE DEFINER=CURRENT_USER FUNCTION `NatSortKey`(`s` VARCHAR(1000) CHARSET utf8mb4, `n` INT) RETURNS varchar(3500) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci + DETERMINISTIC + SQL SECURITY INVOKER + BEGIN + /**** + Converts numbers in the input string s into a format such that sorting results in a nat-sort. + Numbers of up to 359 digits (before the decimal point, if one is present) are supported. Sort results are undefined if the input string contains numbers longer than this. + For n>0, only the first n numbers in the input string will be converted for nat-sort (so strings that differ only after the first n numbers will not nat-sort amongst themselves). + Total sort-ordering is preserved, i.e. if s1!=s2, then NatSortKey(s1,n)!=NatSortKey(s2,n), for any given n. + Numbers may contain ',' as a thousands separator, and '.' as a decimal point. To reverse these (as appropriate for some European locales), the code would require modification. + Numbers preceded by '+' sort with numbers not preceded with either a '+' or '-' sign. + Negative numbers (preceded with '-') sort before positive numbers, but are sorted in order of ascending absolute value (so -7 sorts BEFORE -1001). + Numbers with leading zeros sort after the same number with no (or fewer) leading zeros. + Decimal-part-only numbers (like .75) are recognised, provided the decimal point is not immediately preceded by either another '.', or by a letter-type character. + Numbers with thousand separators sort after the same number without them. + Thousand separators are only recognised in numbers with no leading zeros that don't immediately follow a ',', and when they format the number correctly. + (When not recognised as a thousand separator, a ',' will instead be treated as separating two distinct numbers). + Version-number-like sequences consisting of 3 or more numbers separated by '.' are treated as distinct entities, and each component number will be nat-sorted. + The entire entity will sort after any number beginning with the first component (so e.g. 10.2.1 sorts after both 10 and 10.995, but before 11) + Note that The first number component in an entity like this is also permitted to contain thousand separators. + + To achieve this, numbers within the input string are prefixed and suffixed according to the following format: + - The number is prefixed by a 2-digit base-36 number representing its length, excluding leading zeros. If there is a decimal point, this length only includes the integer part of the number. + - A 3-character suffix is appended after the number (after the decimals if present). + - The first character is a space, or a '+' sign if the number was preceded by '+'. Any preceding '+' sign is also removed from the front of the number. + - This is followed by a 2-digit base-36 number that encodes the number of leading zeros and whether the number was expressed in comma-separated form (e.g. 1,000,000.25 vs 1000000.25) + - The value of this 2-digit number is: (number of leading zeros)*2 + (1 if comma-separated, 0 otherwise) + - For version number sequences, each component number has the prefix in front of it, and the separating dots are removed. + Then there is a single suffix that consists of a ' ' or '+' character, followed by a pair base-36 digits for each number component in the sequence. + + e.g. here is how some simple sample strings get converted: + 'Foo055' --> 'Foo0255 02' + 'Absolute zero is around -273 centigrade' --> 'Absolute zero is around -03273 00 centigrade' + 'The $1,000,000 prize' --> 'The $071000000 01 prize' + '+99.74 degrees' --> '0299.74+00 degrees' + 'I have 0 apples' --> 'I have 00 02 apples' + '.5 is the same value as 0000.5000' --> '00.5 00 is the same value as 00.5000 08' + 'MariaDB v10.3.0018' --> 'MariaDB v02100130218 000004' + + The restriction to numbers of up to 359 digits comes from the fact that the first character of the base-36 prefix MUST be a decimal digit, and so the highest permitted prefix value is '9Z' or 359 decimal. + The code could be modified to handle longer numbers by increasing the size of (both) the prefix and suffix. + A higher base could also be used (by replacing CONV() with a custom function), provided that the collation you are using sorts the "digits" of the base in the correct order, starting with 0123456789. + However, while the maximum number length may be increased this way, note that the technique this function uses is NOT applicable where strings may contain numbers of unlimited length. + + The function definition does not specify the charset or collation to be used for string-type parameters or variables: The default database charset & collation at the time the function is defined will be used. + This is to make the function code more portable. However, there are some important restrictions: + + - Collation is important here only when comparing (or storing) the output value from this function, but it MUST order the characters " +0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" in that order for the natural sort to work. + This is true for most collations, but not all of them, e.g. in Lithuanian 'Y' comes before 'J' (according to Wikipedia). + To adapt the function to work with such collations, replace CONV() in the function code with a custom function that emits "digits" above 9 that are characters ordered according to the collation in use. + + - For efficiency, the function code uses LENGTH() rather than CHAR_LENGTH() to measure the length of strings that consist only of digits 0-9, '.', and ',' characters. + This works for any single-byte charset, as well as any charset that maps standard ASCII characters to single bytes (such as utf8 or utf8mb4). + If using a charset that maps these characters to multiple bytes (such as, e.g. utf16 or utf32), you MUST replace all instances of LENGTH() in the function definition with CHAR_LENGTH() + + Length of the output: + + Each number converted adds 5 characters (2 prefix + 3 suffix) to the length of the string. n is the maximum count of numbers to convert; + This parameter is provided as a means to limit the maximum output length (to input length + 5*n). + If you do not require the total-ordering property, you could edit the code to use suffixes of 1 character (space or plus) only; this would reduce the maximum output length for any given n. + Since a string of length L has at most ((L+1) DIV 2) individual numbers in it (every 2nd character a digit), for n<=0 the maximum output length is (inputlength + 5*((inputlength+1) DIV 2)) + So for the current input length of 100, the maximum output length is 350. + If changing the input length, the output length must be modified according to the above formula. The DECLARE statements for x,y,r, and suf must also be modified, as the code comments indicate. + ****/ + + DECLARE x,y varchar(1000); # need to be same length as input s + DECLARE r varchar(3500) DEFAULT ''; # return value: needs to be same length as return type + DECLARE suf varchar(1001); # suffix for a number or version string. Must be (((inputlength+1) DIV 2)*2 + 1) chars to support version strings (e.g. '1.2.33.5'), though it's usually just 3 chars. (Max version string e.g. 1.2. ... .5 has ((length of input + 1) DIV 2) numeric components) + DECLARE i,j,k int UNSIGNED; + IF n<=0 THEN SET n := -1; END IF; # n<=0 means "process all numbers" + LOOP + SET i := REGEXP_INSTR(s,'\\d'); # find position of next digit + IF i=0 OR n=0 THEN RETURN CONCAT(r,s); END IF; # no more numbers to process -> we're done + SET n := n-1, suf := ' '; + IF i>1 THEN + IF SUBSTRING(s,i-1,1)='.' AND (i=2 OR SUBSTRING(s,i-2,1) RLIKE '[^.\\p{L}\\p{N}\\p{M}\\x{608}\\x{200C}\\x{200D}\\x{2100}-\\x{214F}\\x{24B6}-\\x{24E9}\\x{1F130}-\\x{1F149}\\x{1F150}-\\x{1F169}\\x{1F170}-\\x{1F189}]') AND (SUBSTRING(s,i) NOT RLIKE '^\\d++\\.\\d') THEN SET i:=i-1; END IF; # Allow decimal number (but not version string) to begin with a '.', provided preceding char is neither another '.', nor a member of the unicode character classes: "Alphabetic", "Letter", "Block=Letterlike Symbols" "Number", "Mark", "Join_Control" + IF i>1 AND SUBSTRING(s,i-1,1)='+' THEN SET suf := '+', j := i-1; ELSE SET j := i; END IF; # move any preceding '+' into the suffix, so equal numbers with and without preceding "+" signs sort together + SET r := CONCAT(r,SUBSTRING(s,1,j-1)); SET s = SUBSTRING(s,i); # add everything before the number to r and strip it from the start of s; preceding '+' is dropped (not included in either r or s) + END IF; + SET x := REGEXP_SUBSTR(s,IF(SUBSTRING(s,1,1) IN ('0','.') OR (SUBSTRING(r,-1)=',' AND suf=' '),'^\\d*+(?:\\.\\d++)*','^(?:[1-9]\\d{0,2}(?:,\\d{3}(?!\\d))++|\\d++)(?:\\.\\d++)*+')); # capture the number + following decimals (including multiple consecutive '.' sequences) + SET s := SUBSTRING(s,CHAR_LENGTH(x)+1); # NOTE: CHAR_LENGTH() can be safely used instead of CHAR_LENGTH() here & below PROVIDED we're using a charset that represents digits, ',' and '.' characters using single bytes (e.g. latin1, utf8) + SET i := INSTR(x,'.'); + IF i=0 THEN SET y := ''; ELSE SET y := SUBSTRING(x,i); SET x := SUBSTRING(x,1,i-1); END IF; # move any following decimals into y + SET i := CHAR_LENGTH(x); + SET x := REPLACE(x,',',''); + SET j := CHAR_LENGTH(x); + SET x := TRIM(LEADING '0' FROM x); # strip leading zeros + SET k := CHAR_LENGTH(x); + SET suf := CONCAT(suf,LPAD(CONV(LEAST((j-k)*2,1294) + IF(i=j,0,1),10,36),2,'0')); # (j-k)*2 + IF(i=j,0,1) = (count of leading zeros)*2 + (1 if there are thousands-separators, 0 otherwise) Note the first term is bounded to <= base-36 'ZY' as it must fit within 2 characters + SET i := LOCATE('.',y,2); + IF i=0 THEN + SET r := CONCAT(r,LPAD(CONV(LEAST(k,359),10,36),2,'0'),x,y,suf); # k = count of digits in number, bounded to be <= '9Z' base-36 + ELSE # encode a version number (like 3.12.707, etc) + SET r := CONCAT(r,LPAD(CONV(LEAST(k,359),10,36),2,'0'),x); # k = count of digits in number, bounded to be <= '9Z' base-36 + WHILE CHAR_LENGTH(y)>0 AND n!=0 DO + IF i=0 THEN SET x := SUBSTRING(y,2); SET y := ''; ELSE SET x := SUBSTRING(y,2,i-2); SET y := SUBSTRING(y,i); SET i := LOCATE('.',y,2); END IF; + SET j := CHAR_LENGTH(x); + SET x := TRIM(LEADING '0' FROM x); # strip leading zeros + SET k := CHAR_LENGTH(x); + SET r := CONCAT(r,LPAD(CONV(LEAST(k,359),10,36),2,'0'),x); # k = count of digits in number, bounded to be <= '9Z' base-36 + SET suf := CONCAT(suf,LPAD(CONV(LEAST((j-k)*2,1294),10,36),2,'0')); # (j-k)*2 = (count of leading zeros)*2, bounded to fit within 2 base-36 digits + SET n := n-1; + END WHILE; + SET r := CONCAT(r,y,suf); + END IF; + END LOOP; + END + EOD + ); + } + + public function mySQLDown(Schema $schema): void + { + //Not needed + } + + public function sqLiteUp(Schema $schema): void + { + //Not needed + } + + public function sqLiteDown(Schema $schema): void + { + //Not needed + } + + public function postgreSQLUp(Schema $schema): void + { + //Not needed + } + + public function postgreSQLDown(Schema $schema): void + { + //Not needed + } +} diff --git a/migrations/Version20250220215048.php b/migrations/Version20250220215048.php new file mode 100644 index 00000000..90a73eb1 --- /dev/null +++ b/migrations/Version20250220215048.php @@ -0,0 +1,42 @@ +addSql('ALTER TABLE attachments ADD internal_path VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE attachments ADD external_path VARCHAR(255) DEFAULT NULL'); + + //Copy the data from path to external_path and remove the path column + $this->addSql('UPDATE attachments SET external_path=path'); + $this->addSql('ALTER TABLE attachments DROP COLUMN path'); + + + $this->addSql('UPDATE attachments SET internal_path=external_path WHERE external_path LIKE \'#%MEDIA#%%\' ESCAPE \'#\''); + $this->addSql('UPDATE attachments SET internal_path=external_path WHERE external_path LIKE \'#%BASE#%%\' ESCAPE \'#\''); + $this->addSql('UPDATE attachments SET internal_path=external_path WHERE external_path LIKE \'#%SECURE#%%\' ESCAPE \'#\''); + $this->addSql('UPDATE attachments SET internal_path=external_path WHERE external_path LIKE \'#%FOOTPRINTS#%%\' ESCAPE \'#\''); + $this->addSql('UPDATE attachments SET internal_path=external_path WHERE external_path LIKE \'#%FOOTPRINTS3D#%%\' ESCAPE \'#\''); + $this->addSql('UPDATE attachments SET external_path=NULL WHERE internal_path IS NOT NULL'); + } + + public function down(Schema $schema): void + { + $this->addSql('UPDATE attachments SET external_path=internal_path WHERE internal_path IS NOT NULL'); + $this->addSql('ALTER TABLE attachments DROP COLUMN internal_path'); + $this->addSql('ALTER TABLE attachments RENAME COLUMN external_path TO path'); + } +} diff --git a/migrations/Version20250222165240.php b/migrations/Version20250222165240.php new file mode 100644 index 00000000..57cd3970 --- /dev/null +++ b/migrations/Version20250222165240.php @@ -0,0 +1,31 @@ +addSql("UPDATE attachments SET class_name = 'Part' WHERE class_name = 'PartDB\Part'"); + $this->addSql("UPDATE attachments SET class_name = 'Device' WHERE class_name = 'PartDB\Device'"); + } + + public function down(Schema $schema): void + { + //No down required, as the new format can also be read by older Part-DB version + } +} diff --git a/package.json b/package.json index 2e328866..38656c72 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,12 @@ "@babel/preset-env": "^7.19.4", "@fortawesome/fontawesome-free": "^6.1.1", "@hotwired/stimulus": "^3.0.0", - "@hotwired/turbo": "^7.0.1", + "@hotwired/turbo": "^8.0.1", "@popperjs/core": "^2.10.2", "@symfony/stimulus-bridge": "^3.2.0", "@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets", "@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/assets", - "@symfony/webpack-encore": "^4.1.0", + "@symfony/webpack-encore": "^5.0.0", "bootstrap": "^5.1.3", "core-js": "^3.23.0", "intl-messageformat": "^10.2.5", @@ -18,7 +18,7 @@ "regenerator-runtime": "^0.13.9", "webpack": "^5.74.0", "webpack-bundle-analyzer": "^4.3.0", - "webpack-cli": "^4.10.0", + "webpack-cli": "^5.1.0", "webpack-notifier": "^1.15.0" }, "license": "AGPL-3.0-or-later", @@ -30,70 +30,75 @@ "build": "encore production --progress" }, "dependencies": { - "@ckeditor/ckeditor5-alignment": "^38.0.1", - "@ckeditor/ckeditor5-autoformat": "^38.0.1", - "@ckeditor/ckeditor5-basic-styles": "^38.0.1", - "@ckeditor/ckeditor5-block-quote": "^38.0.1", - "@ckeditor/ckeditor5-code-block": "^38.0.1", - "@ckeditor/ckeditor5-dev-utils": "^38.0.1", - "@ckeditor/ckeditor5-dev-webpack-plugin": "^31.1.13", - "@ckeditor/ckeditor5-editor-classic": "^38.0.1", - "@ckeditor/ckeditor5-essentials": "^38.0.1", - "@ckeditor/ckeditor5-find-and-replace": "^38.0.1", - "@ckeditor/ckeditor5-font": "^38.0.1", - "@ckeditor/ckeditor5-heading": "^38.0.1", - "@ckeditor/ckeditor5-highlight": "^38.0.1", - "@ckeditor/ckeditor5-horizontal-line": "^38.0.1", - "@ckeditor/ckeditor5-html-embed": "^38.0.1", - "@ckeditor/ckeditor5-html-support": "^38.0.1", - "@ckeditor/ckeditor5-image": "^38.0.1", - "@ckeditor/ckeditor5-indent": "^38.0.1", - "@ckeditor/ckeditor5-link": "^38.0.1", - "@ckeditor/ckeditor5-list": "^38.0.1", - "@ckeditor/ckeditor5-markdown-gfm": "^38.0.1", - "@ckeditor/ckeditor5-media-embed": "^38.0.1", - "@ckeditor/ckeditor5-paragraph": "^38.0.1", - "@ckeditor/ckeditor5-paste-from-office": "^38.0.1", - "@ckeditor/ckeditor5-remove-format": "^38.0.1", - "@ckeditor/ckeditor5-source-editing": "^38.0.1", - "@ckeditor/ckeditor5-special-characters": "^38.0.1", - "@ckeditor/ckeditor5-table": "^38.0.1", - "@ckeditor/ckeditor5-theme-lark": "^38.0.1", - "@ckeditor/ckeditor5-upload": "^38.0.1", - "@ckeditor/ckeditor5-watchdog": "^38.0.1", - "@ckeditor/ckeditor5-word-count": "^38.0.1", + "@algolia/autocomplete-js": "^1.17.0", + "@algolia/autocomplete-plugin-recent-searches": "^1.17.0", + "@algolia/autocomplete-theme-classic": "^1.17.0", + "@ckeditor/ckeditor5-alignment": "^44.0.0", + "@ckeditor/ckeditor5-autoformat": "^44.0.0", + "@ckeditor/ckeditor5-basic-styles": "^44.0.0", + "@ckeditor/ckeditor5-block-quote": "^44.0.0", + "@ckeditor/ckeditor5-code-block": "^44.0.0", + "@ckeditor/ckeditor5-dev-translations": "^43.0.1", + "@ckeditor/ckeditor5-dev-utils": "^43.0.1", + "@ckeditor/ckeditor5-editor-classic": "^44.0.0", + "@ckeditor/ckeditor5-essentials": "^44.0.0", + "@ckeditor/ckeditor5-find-and-replace": "^44.0.0", + "@ckeditor/ckeditor5-font": "^44.0.0", + "@ckeditor/ckeditor5-heading": "^44.0.0", + "@ckeditor/ckeditor5-highlight": "^44.0.0", + "@ckeditor/ckeditor5-horizontal-line": "^44.0.0", + "@ckeditor/ckeditor5-html-embed": "^44.0.0", + "@ckeditor/ckeditor5-html-support": "^44.0.0", + "@ckeditor/ckeditor5-image": "^44.0.0", + "@ckeditor/ckeditor5-indent": "^44.0.0", + "@ckeditor/ckeditor5-link": "^44.0.0", + "@ckeditor/ckeditor5-list": "^44.0.0", + "@ckeditor/ckeditor5-markdown-gfm": "^44.0.0", + "@ckeditor/ckeditor5-media-embed": "^44.0.0", + "@ckeditor/ckeditor5-paragraph": "^44.0.0", + "@ckeditor/ckeditor5-paste-from-office": "^44.0.0", + "@ckeditor/ckeditor5-remove-format": "^44.0.0", + "@ckeditor/ckeditor5-source-editing": "^44.0.0", + "@ckeditor/ckeditor5-special-characters": "^44.0.0", + "@ckeditor/ckeditor5-table": "^44.0.0", + "@ckeditor/ckeditor5-theme-lark": "^44.0.0", + "@ckeditor/ckeditor5-upload": "^44.0.0", + "@ckeditor/ckeditor5-watchdog": "^44.0.0", + "@ckeditor/ckeditor5-word-count": "^44.0.0", "@jbtronics/bs-treeview": "^1.0.1", + "@part-db/html5-qrcode": "^3.1.0", "@zxcvbn-ts/core": "^3.0.2", "@zxcvbn-ts/language-common": "^3.0.3", "@zxcvbn-ts/language-de": "^3.0.1", "@zxcvbn-ts/language-en": "^3.0.1", "@zxcvbn-ts/language-fr": "^3.0.1", "@zxcvbn-ts/language-ja": "^3.0.1", + "barcode-detector": "^2.3.1", "bootbox": "^6.0.0", "bootswatch": "^5.1.3", "bs-custom-file-input": "^1.3.4", "clipboard": "^2.0.4", - "compression-webpack-plugin": "^10.0.0", - "datatables.net-bs5": "^1.10.20", - "datatables.net-buttons-bs5": "^2.2.2", - "datatables.net-colreorder-bs5": "^1.5.1", - "datatables.net-fixedheader-bs5": "^3.1.5", - "datatables.net-responsive-bs5": "^2.2.3", - "datatables.net-select-bs5": "^1.2.7", + "compression-webpack-plugin": "^11.1.0", + "datatables.net": "^2.0.0", + "datatables.net-bs5": "^2.0.0", + "datatables.net-buttons-bs5": "^3.0.0", + "datatables.net-colreorder-bs5": "^2.0.0", + "datatables.net-fixedheader-bs5": "^4.0.0", + "datatables.net-responsive-bs5": "^3.0.0", + "datatables.net-select-bs5": "^2.0.0", "dompurify": "^3.0.3", - "emoji.json": "^14.0.0", - "exports-loader": "^3.0.0", - "html5-qrcode": "^2.2.1", + "emoji.json": "^15.0.0", + "exports-loader": "^5.0.0", "json-formatter-js": "^2.3.4", "jszip": "^3.2.0", "katex": "^0.16.0", - "marked": "^5.1.0", - "marked-gfm-heading-id": "^3.0.4", + "marked": "^15.0.4", + "marked-gfm-heading-id": "^4.1.1", "marked-mangle": "^1.0.1", "pdfmake": "^0.2.2", "stimulus-use": "^0.52.0", "tom-select": "^2.1.0", "ts-loader": "^9.2.6", - "typescript": "^4.0.2" + "typescript": "^5.7.2" } } diff --git a/phpstan.neon b/phpstan.dist.neon similarity index 57% rename from phpstan.neon rename to phpstan.dist.neon index db118378..fc7b3524 100644 --- a/phpstan.neon +++ b/phpstan.dist.neon @@ -10,6 +10,9 @@ parameters: - src/DataTables/Adapter/* - src/Configuration/* - src/Doctrine/Purger/* + - src/DataTables/Adapters/TwoStepORMAdapter.php + - src/Form/Fixes/* + - src/Translation/Fixes/* @@ -17,16 +20,15 @@ parameters: treatPhpDocTypesAsCertain: false symfony: - container_xml_path: '%rootDir%/../../../var/cache/dev/App_KernelDevDebugContainer.xml' + containerXmlPath: '%rootDir%/../../../var/cache/dev/App_KernelDevDebugContainer.xml' + + doctrine: + objectManagerLoader: tests/object-manager.php + allowNullablePropertyForRequiredField: true checkUninitializedProperties: true - checkFunctionNameCase: true - - checkAlwaysTrueInstanceof: false - checkAlwaysTrueCheckTypeFunctionCall: false - checkAlwaysTrueStrictComparison: false - reportAlwaysTrueInLastCondition: false + checkFunctionNameCase: false reportMaybesInPropertyPhpDocTypes: false reportMaybesInMethodSignatures: false @@ -36,20 +38,26 @@ parameters: booleansInConditions: false uselessCast: false requireParentConstructorCall: true - disallowedConstructs: false overwriteVariablesWithLoop: false closureUsesThis: false matchingInheritedMethodNames: true numericOperandsInArithmeticOperators: true - strictCalls: true switchConditionsMatchingType: false noVariableVariables: false + disallowedEmpty: false + disallowedShortTernary: false ignoreErrors: # Ignore errors caused by complex mapping with AbstractStructuralDBElement - '#AbstractStructuralDBElement does not have a field named \$parent#' - - '#AbstractStructuralDBElement does not have a field named \$name#' + #- '#AbstractStructuralDBElement does not have a field named \$name#' # Ignore errors related to the use of the ParametersTrait in Part entity - '#expects .*PartParameter, .*AbstractParameter given.#' - - '#Part::getParameters\(\) should return .*AbstractParameter#' \ No newline at end of file + - '#Part::getParameters\(\) should return .*AbstractParameter#' + + # Ignore doctrine type mapping mismatch + - '#Property .* type mapping mismatch: property can contain .* but database expects .*#' + + # Ignore error of unused WithPermPresetsTrait, as it is used in the migrations which are not analyzed by Phpstan + - '#Trait App\\Migration\\WithPermPresetsTrait is used zero times and is not analysed#' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 59622803..7ee7596f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,7 +13,7 @@ - + diff --git a/psalm.xml b/psalm.xml deleted file mode 100644 index 872169ac..00000000 --- a/psalm.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/.htaccess b/public/.htaccess index ee3b5450..bfaab5de 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -118,3 +118,10 @@ DirectoryIndex index.php # RedirectTemp cannot be used instead + +# Set Content-Security-Policy for svg files (and compressed variants), to block embedded javascript in there + + + Header set Content-Security-Policy "default-src 'self'; script-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none';" + + \ No newline at end of file diff --git a/public/img/default_avatar.png b/public/img/default_avatar.png deleted file mode 100644 index 17d6a106..00000000 Binary files a/public/img/default_avatar.png and /dev/null differ diff --git a/public/img/default_avatar.svg b/public/img/default_avatar.svg new file mode 100644 index 00000000..4586017b --- /dev/null +++ b/public/img/default_avatar.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/kicad/footprints.txt b/public/kicad/footprints.txt new file mode 100644 index 00000000..8f0f944c --- /dev/null +++ b/public/kicad/footprints.txt @@ -0,0 +1,14213 @@ +# This file contains all the KiCad footprints available in the official library +# Generated by footprints.sh +# on Sun Feb 16 21:19:56 CET 2025 +Audio_Module:Reverb_BTDR-1H +Audio_Module:Reverb_BTDR-1V +Battery:BatteryClip_Keystone_54_D16-19mm +Battery:BatteryHolder_Bulgin_BX0036_1xC +Battery:BatteryHolder_ComfortableElectronic_CH273-2450_1x2450 +Battery:BatteryHolder_Eagle_12BH611-GR +Battery:BatteryHolder_Keystone_103_1x20mm +Battery:BatteryHolder_Keystone_1042_1x18650 +Battery:BatteryHolder_Keystone_104_1x23mm +Battery:BatteryHolder_Keystone_1057_1x2032 +Battery:BatteryHolder_Keystone_1058_1x2032 +Battery:BatteryHolder_Keystone_105_1x2430 +Battery:BatteryHolder_Keystone_1060_1x2032 +Battery:BatteryHolder_Keystone_106_1x20mm +Battery:BatteryHolder_Keystone_107_1x23mm +Battery:BatteryHolder_Keystone_2460_1xAA +Battery:BatteryHolder_Keystone_2462_2xAA +Battery:BatteryHolder_Keystone_2466_1xAAA +Battery:BatteryHolder_Keystone_2468_2xAAA +Battery:BatteryHolder_Keystone_2479_3xAAA +Battery:BatteryHolder_Keystone_2993 +Battery:BatteryHolder_Keystone_2998_1x6.8mm +Battery:BatteryHolder_Keystone_3000_1x12mm +Battery:BatteryHolder_Keystone_3001_1x12mm +Battery:BatteryHolder_Keystone_3002_1x2032 +Battery:BatteryHolder_Keystone_3008_1x2450 +Battery:BatteryHolder_Keystone_3009_1x2450 +Battery:BatteryHolder_Keystone_3034_1x20mm +Battery:BatteryHolder_Keystone_500 +Battery:BatteryHolder_Keystone_590 +Battery:BatteryHolder_LINX_BAT-HLD-012-SMT +Battery:BatteryHolder_MPD_BA9VPC_1xPP3 +Battery:BatteryHolder_MPD_BC12AAPC_2xAA +Battery:BatteryHolder_MPD_BC2003_1x2032 +Battery:BatteryHolder_MPD_BC2AAPC_2xAA +Battery:BatteryHolder_MPD_BH-18650-PC2 +Battery:BatteryHolder_Multicomp_BC-2001_1x2032 +Battery:BatteryHolder_MYOUNG_BS-07-A1BJ001_CR2032 +Battery:BatteryHolder_Renata_SMTU2032-LF_1x2032 +Battery:BatteryHolder_Seiko_MS621F +Battery:BatteryHolder_TruPower_BH-331P_3xAA +Battery:Battery_CR1225 +Battery:Battery_Panasonic_CR1025-VSK_Vertical_CircularHoles +Battery:Battery_Panasonic_CR1220-VCN_Vertical_CircularHoles +Battery:Battery_Panasonic_CR1632-V1AN_Vertical_CircularHoles +Battery:Battery_Panasonic_CR2025-V1AK_Vertical_CircularHoles +Battery:Battery_Panasonic_CR2032-HFN_Horizontal_CircularHoles +Battery:Battery_Panasonic_CR2032-VS1N_Vertical_CircularHoles +Battery:Battery_Panasonic_CR2354-VCN_Vertical_CircularHoles +Battery:Battery_Panasonic_CR2450-VAN_Vertical_CircularHoles +Battery:Battery_Panasonic_CR2477-VCN_Vertical_CircularHoles +Battery:Battery_Panasonic_CR3032-VCN_Vertical_CircularHoles +Button_Switch_Keyboard:SW_Cherry_MX_1.00u_PCB +Button_Switch_Keyboard:SW_Cherry_MX_1.00u_Plate +Button_Switch_Keyboard:SW_Cherry_MX_1.25u_PCB +Button_Switch_Keyboard:SW_Cherry_MX_1.25u_Plate +Button_Switch_Keyboard:SW_Cherry_MX_1.50u_PCB +Button_Switch_Keyboard:SW_Cherry_MX_1.50u_Plate +Button_Switch_Keyboard:SW_Cherry_MX_1.75u_PCB +Button_Switch_Keyboard:SW_Cherry_MX_1.75u_Plate +Button_Switch_Keyboard:SW_Cherry_MX_2.00u_PCB +Button_Switch_Keyboard:SW_Cherry_MX_2.00u_Plate +Button_Switch_Keyboard:SW_Cherry_MX_2.00u_Vertical_PCB +Button_Switch_Keyboard:SW_Cherry_MX_2.00u_Vertical_Plate +Button_Switch_Keyboard:SW_Cherry_MX_2.25u_PCB +Button_Switch_Keyboard:SW_Cherry_MX_2.25u_Plate +Button_Switch_Keyboard:SW_Cherry_MX_2.75u_PCB +Button_Switch_Keyboard:SW_Cherry_MX_2.75u_Plate +Button_Switch_Keyboard:SW_Cherry_MX_6.25u_PCB +Button_Switch_Keyboard:SW_Cherry_MX_6.25u_Plate +Button_Switch_Keyboard:SW_Cherry_MX_ISOEnter_PCB +Button_Switch_Keyboard:SW_Cherry_MX_ISOEnter_Plate +Button_Switch_Keyboard:SW_Matias_1.00u +Button_Switch_Keyboard:SW_Matias_1.25u +Button_Switch_Keyboard:SW_Matias_1.50u +Button_Switch_Keyboard:SW_Matias_1.75u +Button_Switch_Keyboard:SW_Matias_2.00u +Button_Switch_Keyboard:SW_Matias_2.25u +Button_Switch_Keyboard:SW_Matias_2.75u +Button_Switch_Keyboard:SW_Matias_6.25u +Button_Switch_Keyboard:SW_Matias_ISOEnter +Button_Switch_SMD:Nidec_Copal_CAS-120A +Button_Switch_SMD:Nidec_Copal_SH-7010A +Button_Switch_SMD:Nidec_Copal_SH-7010B +Button_Switch_SMD:Nidec_Copal_SH-7040B +Button_Switch_SMD:Panasonic_EVQPUJ_EVQPUA +Button_Switch_SMD:Panasonic_EVQPUK_EVQPUB +Button_Switch_SMD:Panasonic_EVQPUL_EVQPUC +Button_Switch_SMD:Panasonic_EVQPUM_EVQPUD +Button_Switch_SMD:SW_DIP_SPSTx01_Slide_6.7x4.1mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx01_Slide_6.7x4.1mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx01_Slide_9.78x4.72mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx01_Slide_Copal_CHS-01A_W5.08mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx01_Slide_Copal_CHS-01B_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx01_Slide_Copal_CVS-01xB_W5.9mm_P1mm +Button_Switch_SMD:SW_DIP_SPSTx01_Slide_Omron_A6S-110x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_6.7x6.64mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_6.7x6.64mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_9.78x7.26mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_Copal_CHS-02A_W5.08mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_Copal_CHS-02B_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_Copal_CVS-02xB_W5.9mm_P1mm +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_KingTek_DSHP02TJ_W5.25mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_KingTek_DSHP02TS_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_Omron_A6H-2101_W6.15mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx02_Slide_Omron_A6S-210x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx03_Slide_6.7x9.18mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx03_Slide_6.7x9.18mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx03_Slide_9.78x9.8mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx03_Slide_Copal_CVS-03xB_W5.9mm_P1mm +Button_Switch_SMD:SW_DIP_SPSTx03_Slide_KingTek_DSHP03TJ_W5.25mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx03_Slide_KingTek_DSHP03TS_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx03_Slide_Omron_A6S-310x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_6.7x11.72mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_6.7x11.72mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_9.78x12.34mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_Copal_CHS-04A_W5.08mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_Copal_CHS-04B_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_Copal_CVS-04xB_W5.9mm_P1mm +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_KingTek_DSHP04TJ_W5.25mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_KingTek_DSHP04TS_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_Omron_A6H-4101_W6.15mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx04_Slide_Omron_A6S-410x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx05_Slide_6.7x14.26mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx05_Slide_6.7x14.26mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx05_Slide_9.78x14.88mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx05_Slide_KingTek_DSHP05TJ_W5.25mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx05_Slide_KingTek_DSHP05TS_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx05_Slide_Omron_A6S-510x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx06_Slide_6.7x16.8mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx06_Slide_6.7x16.8mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx06_Slide_9.78x17.42mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx06_Slide_Copal_CHS-06A_W5.08mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx06_Slide_Copal_CHS-06B_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx06_Slide_KingTek_DSHP06TJ_W5.25mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx06_Slide_KingTek_DSHP06TS_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx06_Slide_Omron_A6H-6101_W6.15mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx06_Slide_Omron_A6S-610x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx07_Slide_6.7x19.34mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx07_Slide_6.7x19.34mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx07_Slide_9.78x19.96mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx07_Slide_KingTek_DSHP07TJ_W5.25mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx07_Slide_KingTek_DSHP07TS_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx07_Slide_Omron_A6S-710x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_6.7x21.88mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_6.7x21.88mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_9.78x22.5mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_Copal_CHS-08A_W5.08mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_Copal_CHS-08B_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_Copal_CVS-08xB_W5.9mm_P1mm +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_KingTek_DSHP08TJ_W5.25mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_KingTek_DSHP08TS_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_Omron_A6H-8101_W6.15mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx08_Slide_Omron_A6S-810x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx09_Slide_6.7x24.42mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx09_Slide_6.7x24.42mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx09_Slide_9.78x25.04mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx09_Slide_KingTek_DSHP09TJ_W5.25mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx09_Slide_KingTek_DSHP09TS_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx09_Slide_Omron_A6S-910x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx10_Slide_6.7x26.96mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx10_Slide_6.7x26.96mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx10_Slide_9.78x27.58mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx10_Slide_Copal_CHS-10A_W5.08mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx10_Slide_Copal_CHS-10B_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx10_Slide_KingTek_DSHP10TJ_W5.25mm_P1.27mm_JPin +Button_Switch_SMD:SW_DIP_SPSTx10_Slide_KingTek_DSHP10TS_W7.62mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx10_Slide_Omron_A6H-10101_W6.15mm_P1.27mm +Button_Switch_SMD:SW_DIP_SPSTx10_Slide_Omron_A6S-1010x_W8.9mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx11_Slide_6.7x29.5mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx11_Slide_6.7x29.5mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx11_Slide_9.78x30.12mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DIP_SPSTx12_Slide_6.7x32.04mm_W6.73mm_P2.54mm_LowProfile_JPin +Button_Switch_SMD:SW_DIP_SPSTx12_Slide_6.7x32.04mm_W8.61mm_P2.54mm_LowProfile +Button_Switch_SMD:SW_DIP_SPSTx12_Slide_9.78x32.66mm_W8.61mm_P2.54mm +Button_Switch_SMD:SW_DPDT_CK_JS202011JCQN +Button_Switch_SMD:SW_MEC_5GSH9 +Button_Switch_SMD:SW_Push_1P1T-MP_NO_Horizontal_Alps_SKRTLAE010 +Button_Switch_SMD:SW_Push_1P1T-SH_NO_CK_KMR2xxG +Button_Switch_SMD:SW_Push_1P1T_NO_CK_KMR2 +Button_Switch_SMD:SW_Push_1P1T_NO_CK_KSC6xxJ +Button_Switch_SMD:SW_Push_1P1T_NO_CK_KSC7xxJ +Button_Switch_SMD:SW_Push_1P1T_NO_CK_PTS125Sx43PSMTR +Button_Switch_SMD:SW_Push_1P1T_NO_Vertical_Wuerth_434133025816 +Button_Switch_SMD:SW_Push_1P1T_XKB_TS-1187A +Button_Switch_SMD:SW_Push_1TS009xxxx-xxxx-xxxx_6x6x5mm +Button_Switch_SMD:SW_Push_SPST_NO_Alps_SKRK +Button_Switch_SMD:SW_SP3T_PCM13 +Button_Switch_SMD:SW_SPDT_CK_JS102011SAQN +Button_Switch_SMD:SW_SPDT_PCM12 +Button_Switch_SMD:SW_SPDT_REED_MSDM-DT +Button_Switch_SMD:SW_SPST_B3S-1000 +Button_Switch_SMD:SW_SPST_B3S-1100 +Button_Switch_SMD:SW_SPST_B3SL-1002P +Button_Switch_SMD:SW_SPST_B3SL-1022P +Button_Switch_SMD:SW_SPST_B3U-1000P-B +Button_Switch_SMD:SW_SPST_B3U-1000P +Button_Switch_SMD:SW_SPST_B3U-1100P-B +Button_Switch_SMD:SW_SPST_B3U-1100P +Button_Switch_SMD:SW_SPST_B3U-3000P-B +Button_Switch_SMD:SW_SPST_B3U-3000P +Button_Switch_SMD:SW_SPST_B3U-3100P-B +Button_Switch_SMD:SW_SPST_B3U-3100P +Button_Switch_SMD:SW_SPST_CK_KMS2xxG +Button_Switch_SMD:SW_SPST_CK_KMS2xxGP +Button_Switch_SMD:SW_SPST_CK_KXT3 +Button_Switch_SMD:SW_SPST_CK_RS282G05A3 +Button_Switch_SMD:SW_SPST_EVPBF +Button_Switch_SMD:SW_SPST_EVQP0 +Button_Switch_SMD:SW_SPST_EVQP2 +Button_Switch_SMD:SW_SPST_EVQP7A +Button_Switch_SMD:SW_SPST_EVQP7C +Button_Switch_SMD:SW_SPST_EVQPE1 +Button_Switch_SMD:SW_SPST_EVQQ2 +Button_Switch_SMD:SW_SPST_FSMSM +Button_Switch_SMD:SW_SPST_Omron_B3FS-100xP +Button_Switch_SMD:SW_SPST_Omron_B3FS-101xP +Button_Switch_SMD:SW_SPST_Omron_B3FS-105xP +Button_Switch_SMD:SW_SPST_Panasonic_EVQPL_3PL_5PL_PT_A08 +Button_Switch_SMD:SW_SPST_Panasonic_EVQPL_3PL_5PL_PT_A15 +Button_Switch_SMD:SW_SPST_PTS645 +Button_Switch_SMD:SW_SPST_PTS647_Sx38 +Button_Switch_SMD:SW_SPST_PTS647_Sx50 +Button_Switch_SMD:SW_SPST_PTS647_Sx70 +Button_Switch_SMD:SW_SPST_PTS810 +Button_Switch_SMD:SW_SPST_REED_CT05-XXXX-G1 +Button_Switch_SMD:SW_SPST_REED_CT05-XXXX-J1 +Button_Switch_SMD:SW_SPST_REED_CT10-XXXX-G1 +Button_Switch_SMD:SW_SPST_REED_CT10-XXXX-G2 +Button_Switch_SMD:SW_SPST_REED_CT10-XXXX-G4 +Button_Switch_SMD:SW_SPST_SKQG_WithoutStem +Button_Switch_SMD:SW_SPST_SKQG_WithStem +Button_Switch_SMD:SW_SPST_TL3305A +Button_Switch_SMD:SW_SPST_TL3305B +Button_Switch_SMD:SW_SPST_TL3305C +Button_Switch_SMD:SW_SPST_TL3342 +Button_Switch_SMD:SW_Tactile_SPST_NO_Straight_CK_PTS636Sx25SMTRLFS +Button_Switch_THT:KSA_Tactile_SPST +Button_Switch_THT:Nidec_Copal_SH-7010C +Button_Switch_THT:Push_E-Switch_KS01Q01 +Button_Switch_THT:SW_CK_JS202011AQN_DPDT_Angled +Button_Switch_THT:SW_CK_JS202011CQN_DPDT_Straight +Button_Switch_THT:SW_CW_GPTS203211B +Button_Switch_THT:SW_DIP_SPSTx01_Piano_10.8x4.1mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx01_Slide_6.7x4.1mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx01_Slide_9.78x4.72mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx02_Piano_10.8x6.64mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx02_Piano_CTS_Series194-2MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx02_Slide_6.7x6.64mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx02_Slide_9.78x7.26mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx03_Piano_10.8x9.18mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx03_Piano_CTS_Series194-3MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx03_Slide_6.7x9.18mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx03_Slide_9.78x9.8mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx04_Piano_10.8x11.72mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx04_Piano_CTS_Series194-4MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx04_Slide_6.7x11.72mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx04_Slide_9.78x12.34mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx05_Piano_10.8x14.26mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx05_Piano_CTS_Series194-5MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx05_Slide_6.7x14.26mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx05_Slide_9.78x14.88mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx06_Piano_10.8x16.8mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx06_Piano_CTS_Series194-6MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx06_Slide_6.7x16.8mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx06_Slide_9.78x17.42mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx07_Piano_10.8x19.34mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx07_Piano_CTS_Series194-7MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx07_Slide_6.7x19.34mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx07_Slide_9.78x19.96mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx08_Piano_10.8x21.88mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx08_Piano_CTS_Series194-8MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx08_Slide_6.7x21.88mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx08_Slide_9.78x22.5mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx09_Piano_10.8x24.42mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx09_Piano_CTS_Series194-9MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx09_Slide_6.7x24.42mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx09_Slide_9.78x25.04mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx10_Piano_10.8x26.96mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx10_Piano_CTS_Series194-10MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx10_Slide_6.7x26.96mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx10_Slide_9.78x27.58mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx11_Piano_10.8x29.5mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx11_Piano_CTS_Series194-11MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx11_Slide_6.7x29.5mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx11_Slide_9.78x30.12mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx12_Piano_10.8x32.04mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx12_Piano_CTS_Series194-12MSTN_W7.62mm_P2.54mm +Button_Switch_THT:SW_DIP_SPSTx12_Slide_6.7x32.04mm_W7.62mm_P2.54mm_LowProfile +Button_Switch_THT:SW_DIP_SPSTx12_Slide_9.78x32.66mm_W7.62mm_P2.54mm +Button_Switch_THT:SW_E-Switch_EG1224_SPDT_Angled +Button_Switch_THT:SW_E-Switch_EG1271_SPDT +Button_Switch_THT:SW_E-Switch_EG2219_DPDT_Angled +Button_Switch_THT:SW_Lever_1P2T_NKK_GW12LxH +Button_Switch_THT:SW_MEC_5GTH9 +Button_Switch_THT:SW_NKK_BB15AH +Button_Switch_THT:SW_NKK_G1xJP +Button_Switch_THT:SW_NKK_GW12LJP +Button_Switch_THT:SW_NKK_NR01 +Button_Switch_THT:SW_PUSH-12mm +Button_Switch_THT:SW_PUSH-12mm_Wuerth-430476085716 +Button_Switch_THT:SW_PUSH_1P1T_6x3.5mm_H4.3_APEM_MJTP1243 +Button_Switch_THT:SW_PUSH_1P1T_6x3.5mm_H5.0_APEM_MJTP1250 +Button_Switch_THT:SW_Push_1P1T_NO_LED_E-Switch_TL1250 +Button_Switch_THT:SW_Push_1P2T_Vertical_E-Switch_800UDP8P1A1M6 +Button_Switch_THT:SW_Push_2P1T_Toggle_CK_PVA1xxH1xxxxxxV2 +Button_Switch_THT:SW_Push_2P1T_Toggle_CK_PVA1xxH2xxxxxxV2 +Button_Switch_THT:SW_Push_2P1T_Toggle_CK_PVA1xxH3xxxxxxV2 +Button_Switch_THT:SW_Push_2P1T_Toggle_CK_PVA1xxH4xxxxxxV2 +Button_Switch_THT:SW_Push_2P2T_Toggle_CK_PVA2OAH5xxxxxxV2 +Button_Switch_THT:SW_Push_2P2T_Toggle_CK_PVA2xxH1xxxxxxV2 +Button_Switch_THT:SW_Push_2P2T_Toggle_CK_PVA2xxH2xxxxxxV2 +Button_Switch_THT:SW_Push_2P2T_Toggle_CK_PVA2xxH3xxxxxxV2 +Button_Switch_THT:SW_Push_2P2T_Toggle_CK_PVA2xxH4xxxxxxV2 +Button_Switch_THT:SW_Push_2P2T_Vertical_E-Switch_800UDP8P1A1M6 +Button_Switch_THT:SW_PUSH_6mm +Button_Switch_THT:SW_PUSH_6mm_H13mm +Button_Switch_THT:SW_PUSH_6mm_H4.3mm +Button_Switch_THT:SW_PUSH_6mm_H5mm +Button_Switch_THT:SW_PUSH_6mm_H7.3mm +Button_Switch_THT:SW_PUSH_6mm_H8.5mm +Button_Switch_THT:SW_PUSH_6mm_H8mm +Button_Switch_THT:SW_PUSH_6mm_H9.5mm +Button_Switch_THT:SW_PUSH_E-Switch_FS5700DP_DPDT +Button_Switch_THT:SW_PUSH_LCD_E3_SAxxxx +Button_Switch_THT:SW_PUSH_LCD_E3_SAxxxx_SocketPins +Button_Switch_THT:SW_Slide-03_Wuerth-WS-SLTV_10x2.5x6.4_P2.54mm +Button_Switch_THT:SW_Slide_SPDT_Angled_CK_OS102011MA1Q +Button_Switch_THT:SW_Slide_SPDT_Straight_CK_OS102011MS2Q +Button_Switch_THT:SW_SPST_Omron_B3F-315x_Angled +Button_Switch_THT:SW_SPST_Omron_B3F-40xx +Button_Switch_THT:SW_SPST_Omron_B3F-50xx +Button_Switch_THT:SW_Tactile_SKHH_Angled +Button_Switch_THT:SW_Tactile_SPST_Angled_PTS645Vx31-2LFS +Button_Switch_THT:SW_Tactile_SPST_Angled_PTS645Vx39-2LFS +Button_Switch_THT:SW_Tactile_SPST_Angled_PTS645Vx58-2LFS +Button_Switch_THT:SW_Tactile_SPST_Angled_PTS645Vx83-2LFS +Button_Switch_THT:SW_Tactile_Straight_KSA0Axx1LFTR +Button_Switch_THT:SW_Tactile_Straight_KSL0Axx1LFTR +Button_Switch_THT:SW_TH_Tactile_Omron_B3F-10xx +Button_Switch_THT:SW_XKB_DM1-16UC-1 +Button_Switch_THT:SW_XKB_DM1-16UD-1 +Button_Switch_THT:SW_XKB_DM1-16UP-1 +Buzzer_Beeper:Buzzer_12x9.5RM7.6 +Buzzer_Beeper:Buzzer_15x7.5RM7.6 +Buzzer_Beeper:Buzzer_CUI_CPT-9019S-SMT +Buzzer_Beeper:Buzzer_D14mm_H7mm_P10mm +Buzzer_Beeper:Buzzer_Mallory_AST1109MLTRQ +Buzzer_Beeper:Buzzer_Mallory_AST1240MLQ +Buzzer_Beeper:Buzzer_Murata_PKLCS1212E +Buzzer_Beeper:Buzzer_Murata_PKMCS0909E +Buzzer_Beeper:Buzzer_TDK_PS1240P02BT_D12.2mm_H6.5mm +Buzzer_Beeper:Indicator_PUI_AI-1440-TWT-24V-2-R +Buzzer_Beeper:MagneticBuzzer_CUI_CMT-8504-100-SMT +Buzzer_Beeper:MagneticBuzzer_CUI_CST-931RP-A +Buzzer_Beeper:MagneticBuzzer_Kingstate_KCG0601 +Buzzer_Beeper:MagneticBuzzer_Kobitone_254-EMB73-RO +Buzzer_Beeper:MagneticBuzzer_Kobitone_254-EMB84Q-RO +Buzzer_Beeper:MagneticBuzzer_ProjectsUnlimited_AI-4228-TWT-R +Buzzer_Beeper:MagneticBuzzer_ProSignal_ABI-009-RC +Buzzer_Beeper:MagneticBuzzer_ProSignal_ABI-010-RC +Buzzer_Beeper:MagneticBuzzer_ProSignal_ABT-410-RC +Buzzer_Beeper:MagneticBuzzer_PUI_AT-0927-TT-6-R +Buzzer_Beeper:MagneticBuzzer_PUI_SMT-1028-T-2-R +Buzzer_Beeper:MagneticBuzzer_StarMicronics_HMB-06_HMB-12 +Buzzer_Beeper:PUIAudio_SMT_0825_S_4_R +Buzzer_Beeper:Speaker_CUI_CMR-1206S-67 +Calibration_Scale:Gauge_100mm_Grid_Type1_CopperTop +Calibration_Scale:Gauge_100mm_Type1_CopperTop +Calibration_Scale:Gauge_100mm_Type1_SilkScreenTop +Calibration_Scale:Gauge_100mm_Type2_CopperTop +Calibration_Scale:Gauge_100mm_Type2_SilkScreenTop +Calibration_Scale:Gauge_10mm_Type1_CopperTop +Calibration_Scale:Gauge_10mm_Type1_SilkScreenTop +Calibration_Scale:Gauge_10mm_Type2_CopperTop +Calibration_Scale:Gauge_10mm_Type2_SilkScreenTop +Calibration_Scale:Gauge_10mm_Type3_CopperTop +Calibration_Scale:Gauge_10mm_Type3_SilkScreenTop +Calibration_Scale:Gauge_10mm_Type4_CopperTop +Calibration_Scale:Gauge_10mm_Type4_SilkScreenTop +Calibration_Scale:Gauge_10mm_Type5_CopperTop +Calibration_Scale:Gauge_10mm_Type5_SilkScreenTop +Calibration_Scale:Gauge_50mm_Type1_CopperTop +Calibration_Scale:Gauge_50mm_Type1_SilkScreenTop +Calibration_Scale:Gauge_50mm_Type2_CopperTop +Calibration_Scale:Gauge_50mm_Type2_SilkScreenTop +Capacitor_SMD:CP_Elec_10x10.5 +Capacitor_SMD:CP_Elec_10x10 +Capacitor_SMD:CP_Elec_10x12.5 +Capacitor_SMD:CP_Elec_10x12.6 +Capacitor_SMD:CP_Elec_10x14.3 +Capacitor_SMD:CP_Elec_10x7.7 +Capacitor_SMD:CP_Elec_10x7.9 +Capacitor_SMD:CP_Elec_16x17.5 +Capacitor_SMD:CP_Elec_16x22 +Capacitor_SMD:CP_Elec_18x17.5 +Capacitor_SMD:CP_Elec_18x22 +Capacitor_SMD:CP_Elec_3x5.3 +Capacitor_SMD:CP_Elec_3x5.4 +Capacitor_SMD:CP_Elec_4x3.9 +Capacitor_SMD:CP_Elec_4x3 +Capacitor_SMD:CP_Elec_4x4.5 +Capacitor_SMD:CP_Elec_4x5.3 +Capacitor_SMD:CP_Elec_4x5.4 +Capacitor_SMD:CP_Elec_4x5.7 +Capacitor_SMD:CP_Elec_4x5.8 +Capacitor_SMD:CP_Elec_5x3.9 +Capacitor_SMD:CP_Elec_5x3 +Capacitor_SMD:CP_Elec_5x4.4 +Capacitor_SMD:CP_Elec_5x4.5 +Capacitor_SMD:CP_Elec_5x5.3 +Capacitor_SMD:CP_Elec_5x5.4 +Capacitor_SMD:CP_Elec_5x5.7 +Capacitor_SMD:CP_Elec_5x5.8 +Capacitor_SMD:CP_Elec_5x5.9 +Capacitor_SMD:CP_Elec_6.3x3.9 +Capacitor_SMD:CP_Elec_6.3x3 +Capacitor_SMD:CP_Elec_6.3x4.5 +Capacitor_SMD:CP_Elec_6.3x4.9 +Capacitor_SMD:CP_Elec_6.3x5.2 +Capacitor_SMD:CP_Elec_6.3x5.3 +Capacitor_SMD:CP_Elec_6.3x5.4 +Capacitor_SMD:CP_Elec_6.3x5.4_Nichicon +Capacitor_SMD:CP_Elec_6.3x5.7 +Capacitor_SMD:CP_Elec_6.3x5.8 +Capacitor_SMD:CP_Elec_6.3x5.9 +Capacitor_SMD:CP_Elec_6.3x7.7 +Capacitor_SMD:CP_Elec_6.3x9.9 +Capacitor_SMD:CP_Elec_8x10.5 +Capacitor_SMD:CP_Elec_8x10 +Capacitor_SMD:CP_Elec_8x11.9 +Capacitor_SMD:CP_Elec_8x5.4 +Capacitor_SMD:CP_Elec_8x6.2 +Capacitor_SMD:CP_Elec_8x6.5 +Capacitor_SMD:CP_Elec_8x6.7 +Capacitor_SMD:CP_Elec_8x6.9 +Capacitor_SMD:CP_Elec_CAP-XX_DMF3Zxxxxxxxx3D +Capacitor_SMD:C_01005_0402Metric +Capacitor_SMD:C_01005_0402Metric_Pad0.57x0.30mm_HandSolder +Capacitor_SMD:C_0201_0603Metric +Capacitor_SMD:C_0201_0603Metric_Pad0.64x0.40mm_HandSolder +Capacitor_SMD:C_0402_1005Metric +Capacitor_SMD:C_0402_1005Metric_Pad0.74x0.62mm_HandSolder +Capacitor_SMD:C_0504_1310Metric +Capacitor_SMD:C_0504_1310Metric_Pad0.83x1.28mm_HandSolder +Capacitor_SMD:C_0603_1608Metric +Capacitor_SMD:C_0603_1608Metric_Pad1.08x0.95mm_HandSolder +Capacitor_SMD:C_0805_2012Metric +Capacitor_SMD:C_0805_2012Metric_Pad1.18x1.45mm_HandSolder +Capacitor_SMD:C_1206_3216Metric +Capacitor_SMD:C_1206_3216Metric_Pad1.33x1.80mm_HandSolder +Capacitor_SMD:C_1210_3225Metric +Capacitor_SMD:C_1210_3225Metric_Pad1.33x2.70mm_HandSolder +Capacitor_SMD:C_1808_4520Metric +Capacitor_SMD:C_1808_4520Metric_Pad1.72x2.30mm_HandSolder +Capacitor_SMD:C_1812_4532Metric +Capacitor_SMD:C_1812_4532Metric_Pad1.57x3.40mm_HandSolder +Capacitor_SMD:C_1825_4564Metric +Capacitor_SMD:C_1825_4564Metric_Pad1.57x6.80mm_HandSolder +Capacitor_SMD:C_2220_5750Metric +Capacitor_SMD:C_2220_5750Metric_Pad1.97x5.40mm_HandSolder +Capacitor_SMD:C_2225_5664Metric +Capacitor_SMD:C_2225_5664Metric_Pad1.80x6.60mm_HandSolder +Capacitor_SMD:C_3640_9110Metric +Capacitor_SMD:C_3640_9110Metric_Pad2.10x10.45mm_HandSolder +Capacitor_SMD:C_Elec_10x10.2 +Capacitor_SMD:C_Elec_3x5.4 +Capacitor_SMD:C_Elec_4x5.4 +Capacitor_SMD:C_Elec_4x5.8 +Capacitor_SMD:C_Elec_5x5.4 +Capacitor_SMD:C_Elec_5x5.8 +Capacitor_SMD:C_Elec_6.3x5.4 +Capacitor_SMD:C_Elec_6.3x5.8 +Capacitor_SMD:C_Elec_6.3x7.7 +Capacitor_SMD:C_Elec_8x10.2 +Capacitor_SMD:C_Elec_8x5.4 +Capacitor_SMD:C_Elec_8x6.2 +Capacitor_SMD:C_Trimmer_Murata_TZB4-A +Capacitor_SMD:C_Trimmer_Murata_TZB4-B +Capacitor_SMD:C_Trimmer_Murata_TZC3 +Capacitor_SMD:C_Trimmer_Murata_TZR1 +Capacitor_SMD:C_Trimmer_Murata_TZW4 +Capacitor_SMD:C_Trimmer_Murata_TZY2 +Capacitor_SMD:C_Trimmer_Sprague-Goodman_SGC3 +Capacitor_SMD:C_Trimmer_Voltronics_JN +Capacitor_SMD:C_Trimmer_Voltronics_JQ +Capacitor_SMD:C_Trimmer_Voltronics_JR +Capacitor_SMD:C_Trimmer_Voltronics_JV +Capacitor_SMD:C_Trimmer_Voltronics_JZ +Capacitor_Tantalum_SMD:CP_EIA-1608-08_AVX-J +Capacitor_Tantalum_SMD:CP_EIA-1608-08_AVX-J_Pad1.25x1.05mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-1608-10_AVX-L +Capacitor_Tantalum_SMD:CP_EIA-1608-10_AVX-L_Pad1.25x1.05mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-2012-12_Kemet-R +Capacitor_Tantalum_SMD:CP_EIA-2012-12_Kemet-R_Pad1.30x1.05mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-2012-15_AVX-P +Capacitor_Tantalum_SMD:CP_EIA-2012-15_AVX-P_Pad1.30x1.05mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-3216-10_Kemet-I +Capacitor_Tantalum_SMD:CP_EIA-3216-10_Kemet-I_Pad1.58x1.35mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-3216-12_Kemet-S +Capacitor_Tantalum_SMD:CP_EIA-3216-12_Kemet-S_Pad1.58x1.35mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-3216-18_Kemet-A +Capacitor_Tantalum_SMD:CP_EIA-3216-18_Kemet-A_Pad1.58x1.35mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-3528-12_Kemet-T +Capacitor_Tantalum_SMD:CP_EIA-3528-12_Kemet-T_Pad1.50x2.35mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-3528-15_AVX-H +Capacitor_Tantalum_SMD:CP_EIA-3528-15_AVX-H_Pad1.50x2.35mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-3528-21_Kemet-B +Capacitor_Tantalum_SMD:CP_EIA-3528-21_Kemet-B_Pad1.50x2.35mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-6032-15_Kemet-U +Capacitor_Tantalum_SMD:CP_EIA-6032-15_Kemet-U_Pad2.25x2.35mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-6032-20_AVX-F +Capacitor_Tantalum_SMD:CP_EIA-6032-20_AVX-F_Pad2.25x2.35mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-6032-28_Kemet-C +Capacitor_Tantalum_SMD:CP_EIA-6032-28_Kemet-C_Pad2.25x2.35mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7132-20_AVX-U +Capacitor_Tantalum_SMD:CP_EIA-7132-20_AVX-U_Pad2.72x3.50mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7132-28_AVX-C +Capacitor_Tantalum_SMD:CP_EIA-7132-28_AVX-C_Pad2.72x3.50mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7260-15_AVX-R +Capacitor_Tantalum_SMD:CP_EIA-7260-15_AVX-R_Pad2.68x6.30mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7260-20_AVX-M +Capacitor_Tantalum_SMD:CP_EIA-7260-20_AVX-M_Pad2.68x6.30mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7260-28_AVX-M +Capacitor_Tantalum_SMD:CP_EIA-7260-28_AVX-M_Pad2.68x6.30mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7260-38_AVX-R +Capacitor_Tantalum_SMD:CP_EIA-7260-38_AVX-R_Pad2.68x6.30mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7343-15_Kemet-W +Capacitor_Tantalum_SMD:CP_EIA-7343-15_Kemet-W_Pad2.25x2.55mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7343-20_Kemet-V +Capacitor_Tantalum_SMD:CP_EIA-7343-20_Kemet-V_Pad2.25x2.55mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7343-30_AVX-N +Capacitor_Tantalum_SMD:CP_EIA-7343-30_AVX-N_Pad2.25x2.55mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7343-31_Kemet-D +Capacitor_Tantalum_SMD:CP_EIA-7343-31_Kemet-D_Pad2.25x2.55mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7343-40_Kemet-Y +Capacitor_Tantalum_SMD:CP_EIA-7343-40_Kemet-Y_Pad2.25x2.55mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7343-43_Kemet-X +Capacitor_Tantalum_SMD:CP_EIA-7343-43_Kemet-X_Pad2.25x2.55mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7360-38_Kemet-E +Capacitor_Tantalum_SMD:CP_EIA-7360-38_Kemet-E_Pad2.25x4.25mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7361-38_AVX-V +Capacitor_Tantalum_SMD:CP_EIA-7361-38_AVX-V_Pad2.18x3.30mm_HandSolder +Capacitor_Tantalum_SMD:CP_EIA-7361-438_AVX-U +Capacitor_Tantalum_SMD:CP_EIA-7361-438_AVX-U_Pad2.18x3.30mm_HandSolder +Capacitor_THT:CP_Axial_L10.0mm_D4.5mm_P15.00mm_Horizontal +Capacitor_THT:CP_Axial_L10.0mm_D6.0mm_P15.00mm_Horizontal +Capacitor_THT:CP_Axial_L11.0mm_D5.0mm_P18.00mm_Horizontal +Capacitor_THT:CP_Axial_L11.0mm_D6.0mm_P18.00mm_Horizontal +Capacitor_THT:CP_Axial_L11.0mm_D8.0mm_P15.00mm_Horizontal +Capacitor_THT:CP_Axial_L18.0mm_D10.0mm_P25.00mm_Horizontal +Capacitor_THT:CP_Axial_L18.0mm_D6.5mm_P25.00mm_Horizontal +Capacitor_THT:CP_Axial_L18.0mm_D8.0mm_P25.00mm_Horizontal +Capacitor_THT:CP_Axial_L20.0mm_D10.0mm_P26.00mm_Horizontal +Capacitor_THT:CP_Axial_L20.0mm_D13.0mm_P26.00mm_Horizontal +Capacitor_THT:CP_Axial_L21.0mm_D8.0mm_P28.00mm_Horizontal +Capacitor_THT:CP_Axial_L25.0mm_D10.0mm_P30.00mm_Horizontal +Capacitor_THT:CP_Axial_L26.5mm_D20.0mm_P33.00mm_Horizontal +Capacitor_THT:CP_Axial_L29.0mm_D10.0mm_P35.00mm_Horizontal +Capacitor_THT:CP_Axial_L29.0mm_D13.0mm_P35.00mm_Horizontal +Capacitor_THT:CP_Axial_L29.0mm_D16.0mm_P35.00mm_Horizontal +Capacitor_THT:CP_Axial_L29.0mm_D20.0mm_P35.00mm_Horizontal +Capacitor_THT:CP_Axial_L30.0mm_D10.0mm_P35.00mm_Horizontal +Capacitor_THT:CP_Axial_L30.0mm_D12.5mm_P35.00mm_Horizontal +Capacitor_THT:CP_Axial_L30.0mm_D15.0mm_P35.00mm_Horizontal +Capacitor_THT:CP_Axial_L30.0mm_D18.0mm_P35.00mm_Horizontal +Capacitor_THT:CP_Axial_L34.5mm_D20.0mm_P41.00mm_Horizontal +Capacitor_THT:CP_Axial_L37.0mm_D13.0mm_P43.00mm_Horizontal +Capacitor_THT:CP_Axial_L37.0mm_D16.0mm_P43.00mm_Horizontal +Capacitor_THT:CP_Axial_L37.0mm_D20.0mm_P43.00mm_Horizontal +Capacitor_THT:CP_Axial_L38.0mm_D18.0mm_P44.00mm_Horizontal +Capacitor_THT:CP_Axial_L38.0mm_D21.0mm_P44.00mm_Horizontal +Capacitor_THT:CP_Axial_L40.0mm_D16.0mm_P48.00mm_Horizontal +Capacitor_THT:CP_Axial_L42.0mm_D23.0mm_P45.00mm_Horizontal +Capacitor_THT:CP_Axial_L42.0mm_D26.0mm_P45.00mm_Horizontal +Capacitor_THT:CP_Axial_L42.0mm_D29.0mm_P45.00mm_Horizontal +Capacitor_THT:CP_Axial_L42.0mm_D32.0mm_P45.00mm_Horizontal +Capacitor_THT:CP_Axial_L42.0mm_D35.0mm_P45.00mm_Horizontal +Capacitor_THT:CP_Axial_L42.5mm_D20.0mm_P49.00mm_Horizontal +Capacitor_THT:CP_Axial_L46.0mm_D20.0mm_P52.00mm_Horizontal +Capacitor_THT:CP_Axial_L55.0mm_D23.0mm_P60.00mm_Horizontal +Capacitor_THT:CP_Axial_L55.0mm_D26.0mm_P60.00mm_Horizontal +Capacitor_THT:CP_Axial_L55.0mm_D29.0mm_P60.00mm_Horizontal +Capacitor_THT:CP_Axial_L55.0mm_D32.0mm_P60.00mm_Horizontal +Capacitor_THT:CP_Axial_L55.0mm_D35.0mm_P60.00mm_Horizontal +Capacitor_THT:CP_Axial_L67.0mm_D23.0mm_P75.00mm_Horizontal +Capacitor_THT:CP_Axial_L67.0mm_D26.0mm_P75.00mm_Horizontal +Capacitor_THT:CP_Axial_L67.0mm_D29.0mm_P75.00mm_Horizontal +Capacitor_THT:CP_Axial_L67.0mm_D32.0mm_P75.00mm_Horizontal +Capacitor_THT:CP_Axial_L67.0mm_D35.0mm_P75.00mm_Horizontal +Capacitor_THT:CP_Axial_L80.0mm_D23.0mm_P85.00mm_Horizontal +Capacitor_THT:CP_Axial_L80.0mm_D26.0mm_P85.00mm_Horizontal +Capacitor_THT:CP_Axial_L80.0mm_D29.0mm_P85.00mm_Horizontal +Capacitor_THT:CP_Axial_L80.0mm_D32.0mm_P85.00mm_Horizontal +Capacitor_THT:CP_Axial_L80.0mm_D35.0mm_P85.00mm_Horizontal +Capacitor_THT:CP_Axial_L93.0mm_D23.0mm_P100.00mm_Horizontal +Capacitor_THT:CP_Axial_L93.0mm_D26.0mm_P100.00mm_Horizontal +Capacitor_THT:CP_Axial_L93.0mm_D29.0mm_P100.00mm_Horizontal +Capacitor_THT:CP_Axial_L93.0mm_D32.0mm_P100.00mm_Horizontal +Capacitor_THT:CP_Axial_L93.0mm_D35.0mm_P100.00mm_Horizontal +Capacitor_THT:CP_Radial_D10.0mm_P2.50mm +Capacitor_THT:CP_Radial_D10.0mm_P2.50mm_P5.00mm +Capacitor_THT:CP_Radial_D10.0mm_P3.50mm +Capacitor_THT:CP_Radial_D10.0mm_P3.80mm +Capacitor_THT:CP_Radial_D10.0mm_P5.00mm +Capacitor_THT:CP_Radial_D10.0mm_P5.00mm_P7.50mm +Capacitor_THT:CP_Radial_D10.0mm_P7.50mm +Capacitor_THT:CP_Radial_D12.5mm_P2.50mm +Capacitor_THT:CP_Radial_D12.5mm_P5.00mm +Capacitor_THT:CP_Radial_D12.5mm_P7.50mm +Capacitor_THT:CP_Radial_D13.0mm_P2.50mm +Capacitor_THT:CP_Radial_D13.0mm_P5.00mm +Capacitor_THT:CP_Radial_D13.0mm_P7.50mm +Capacitor_THT:CP_Radial_D14.0mm_P5.00mm +Capacitor_THT:CP_Radial_D14.0mm_P7.50mm +Capacitor_THT:CP_Radial_D16.0mm_P7.50mm +Capacitor_THT:CP_Radial_D17.0mm_P7.50mm +Capacitor_THT:CP_Radial_D18.0mm_P7.50mm +Capacitor_THT:CP_Radial_D22.0mm_P10.00mm_3pin_SnapIn +Capacitor_THT:CP_Radial_D22.0mm_P10.00mm_SnapIn +Capacitor_THT:CP_Radial_D24.0mm_P10.00mm_3pin_SnapIn +Capacitor_THT:CP_Radial_D24.0mm_P10.00mm_SnapIn +Capacitor_THT:CP_Radial_D25.0mm_P10.00mm_3pin_SnapIn +Capacitor_THT:CP_Radial_D25.0mm_P10.00mm_SnapIn +Capacitor_THT:CP_Radial_D26.0mm_P10.00mm_3pin_SnapIn +Capacitor_THT:CP_Radial_D26.0mm_P10.00mm_SnapIn +Capacitor_THT:CP_Radial_D30.0mm_P10.00mm_3pin_SnapIn +Capacitor_THT:CP_Radial_D30.0mm_P10.00mm_SnapIn +Capacitor_THT:CP_Radial_D35.0mm_P10.00mm_3pin_SnapIn +Capacitor_THT:CP_Radial_D35.0mm_P10.00mm_SnapIn +Capacitor_THT:CP_Radial_D4.0mm_P1.50mm +Capacitor_THT:CP_Radial_D4.0mm_P2.00mm +Capacitor_THT:CP_Radial_D40.0mm_P10.00mm_3pin_SnapIn +Capacitor_THT:CP_Radial_D40.0mm_P10.00mm_SnapIn +Capacitor_THT:CP_Radial_D5.0mm_P2.00mm +Capacitor_THT:CP_Radial_D5.0mm_P2.50mm +Capacitor_THT:CP_Radial_D6.3mm_P2.50mm +Capacitor_THT:CP_Radial_D7.5mm_P2.50mm +Capacitor_THT:CP_Radial_D8.0mm_P2.50mm +Capacitor_THT:CP_Radial_D8.0mm_P3.50mm +Capacitor_THT:CP_Radial_D8.0mm_P3.80mm +Capacitor_THT:CP_Radial_D8.0mm_P5.00mm +Capacitor_THT:CP_Radial_Tantal_D10.5mm_P2.50mm +Capacitor_THT:CP_Radial_Tantal_D10.5mm_P5.00mm +Capacitor_THT:CP_Radial_Tantal_D4.5mm_P2.50mm +Capacitor_THT:CP_Radial_Tantal_D4.5mm_P5.00mm +Capacitor_THT:CP_Radial_Tantal_D5.0mm_P2.50mm +Capacitor_THT:CP_Radial_Tantal_D5.0mm_P5.00mm +Capacitor_THT:CP_Radial_Tantal_D5.5mm_P2.50mm +Capacitor_THT:CP_Radial_Tantal_D5.5mm_P5.00mm +Capacitor_THT:CP_Radial_Tantal_D6.0mm_P2.50mm +Capacitor_THT:CP_Radial_Tantal_D6.0mm_P5.00mm +Capacitor_THT:CP_Radial_Tantal_D7.0mm_P2.50mm +Capacitor_THT:CP_Radial_Tantal_D7.0mm_P5.00mm +Capacitor_THT:CP_Radial_Tantal_D8.0mm_P2.50mm +Capacitor_THT:CP_Radial_Tantal_D8.0mm_P5.00mm +Capacitor_THT:CP_Radial_Tantal_D9.0mm_P2.50mm +Capacitor_THT:CP_Radial_Tantal_D9.0mm_P5.00mm +Capacitor_THT:C_Axial_L12.0mm_D10.5mm_P15.00mm_Horizontal +Capacitor_THT:C_Axial_L12.0mm_D10.5mm_P20.00mm_Horizontal +Capacitor_THT:C_Axial_L12.0mm_D6.5mm_P15.00mm_Horizontal +Capacitor_THT:C_Axial_L12.0mm_D6.5mm_P20.00mm_Horizontal +Capacitor_THT:C_Axial_L12.0mm_D7.5mm_P15.00mm_Horizontal +Capacitor_THT:C_Axial_L12.0mm_D7.5mm_P20.00mm_Horizontal +Capacitor_THT:C_Axial_L12.0mm_D8.5mm_P15.00mm_Horizontal +Capacitor_THT:C_Axial_L12.0mm_D8.5mm_P20.00mm_Horizontal +Capacitor_THT:C_Axial_L12.0mm_D9.5mm_P15.00mm_Horizontal +Capacitor_THT:C_Axial_L12.0mm_D9.5mm_P20.00mm_Horizontal +Capacitor_THT:C_Axial_L17.0mm_D6.5mm_P20.00mm_Horizontal +Capacitor_THT:C_Axial_L17.0mm_D6.5mm_P25.00mm_Horizontal +Capacitor_THT:C_Axial_L17.0mm_D7.0mm_P20.00mm_Horizontal +Capacitor_THT:C_Axial_L17.0mm_D7.0mm_P25.00mm_Horizontal +Capacitor_THT:C_Axial_L19.0mm_D7.5mm_P25.00mm_Horizontal +Capacitor_THT:C_Axial_L19.0mm_D8.0mm_P25.00mm_Horizontal +Capacitor_THT:C_Axial_L19.0mm_D9.0mm_P25.00mm_Horizontal +Capacitor_THT:C_Axial_L19.0mm_D9.5mm_P25.00mm_Horizontal +Capacitor_THT:C_Axial_L22.0mm_D10.5mm_P27.50mm_Horizontal +Capacitor_THT:C_Axial_L22.0mm_D9.5mm_P27.50mm_Horizontal +Capacitor_THT:C_Axial_L3.8mm_D2.6mm_P10.00mm_Horizontal +Capacitor_THT:C_Axial_L3.8mm_D2.6mm_P12.50mm_Horizontal +Capacitor_THT:C_Axial_L3.8mm_D2.6mm_P15.00mm_Horizontal +Capacitor_THT:C_Axial_L3.8mm_D2.6mm_P7.50mm_Horizontal +Capacitor_THT:C_Axial_L5.1mm_D3.1mm_P10.00mm_Horizontal +Capacitor_THT:C_Axial_L5.1mm_D3.1mm_P12.50mm_Horizontal +Capacitor_THT:C_Axial_L5.1mm_D3.1mm_P15.00mm_Horizontal +Capacitor_THT:C_Axial_L5.1mm_D3.1mm_P7.50mm_Horizontal +Capacitor_THT:C_Disc_D10.0mm_W2.5mm_P5.00mm +Capacitor_THT:C_Disc_D10.5mm_W5.0mm_P10.00mm +Capacitor_THT:C_Disc_D10.5mm_W5.0mm_P5.00mm +Capacitor_THT:C_Disc_D10.5mm_W5.0mm_P7.50mm +Capacitor_THT:C_Disc_D11.0mm_W5.0mm_P10.00mm +Capacitor_THT:C_Disc_D11.0mm_W5.0mm_P5.00mm +Capacitor_THT:C_Disc_D11.0mm_W5.0mm_P7.50mm +Capacitor_THT:C_Disc_D12.0mm_W4.4mm_P7.75mm +Capacitor_THT:C_Disc_D12.5mm_W5.0mm_P10.00mm +Capacitor_THT:C_Disc_D12.5mm_W5.0mm_P7.50mm +Capacitor_THT:C_Disc_D14.5mm_W5.0mm_P10.00mm +Capacitor_THT:C_Disc_D14.5mm_W5.0mm_P7.50mm +Capacitor_THT:C_Disc_D16.0mm_W5.0mm_P10.00mm +Capacitor_THT:C_Disc_D16.0mm_W5.0mm_P7.50mm +Capacitor_THT:C_Disc_D3.0mm_W1.6mm_P2.50mm +Capacitor_THT:C_Disc_D3.0mm_W2.0mm_P2.50mm +Capacitor_THT:C_Disc_D3.4mm_W2.1mm_P2.50mm +Capacitor_THT:C_Disc_D3.8mm_W2.6mm_P2.50mm +Capacitor_THT:C_Disc_D4.3mm_W1.9mm_P5.00mm +Capacitor_THT:C_Disc_D4.7mm_W2.5mm_P5.00mm +Capacitor_THT:C_Disc_D5.0mm_W2.5mm_P2.50mm +Capacitor_THT:C_Disc_D5.0mm_W2.5mm_P5.00mm +Capacitor_THT:C_Disc_D5.1mm_W3.2mm_P5.00mm +Capacitor_THT:C_Disc_D6.0mm_W2.5mm_P5.00mm +Capacitor_THT:C_Disc_D6.0mm_W4.4mm_P5.00mm +Capacitor_THT:C_Disc_D7.0mm_W2.5mm_P5.00mm +Capacitor_THT:C_Disc_D7.5mm_W2.5mm_P5.00mm +Capacitor_THT:C_Disc_D7.5mm_W4.4mm_P5.00mm +Capacitor_THT:C_Disc_D7.5mm_W5.0mm_P10.00mm +Capacitor_THT:C_Disc_D7.5mm_W5.0mm_P5.00mm +Capacitor_THT:C_Disc_D7.5mm_W5.0mm_P7.50mm +Capacitor_THT:C_Disc_D8.0mm_W2.5mm_P5.00mm +Capacitor_THT:C_Disc_D8.0mm_W5.0mm_P10.00mm +Capacitor_THT:C_Disc_D8.0mm_W5.0mm_P5.00mm +Capacitor_THT:C_Disc_D8.0mm_W5.0mm_P7.50mm +Capacitor_THT:C_Disc_D9.0mm_W2.5mm_P5.00mm +Capacitor_THT:C_Disc_D9.0mm_W5.0mm_P10.00mm +Capacitor_THT:C_Disc_D9.0mm_W5.0mm_P5.00mm +Capacitor_THT:C_Disc_D9.0mm_W5.0mm_P7.50mm +Capacitor_THT:C_Radial_D10.0mm_H12.5mm_P5.00mm +Capacitor_THT:C_Radial_D10.0mm_H16.0mm_P5.00mm +Capacitor_THT:C_Radial_D10.0mm_H20.0mm_P5.00mm +Capacitor_THT:C_Radial_D12.5mm_H20.0mm_P5.00mm +Capacitor_THT:C_Radial_D12.5mm_H25.0mm_P5.00mm +Capacitor_THT:C_Radial_D16.0mm_H25.0mm_P7.50mm +Capacitor_THT:C_Radial_D16.0mm_H31.5mm_P7.50mm +Capacitor_THT:C_Radial_D18.0mm_H35.5mm_P7.50mm +Capacitor_THT:C_Radial_D4.0mm_H5.0mm_P1.50mm +Capacitor_THT:C_Radial_D4.0mm_H7.0mm_P1.50mm +Capacitor_THT:C_Radial_D5.0mm_H11.0mm_P2.00mm +Capacitor_THT:C_Radial_D5.0mm_H5.0mm_P2.00mm +Capacitor_THT:C_Radial_D5.0mm_H7.0mm_P2.00mm +Capacitor_THT:C_Radial_D6.3mm_H11.0mm_P2.50mm +Capacitor_THT:C_Radial_D6.3mm_H5.0mm_P2.50mm +Capacitor_THT:C_Radial_D6.3mm_H7.0mm_P2.50mm +Capacitor_THT:C_Radial_D8.0mm_H11.5mm_P3.50mm +Capacitor_THT:C_Radial_D8.0mm_H7.0mm_P3.50mm +Capacitor_THT:C_Rect_L10.0mm_W2.5mm_P7.50mm_MKS4 +Capacitor_THT:C_Rect_L10.0mm_W3.0mm_P7.50mm_FKS3_FKP3 +Capacitor_THT:C_Rect_L10.0mm_W3.0mm_P7.50mm_MKS4 +Capacitor_THT:C_Rect_L10.0mm_W4.0mm_P7.50mm_FKS3_FKP3 +Capacitor_THT:C_Rect_L10.0mm_W4.0mm_P7.50mm_MKS4 +Capacitor_THT:C_Rect_L10.0mm_W5.0mm_P5.00mm_P7.50mm +Capacitor_THT:C_Rect_L10.3mm_W4.5mm_P7.50mm_MKS4 +Capacitor_THT:C_Rect_L10.3mm_W5.0mm_P7.50mm_MKS4 +Capacitor_THT:C_Rect_L10.3mm_W5.7mm_P7.50mm_MKS4 +Capacitor_THT:C_Rect_L10.3mm_W7.2mm_P7.50mm_MKS4 +Capacitor_THT:C_Rect_L11.0mm_W2.8mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W3.4mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W3.5mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W4.2mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W4.3mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W5.1mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W5.3mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W6.3mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W6.4mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W7.3mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.0mm_W8.8mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W2.0mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W2.6mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W2.8mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W3.2mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W3.5mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W3.6mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W4.0mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W4.3mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W4.5mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W5.0mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W5.1mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W5.2mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W5.6mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W6.4mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W6.6mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W6.9mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W7.3mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W7.5mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W7.8mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W8.0mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W8.8mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W9.5mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L11.5mm_W9.8mm_P10.00mm_MKT +Capacitor_THT:C_Rect_L13.0mm_W3.0mm_P10.00mm_FKS3_FKP3_MKS4 +Capacitor_THT:C_Rect_L13.0mm_W4.0mm_P10.00mm_FKS3_FKP3_MKS4 +Capacitor_THT:C_Rect_L13.0mm_W5.0mm_P10.00mm_FKS3_FKP3_MKS4 +Capacitor_THT:C_Rect_L13.0mm_W6.0mm_P10.00mm_FKS3_FKP3_MKS4 +Capacitor_THT:C_Rect_L13.0mm_W6.5mm_P7.50mm_P10.00mm +Capacitor_THT:C_Rect_L13.0mm_W8.0mm_P10.00mm_FKS3_FKP3_MKS4 +Capacitor_THT:C_Rect_L13.5mm_W4.0mm_P10.00mm_FKS3_FKP3_MKS4 +Capacitor_THT:C_Rect_L13.5mm_W5.0mm_P10.00mm_FKS3_FKP3_MKS4 +Capacitor_THT:C_Rect_L16.5mm_W10.7mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W10.9mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W11.2mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W11.8mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W13.5mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W13.7mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W13.9mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W4.7mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W4.9mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W5.0mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W6.0mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W7.0mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W7.3mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W8.7mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W8.9mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W9.0mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L16.5mm_W9.2mm_P15.00mm_MKT +Capacitor_THT:C_Rect_L18.0mm_W11.0mm_P15.00mm_FKS3_FKP3 +Capacitor_THT:C_Rect_L18.0mm_W5.0mm_P15.00mm_FKS3_FKP3 +Capacitor_THT:C_Rect_L18.0mm_W6.0mm_P15.00mm_FKS3_FKP3 +Capacitor_THT:C_Rect_L18.0mm_W7.0mm_P15.00mm_FKS3_FKP3 +Capacitor_THT:C_Rect_L18.0mm_W8.0mm_P15.00mm_FKS3_FKP3 +Capacitor_THT:C_Rect_L18.0mm_W9.0mm_P15.00mm_FKS3_FKP3 +Capacitor_THT:C_Rect_L19.0mm_W11.0mm_P15.00mm_MKS4 +Capacitor_THT:C_Rect_L19.0mm_W5.0mm_P15.00mm_MKS4 +Capacitor_THT:C_Rect_L19.0mm_W6.0mm_P15.00mm_MKS4 +Capacitor_THT:C_Rect_L19.0mm_W7.0mm_P15.00mm_MKS4 +Capacitor_THT:C_Rect_L19.0mm_W8.0mm_P15.00mm_MKS4 +Capacitor_THT:C_Rect_L19.0mm_W9.0mm_P15.00mm_MKS4 +Capacitor_THT:C_Rect_L24.0mm_W10.1mm_P22.50mm_MKT +Capacitor_THT:C_Rect_L24.0mm_W10.3mm_P22.50mm_MKT +Capacitor_THT:C_Rect_L24.0mm_W10.9mm_P22.50mm_MKT +Capacitor_THT:C_Rect_L24.0mm_W12.2mm_P22.50mm_MKT +Capacitor_THT:C_Rect_L24.0mm_W12.6mm_P22.50mm_MKT +Capacitor_THT:C_Rect_L24.0mm_W12.8mm_P22.50mm_MKT +Capacitor_THT:C_Rect_L24.0mm_W7.0mm_P22.50mm_MKT +Capacitor_THT:C_Rect_L24.0mm_W8.3mm_P22.50mm_MKT +Capacitor_THT:C_Rect_L24.0mm_W8.6mm_P22.50mm_MKT +Capacitor_THT:C_Rect_L26.5mm_W10.5mm_P22.50mm_MKS4 +Capacitor_THT:C_Rect_L26.5mm_W11.5mm_P22.50mm_MKS4 +Capacitor_THT:C_Rect_L26.5mm_W5.0mm_P22.50mm_MKS4 +Capacitor_THT:C_Rect_L26.5mm_W6.0mm_P22.50mm_MKS4 +Capacitor_THT:C_Rect_L26.5mm_W7.0mm_P22.50mm_MKS4 +Capacitor_THT:C_Rect_L26.5mm_W8.5mm_P22.50mm_MKS4 +Capacitor_THT:C_Rect_L27.0mm_W11.0mm_P22.00mm +Capacitor_THT:C_Rect_L27.0mm_W9.0mm_P22.00mm +Capacitor_THT:C_Rect_L27.0mm_W9.0mm_P23.00mm +Capacitor_THT:C_Rect_L28.0mm_W10.0mm_P22.50mm_MKS4 +Capacitor_THT:C_Rect_L28.0mm_W12.0mm_P22.50mm_MKS4 +Capacitor_THT:C_Rect_L28.0mm_W8.0mm_P22.50mm_MKS4 +Capacitor_THT:C_Rect_L29.0mm_W11.0mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W11.9mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W12.2mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W13.0mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W13.8mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W14.2mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W16.0mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W7.6mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W7.8mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W7.9mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W9.1mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L29.0mm_W9.6mm_P27.50mm_MKT +Capacitor_THT:C_Rect_L31.5mm_W11.0mm_P27.50mm_MKS4 +Capacitor_THT:C_Rect_L31.5mm_W13.0mm_P27.50mm_MKS4 +Capacitor_THT:C_Rect_L31.5mm_W15.0mm_P27.50mm_MKS4 +Capacitor_THT:C_Rect_L31.5mm_W17.0mm_P27.50mm_MKS4 +Capacitor_THT:C_Rect_L31.5mm_W20.0mm_P27.50mm_MKS4 +Capacitor_THT:C_Rect_L31.5mm_W9.0mm_P27.50mm_MKS4 +Capacitor_THT:C_Rect_L32.0mm_W15.0mm_P27.00mm +Capacitor_THT:C_Rect_L33.0mm_W13.0mm_P27.50mm_MKS4 +Capacitor_THT:C_Rect_L33.0mm_W15.0mm_P27.50mm_MKS4 +Capacitor_THT:C_Rect_L33.0mm_W20.0mm_P27.50mm_MKS4 +Capacitor_THT:C_Rect_L4.0mm_W2.5mm_P2.50mm +Capacitor_THT:C_Rect_L4.6mm_W2.0mm_P2.50mm_MKS02_FKP02 +Capacitor_THT:C_Rect_L4.6mm_W3.0mm_P2.50mm_MKS02_FKP02 +Capacitor_THT:C_Rect_L4.6mm_W3.8mm_P2.50mm_MKS02_FKP02 +Capacitor_THT:C_Rect_L4.6mm_W4.6mm_P2.50mm_MKS02_FKP02 +Capacitor_THT:C_Rect_L4.6mm_W5.5mm_P2.50mm_MKS02_FKP02 +Capacitor_THT:C_Rect_L41.5mm_W11.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W13.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W15.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W17.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W19.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W20.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W24.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W31.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W35.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W40.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L41.5mm_W9.0mm_P37.50mm_MKS4 +Capacitor_THT:C_Rect_L7.0mm_W2.0mm_P5.00mm +Capacitor_THT:C_Rect_L7.0mm_W2.5mm_P5.00mm +Capacitor_THT:C_Rect_L7.0mm_W3.5mm_P2.50mm_P5.00mm +Capacitor_THT:C_Rect_L7.0mm_W3.5mm_P5.00mm +Capacitor_THT:C_Rect_L7.0mm_W4.5mm_P5.00mm +Capacitor_THT:C_Rect_L7.0mm_W6.0mm_P5.00mm +Capacitor_THT:C_Rect_L7.0mm_W6.5mm_P5.00mm +Capacitor_THT:C_Rect_L7.2mm_W11.0mm_P5.00mm_FKS2_FKP2_MKS2_MKP2 +Capacitor_THT:C_Rect_L7.2mm_W2.5mm_P5.00mm_FKS2_FKP2_MKS2_MKP2 +Capacitor_THT:C_Rect_L7.2mm_W3.0mm_P5.00mm_FKS2_FKP2_MKS2_MKP2 +Capacitor_THT:C_Rect_L7.2mm_W3.5mm_P5.00mm_FKS2_FKP2_MKS2_MKP2 +Capacitor_THT:C_Rect_L7.2mm_W4.5mm_P5.00mm_FKS2_FKP2_MKS2_MKP2 +Capacitor_THT:C_Rect_L7.2mm_W5.5mm_P5.00mm_FKS2_FKP2_MKS2_MKP2 +Capacitor_THT:C_Rect_L7.2mm_W7.2mm_P5.00mm_FKS2_FKP2_MKS2_MKP2 +Capacitor_THT:C_Rect_L7.2mm_W8.5mm_P5.00mm_FKP2_FKP2_MKS2_MKP2 +Capacitor_THT:C_Rect_L7.5mm_W6.5mm_P5.00mm +Capacitor_THT:C_Rect_L9.0mm_W2.5mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W2.6mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W2.7mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W3.2mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W3.3mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W3.4mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W3.6mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W3.8mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W3.9mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W4.0mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W4.2mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W4.9mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W5.1mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W5.7mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W6.4mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W6.7mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W7.7mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W8.5mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W9.5mm_P7.50mm_MKT +Capacitor_THT:C_Rect_L9.0mm_W9.8mm_P7.50mm_MKT +Capacitor_THT:DX_5R5HxxxxU_D11.5mm_P10.00mm +Capacitor_THT:DX_5R5VxxxxU_D11.5mm_P5.00mm +Capacitor_THT:DX_5R5VxxxxU_D19.0mm_P5.00mm +Connector:Banana_Cliff_FCR7350B_S16N-PC_Horizontal +Connector:Banana_Cliff_FCR7350G_S16N-PC_Horizontal +Connector:Banana_Cliff_FCR7350L_S16N-PC_Horizontal +Connector:Banana_Cliff_FCR7350N_S16N-PC_Horizontal +Connector:Banana_Cliff_FCR7350R_S16N-PC_Horizontal +Connector:Banana_Cliff_FCR7350Y_S16N-PC_Horizontal +Connector:Banana_Jack_1Pin +Connector:Banana_Jack_2Pin +Connector:Banana_Jack_3Pin +Connector:CalTest_CT3151 +Connector:Connector_SFP_and_Cage +Connector:CUI_PD-30 +Connector:CUI_PD-30S +Connector:CUI_PD-30S_CircularHoles +Connector:DTF13-12Px +Connector:FanPinHeader_1x03_P2.54mm_Vertical +Connector:FanPinHeader_1x04_P2.54mm_Vertical +Connector:GB042-34S-H10 +Connector:IHI_B6A-PCB-45_Vertical +Connector:Joint-Tech_C5080WR-04P_1x04_P5.08mm_Vertical +Connector:JWT_A3963_1x02_P3.96mm_Vertical +Connector:NS-Tech_Grove_1x04_P2mm_Vertical +Connector:OCN_OK-01GM030-04_2x15_P0.4mm_Vertical +Connector:SpringContact_Harwin_S1941-46R +Connector:Tag-Connect_TC2030-IDC-FP_2x03_P1.27mm_Vertical +Connector:Tag-Connect_TC2030-IDC-NL_2x03_P1.27mm_Vertical +Connector:Tag-Connect_TC2050-IDC-FP_2x05_P1.27mm_Vertical +Connector:Tag-Connect_TC2050-IDC-NL_2x05_P1.27mm_Vertical +Connector:Tag-Connect_TC2050-IDC-NL_2x05_P1.27mm_Vertical_with_bottom_clip +Connector:Tag-Connect_TC2070-IDC-FP_2x07_P1.27mm_Vertical +Connector_AMASS:AMASS_MR30PW-FB_1x03_P3.50mm_Horizontal +Connector_AMASS:AMASS_MR30PW-M_1x03_P3.50mm_Horizontal +Connector_AMASS:AMASS_XT30PW-F_1x02_P2.50mm_Horizontal +Connector_AMASS:AMASS_XT30PW-M_1x02_P2.50mm_Horizontal +Connector_AMASS:AMASS_XT30U-F_1x02_P5.0mm_Vertical +Connector_AMASS:AMASS_XT30U-M_1x02_P5.0mm_Vertical +Connector_AMASS:AMASS_XT30UPB-F_1x02_P5.0mm_Vertical +Connector_AMASS:AMASS_XT30UPB-M_1x02_P5.0mm_Vertical +Connector_AMASS:AMASS_XT60-F_1x02_P7.20mm_Vertical +Connector_AMASS:AMASS_XT60-M_1x02_P7.20mm_Vertical +Connector_AMASS:AMASS_XT60IPW-M_1x03_P7.20mm_Horizontal +Connector_AMASS:AMASS_XT60PW-F_1x02_P7.20mm_Horizontal +Connector_AMASS:AMASS_XT60PW-M_1x02_P7.20mm_Horizontal +Connector_AMASS:AMASS_XT90PW-M_1x02_P10.90mm_Horizontal +Connector_Amphenol:Amphenol_M8S-03PMMR-SF8001 +Connector_Audio:Jack_3.5mm_CUI_SJ-3523-SMT_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ-3524-SMT_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ1-3513N_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ1-3514N_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ1-3515N_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ1-3523N_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ1-3524N_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ1-3525N_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ1-3533NG_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ1-3533NG_Horizontal_CircularHoles +Connector_Audio:Jack_3.5mm_CUI_SJ1-3535NG_Horizontal +Connector_Audio:Jack_3.5mm_CUI_SJ1-3535NG_Horizontal_CircularHoles +Connector_Audio:Jack_3.5mm_CUI_SJ2-3593D-SMT_Horizontal +Connector_Audio:Jack_3.5mm_KoreanHropartsElec_PJ-320D-4A_Horizontal +Connector_Audio:Jack_3.5mm_Ledino_KB3SPRS_Horizontal +Connector_Audio:Jack_3.5mm_Lumberg_1503_02_Horizontal +Connector_Audio:Jack_3.5mm_Lumberg_1503_03_Horizontal +Connector_Audio:Jack_3.5mm_Lumberg_1503_07_Horizontal +Connector_Audio:Jack_3.5mm_PJ31060-I_Horizontal +Connector_Audio:Jack_3.5mm_PJ311_Horizontal +Connector_Audio:Jack_3.5mm_PJ320D_Horizontal +Connector_Audio:Jack_3.5mm_PJ320E_Horizontal +Connector_Audio:Jack_3.5mm_QingPu_WQP-PJ398SM_Vertical_CircularHoles +Connector_Audio:Jack_3.5mm_Switronic_ST-005-G_horizontal +Connector_Audio:Jack_3.5mm_Technik_TWP-3002_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NJ2FD-V_Vertical +Connector_Audio:Jack_6.35mm_Neutrik_NJ3FD-V_Vertical +Connector_Audio:Jack_6.35mm_Neutrik_NJ5FD-V_Vertical +Connector_Audio:Jack_6.35mm_Neutrik_NJ6FD-V_Vertical +Connector_Audio:Jack_6.35mm_Neutrik_NJ6TB-V_Vertical +Connector_Audio:Jack_6.35mm_Neutrik_NMJ4HCD2_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ4HFD2_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ4HFD3_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ4HHD2_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ6HCD2_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ6HCD3_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ6HFD2-AU_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ6HFD2_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ6HFD3_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ6HFD4_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NMJ6HHD2_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ3HF-1_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ4HF-1_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ4HF_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ4HH-1_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ4HH_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HF-1-AU_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HF-1_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HF-AU_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HF_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HH-1_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HH-AU_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HH_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HM-1-AU_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HM-1-PRE_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NRJ6HM-1_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NSJ12HC_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NSJ12HF-1_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NSJ12HH-1_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NSJ12HL_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NSJ8HC_Horizontal +Connector_Audio:Jack_6.35mm_Neutrik_NSJ8HL_Horizontal +Connector_Audio:Jack_speakON-6.35mm_Neutrik_NLJ2MDXX-H_Horizontal +Connector_Audio:Jack_speakON-6.35mm_Neutrik_NLJ2MDXX-V_Vertical +Connector_Audio:Jack_speakON_Neutrik_NL2MDXX-H-3_Horizontal +Connector_Audio:Jack_speakON_Neutrik_NL2MDXX-V_Vertical +Connector_Audio:Jack_speakON_Neutrik_NL4MDXX-H-2_Horizontal +Connector_Audio:Jack_speakON_Neutrik_NL4MDXX-H-3_Horizontal +Connector_Audio:Jack_speakON_Neutrik_NL4MDXX-V-2_Vertical +Connector_Audio:Jack_speakON_Neutrik_NL4MDXX-V-3_Vertical +Connector_Audio:Jack_speakON_Neutrik_NL4MDXX-V_Vertical +Connector_Audio:Jack_speakON_Neutrik_NL8MDXX-V-3_Vertical +Connector_Audio:Jack_speakON_Neutrik_NL8MDXX-V_Vertical +Connector_Audio:Jack_speakON_Neutrik_NLT4MD-V_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ10FI-H-0_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ10FI-H_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ10FI-V-0_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ10FI-V_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ5FI-H-0_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ5FI-H_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ5FI-V-0_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ5FI-V_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FA-H-0_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FA-H-DA_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FA-H_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FA-V-0_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FA-V-DA_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FA-V_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FI-H-0_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FI-H_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FI-V-0_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ6FI-V_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ9FI-H-0_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ9FI-H_Horizontal +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ9FI-V-0_Vertical +Connector_Audio:Jack_XLR-6.35mm_Neutrik_NCJ9FI-V_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAAH-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAAH1-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAAH1-DA_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAAH1_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAAH2-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAAH2_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAAH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAAV-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAAV1-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAAV1-DA_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAAV1_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAAV2-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAAV2_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAAV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAH-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAH1-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAH1-DA_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAH1_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAH2-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAH2-DA_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAH2_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAHL-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAHL1-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAHL1_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAHR-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAHR1-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAHR1_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAHR2-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAHR2_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FAV-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAV1-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAV1-DA_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAV1_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAV2-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAV2-DA_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAV2_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FAV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FBH1-B_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FBH1-DA_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FBH1-E_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FBH1_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FBH2-B_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FBH2-DA_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FBH2-E_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FBH2_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FBHL1_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3FBV1-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FBV1-B_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FBV1-DA_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FBV1_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FBV2-B_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FBV2-DA_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FBV2-SW_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3FBV2_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MAAH-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MAAH-1_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MAAH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MAAV-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MAAV-1_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MAAV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MAFH-PH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MAH-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MAHL_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MAHR_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MAH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MAMH-PH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MAV-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MAV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MBH-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MBH-1_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MBH-B_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MBH-E_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MBHL-B_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MBHL_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MBHR-B_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MBHR_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MBH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC3MBV-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MBV-1_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MBV-B_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MBV-E_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MBV-SW_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC3MBV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC4FAH-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC4FAH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC4FAV-0_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC4FAV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC4FBH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC4FBV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC4MAH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC4MAV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC4MBH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC4MBV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5FAH-0_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC5FAH-DA_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC5FAH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC5FAV-DA_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5FAV-SW_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5FAV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5FBH-B_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC5FBH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC5FBV-B_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5FBV-SW_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5FBV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5MAH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC5MAV-SW_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5MAV_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5MBH-B_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC5MBH_Horizontal +Connector_Audio:Jack_XLR_Neutrik_NC5MBV-B_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5MBV-SW_Vertical +Connector_Audio:Jack_XLR_Neutrik_NC5MBV_Vertical +Connector_Audio:MiniXLR-5_Switchcraft_TRAPC_Horizontal +Connector_Audio:Plug_3.5mm_CUI_SP-3541 +Connector_BarrelJack:BarrelJack_CLIFF_FC681465S_SMT_Horizontal +Connector_BarrelJack:BarrelJack_CUI_PJ-036AH-SMT_Horizontal +Connector_BarrelJack:BarrelJack_CUI_PJ-063AH_Horizontal +Connector_BarrelJack:BarrelJack_CUI_PJ-063AH_Horizontal_CircularHoles +Connector_BarrelJack:BarrelJack_CUI_PJ-079BH_Horizontal +Connector_BarrelJack:BarrelJack_CUI_PJ-102AH_Horizontal +Connector_BarrelJack:BarrelJack_GCT_DCJ200-10-A_Horizontal +Connector_BarrelJack:BarrelJack_Horizontal +Connector_BarrelJack:BarrelJack_Kycon_KLDX-0202-xC_Horizontal +Connector_BarrelJack:BarrelJack_SwitchcraftConxall_RAPC10U_Horizontal +Connector_BarrelJack:BarrelJack_Wuerth_694102107102_1.0x3.9mm +Connector_BarrelJack:BarrelJack_Wuerth_694103107102_1.35x3.9mm +Connector_BarrelJack:BarrelJack_Wuerth_694106106102_2.0x5.5mm +Connector_BarrelJack:BarrelJack_Wuerth_694108106102_2.5x5.5mm +Connector_BarrelJack:BarrelJack_Wuerth_6941xx301002 +Connector_Card:CF-Card_3M_N7E50-A516xx-30 +Connector_Card:CF-Card_3M_N7E50-E516xx-30 +Connector_Card:microSD_HC_Hirose_DM3AT-SF-PEJM5 +Connector_Card:microSD_HC_Hirose_DM3BT-DSF-PEJS +Connector_Card:microSD_HC_Hirose_DM3D-SF +Connector_Card:microSD_HC_Molex_104031-0811 +Connector_Card:microSD_HC_Molex_47219-2001 +Connector_Card:microSD_HC_Wuerth_693072010801 +Connector_Card:microSIM_JAE_SF53S006VCBR2000 +Connector_Card:nanoSIM_GCT_SIM8060-6-0-14-00 +Connector_Card:nanoSIM_GCT_SIM8060-6-1-14-00 +Connector_Card:nanoSIM_Hinged_CUI_NSIM-2-C +Connector_Card:SD-SIM_microSD-microSIM_Molex_104168-1620 +Connector_Card:SD_Card_Device_16mm_SlotDepth +Connector_Card:SD_Hirose_DM1AA_SF_PEJ82 +Connector_Card:SD_Kyocera_145638009211859+ +Connector_Card:SD_Kyocera_145638009511859+ +Connector_Card:SD_Kyocera_145638109211859+ +Connector_Card:SD_Kyocera_145638109511859+ +Connector_Card:SD_TE_2041021 +Connector_Coaxial:BNC_Amphenol_031-5539_Vertical +Connector_Coaxial:BNC_Amphenol_031-6575_Horizontal +Connector_Coaxial:BNC_Amphenol_B6252HB-NPP3G-50_Horizontal +Connector_Coaxial:BNC_PanelMountable_Vertical +Connector_Coaxial:BNC_TEConnectivity_1478035_Horizontal +Connector_Coaxial:BNC_TEConnectivity_1478204_Vertical +Connector_Coaxial:BNC_Win_364A2x95_Horizontal +Connector_Coaxial:CoaxialSwitch_Hirose_MS-156C3_Horizontal +Connector_Coaxial:LEMO-EPG.00.302.NLN +Connector_Coaxial:LEMO-EPL.00.250.NTN +Connector_Coaxial:MMCX_Molex_73415-0961_Horizontal_0.8mm-PCB +Connector_Coaxial:MMCX_Molex_73415-0961_Horizontal_1.0mm-PCB +Connector_Coaxial:MMCX_Molex_73415-0961_Horizontal_1.6mm-PCB +Connector_Coaxial:MMCX_Molex_73415-1471_Vertical +Connector_Coaxial:SMA_Amphenol_132134-10_Vertical +Connector_Coaxial:SMA_Amphenol_132134-11_Vertical +Connector_Coaxial:SMA_Amphenol_132134-14_Vertical +Connector_Coaxial:SMA_Amphenol_132134-16_Vertical +Connector_Coaxial:SMA_Amphenol_132134_Vertical +Connector_Coaxial:SMA_Amphenol_132203-12_Horizontal +Connector_Coaxial:SMA_Amphenol_132289_EdgeMount +Connector_Coaxial:SMA_Amphenol_132291-12_Vertical +Connector_Coaxial:SMA_Amphenol_132291_Vertical +Connector_Coaxial:SMA_Amphenol_901-143_Horizontal +Connector_Coaxial:SMA_Amphenol_901-144_Vertical +Connector_Coaxial:SMA_BAT_Wireless_BWSMA-KWE-Z001 +Connector_Coaxial:SMA_Molex_73251-1153_EdgeMount_Horizontal +Connector_Coaxial:SMA_Molex_73251-2120_EdgeMount_Horizontal +Connector_Coaxial:SMA_Molex_73251-2200_Horizontal +Connector_Coaxial:SMA_Samtec_SMA-J-P-H-ST-EM1_EdgeMount +Connector_Coaxial:SMA_Wurth_60312002114503_Vertical +Connector_Coaxial:SMA_Wurth_60312102114405_Vertical +Connector_Coaxial:SMB_Jack_Vertical +Connector_Coaxial:U.FL_Hirose_U.FL-R-SMT-1_Vertical +Connector_Coaxial:U.FL_Molex_MCRF_73412-0110_Vertical +Connector_Coaxial:WR-MMCX_Wuerth_66011102111302_Horizontal +Connector_Coaxial:WR-MMCX_Wuerth_66012102111404_Vertical +Connector_DIN:DIN41612_B2_2x16_Female_Vertical_THT +Connector_DIN:DIN41612_B2_2x16_Male_Horizontal_THT +Connector_DIN:DIN41612_B2_2x8_Female_Vertical_THT +Connector_DIN:DIN41612_B2_2x8_Male_Horizontal_THT +Connector_DIN:DIN41612_B3_2x10_Female_Vertical_THT +Connector_DIN:DIN41612_B3_2x10_Male_Horizontal_THT +Connector_DIN:DIN41612_B3_2x5_Female_Vertical_THT +Connector_DIN:DIN41612_B3_2x5_Male_Horizontal_THT +Connector_DIN:DIN41612_B_1x32_Female_Vertical_THT +Connector_DIN:DIN41612_B_1x32_Male_Horizontal_THT +Connector_DIN:DIN41612_B_2x16_Female_Vertical_THT +Connector_DIN:DIN41612_B_2x16_Male_Horizontal_THT +Connector_DIN:DIN41612_B_2x32_Female_Vertical_THT +Connector_DIN:DIN41612_B_2x32_Male_Horizontal_THT +Connector_DIN:DIN41612_C2_2x16_Female_Vertical_THT +Connector_DIN:DIN41612_C2_2x16_Male_Horizontal_THT +Connector_DIN:DIN41612_C2_3x16_Female_Vertical_THT +Connector_DIN:DIN41612_C2_3x16_Male_Horizontal_THT +Connector_DIN:DIN41612_C3_2x10_Female_Vertical_THT +Connector_DIN:DIN41612_C3_2x10_Male_Horizontal_THT +Connector_DIN:DIN41612_C3_3x10_Female_Vertical_THT +Connector_DIN:DIN41612_C3_3x10_Male_Horizontal_THT +Connector_DIN:DIN41612_C_1x32_Female_Vertical_THT +Connector_DIN:DIN41612_C_1x32_Male_Horizontal_THT +Connector_DIN:DIN41612_C_2x16_Female_Vertical_THT +Connector_DIN:DIN41612_C_2x16_Male_Horizontal_THT +Connector_DIN:DIN41612_C_2x32_Female_Vertical_THT +Connector_DIN:DIN41612_C_2x32_Male_Horizontal_THT +Connector_DIN:DIN41612_C_3x16_Female_Vertical_THT +Connector_DIN:DIN41612_C_3x16_Male_Horizontal_THT +Connector_DIN:DIN41612_C_3x32_Female_Vertical_THT +Connector_DIN:DIN41612_C_3x32_Male_Horizontal_THT +Connector_DIN:DIN41612_D_2x16_Female_Vertical_THT +Connector_DIN:DIN41612_D_2x16_Male_Horizontal_THT +Connector_DIN:DIN41612_D_2x8_Female_Vertical_THT +Connector_DIN:DIN41612_D_2x8_Male_Horizontal_THT +Connector_DIN:DIN41612_E_2x16_Female_Vertical_THT +Connector_DIN:DIN41612_E_2x16_Male_Horizontal_THT +Connector_DIN:DIN41612_E_2x16_RowsAC_Female_Vertical_THT +Connector_DIN:DIN41612_E_2x16_RowsAC_Male_Horizontal_THT +Connector_DIN:DIN41612_E_3x16_Female_Vertical_THT +Connector_DIN:DIN41612_E_3x16_Male_Horizontal_THT +Connector_DIN:DIN41612_F_2x16_Female_Vertical_THT +Connector_DIN:DIN41612_F_2x16_Male_Horizontal_THT +Connector_DIN:DIN41612_F_2x16_RowsZD_Female_Vertical_THT +Connector_DIN:DIN41612_F_2x16_RowsZD_Male_Horizontal_THT +Connector_DIN:DIN41612_F_3x16_Female_Vertical_THT +Connector_DIN:DIN41612_F_3x16_Male_Horizontal_THT +Connector_DIN:DIN41612_Q2_2x16_Female_Horizontal_THT +Connector_DIN:DIN41612_Q2_2x16_Male_Vertical_THT +Connector_DIN:DIN41612_Q3_2x10_Female_Horizontal_THT +Connector_DIN:DIN41612_Q3_2x10_Male_Vertical_THT +Connector_DIN:DIN41612_Q_2x32_Female_Horizontal_THT +Connector_DIN:DIN41612_Q_2x32_Male_Vertical_THT +Connector_DIN:DIN41612_R2_2x16_Female_Horizontal_THT +Connector_DIN:DIN41612_R2_2x16_Male_Vertical_THT +Connector_DIN:DIN41612_R2_3x16_Female_Horizontal_THT +Connector_DIN:DIN41612_R2_3x16_Male_Vertical_THT +Connector_DIN:DIN41612_R3_2x10_Female_Horizontal_THT +Connector_DIN:DIN41612_R3_2x10_Male_Vertical_THT +Connector_DIN:DIN41612_R3_3x10_Female_Horizontal_THT +Connector_DIN:DIN41612_R3_3x10_Male_Vertical_THT +Connector_DIN:DIN41612_R_1x32_Female_Horizontal_THT +Connector_DIN:DIN41612_R_1x32_Male_Vertical_THT +Connector_DIN:DIN41612_R_2x16_Female_Horizontal_THT +Connector_DIN:DIN41612_R_2x16_Male_Vertical_THT +Connector_DIN:DIN41612_R_2x32_Female_Horizontal_THT +Connector_DIN:DIN41612_R_2x32_Male_Vertical_THT +Connector_DIN:DIN41612_R_3x16_Female_Horizontal_THT +Connector_DIN:DIN41612_R_3x16_Male_Vertical_THT +Connector_DIN:DIN41612_R_3x32_Female_Horizontal_THT +Connector_DIN:DIN41612_R_3x32_Male_Vertical_THT +Connector_Dsub:DSUB-15-HD_Pins_Horizontal_P2.29x1.90mm_EdgePinOffset3.03mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-15-HD_Pins_Horizontal_P2.29x2.54mm_EdgePinOffset8.35mm_Housed_MountingHolesOffset10.89mm +Connector_Dsub:DSUB-15-HD_Pins_Vertical_P2.29x1.98mm_MountingHoles +Connector_Dsub:DSUB-15-HD_Socket_Horizontal_P2.29x1.90mm_EdgePinOffset3.03mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-15-HD_Socket_Horizontal_P2.29x2.54mm_EdgePinOffset8.35mm_Housed_MountingHolesOffset10.89mm +Connector_Dsub:DSUB-15-HD_Socket_Vertical_P2.29x1.98mm_MountingHoles +Connector_Dsub:DSUB-15_Pins_EdgeMount_P2.77mm +Connector_Dsub:DSUB-15_Pins_Horizontal_P2.77x2.54mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-15_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset15.98mm +Connector_Dsub:DSUB-15_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset8.20mm +Connector_Dsub:DSUB-15_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset4.94mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-15_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset7.70mm_Housed_MountingHolesOffset9.12mm +Connector_Dsub:DSUB-15_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-15_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset9.90mm_Housed_MountingHolesOffset11.32mm +Connector_Dsub:DSUB-15_Pins_Vertical_P2.77x2.84mm +Connector_Dsub:DSUB-15_Pins_Vertical_P2.77x2.84mm_MountingHoles +Connector_Dsub:DSUB-15_Socket_EdgeMount_P2.77mm +Connector_Dsub:DSUB-15_Socket_Horizontal_P2.77x2.54mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-15_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset15.98mm +Connector_Dsub:DSUB-15_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset8.20mm +Connector_Dsub:DSUB-15_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset4.94mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-15_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset7.70mm_Housed_MountingHolesOffset9.12mm +Connector_Dsub:DSUB-15_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-15_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset9.90mm_Housed_MountingHolesOffset11.32mm +Connector_Dsub:DSUB-15_Socket_Vertical_P2.77x2.84mm +Connector_Dsub:DSUB-15_Socket_Vertical_P2.77x2.84mm_MountingHoles +Connector_Dsub:DSUB-25_Pins_EdgeMount_P2.77mm +Connector_Dsub:DSUB-25_Pins_Horizontal_P2.77x2.54mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-25_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset15.98mm +Connector_Dsub:DSUB-25_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset8.20mm +Connector_Dsub:DSUB-25_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset4.94mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-25_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset7.70mm_Housed_MountingHolesOffset9.12mm +Connector_Dsub:DSUB-25_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-25_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset9.90mm_Housed_MountingHolesOffset11.32mm +Connector_Dsub:DSUB-25_Pins_Vertical_P2.77x2.84mm +Connector_Dsub:DSUB-25_Pins_Vertical_P2.77x2.84mm_MountingHoles +Connector_Dsub:DSUB-25_Socket_EdgeMount_P2.77mm +Connector_Dsub:DSUB-25_Socket_Horizontal_P2.77x2.54mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-25_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset15.98mm +Connector_Dsub:DSUB-25_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset8.20mm +Connector_Dsub:DSUB-25_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset4.94mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-25_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset7.70mm_Housed_MountingHolesOffset9.12mm +Connector_Dsub:DSUB-25_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-25_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset9.90mm_Housed_MountingHolesOffset11.32mm +Connector_Dsub:DSUB-25_Socket_Vertical_P2.77x2.84mm +Connector_Dsub:DSUB-25_Socket_Vertical_P2.77x2.84mm_MountingHoles +Connector_Dsub:DSUB-26-HD_Pins_Horizontal_P2.29x1.90mm_EdgePinOffset3.03mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-26-HD_Pins_Horizontal_P2.29x2.54mm_EdgePinOffset8.35mm_Housed_MountingHolesOffset10.89mm +Connector_Dsub:DSUB-26-HD_Pins_Vertical_P2.29x1.98mm_MountingHoles +Connector_Dsub:DSUB-26-HD_Socket_Horizontal_P2.29x1.90mm_EdgePinOffset3.03mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-26-HD_Socket_Horizontal_P2.29x2.54mm_EdgePinOffset8.35mm_Housed_MountingHolesOffset10.89mm +Connector_Dsub:DSUB-26-HD_Socket_Vertical_P2.29x1.98mm_MountingHoles +Connector_Dsub:DSUB-37_Pins_EdgeMount_P2.77mm +Connector_Dsub:DSUB-37_Pins_Horizontal_P2.77x2.54mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-37_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset15.98mm +Connector_Dsub:DSUB-37_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset8.20mm +Connector_Dsub:DSUB-37_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset4.94mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-37_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset7.70mm_Housed_MountingHolesOffset9.12mm +Connector_Dsub:DSUB-37_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-37_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset9.90mm_Housed_MountingHolesOffset11.32mm +Connector_Dsub:DSUB-37_Pins_Vertical_P2.77x2.84mm +Connector_Dsub:DSUB-37_Pins_Vertical_P2.77x2.84mm_MountingHoles +Connector_Dsub:DSUB-37_Socket_EdgeMount_P2.77mm +Connector_Dsub:DSUB-37_Socket_Horizontal_P2.77x2.54mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-37_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset15.98mm +Connector_Dsub:DSUB-37_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset8.20mm +Connector_Dsub:DSUB-37_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset4.94mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-37_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset7.70mm_Housed_MountingHolesOffset9.12mm +Connector_Dsub:DSUB-37_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-37_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset9.90mm_Housed_MountingHolesOffset11.32mm +Connector_Dsub:DSUB-37_Socket_Vertical_P2.77x2.84mm +Connector_Dsub:DSUB-37_Socket_Vertical_P2.77x2.84mm_MountingHoles +Connector_Dsub:DSUB-44-HD_Pins_Horizontal_P2.29x1.90mm_EdgePinOffset3.03mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-44-HD_Pins_Horizontal_P2.29x2.54mm_EdgePinOffset8.35mm_Housed_MountingHolesOffset10.89mm +Connector_Dsub:DSUB-44-HD_Pins_Vertical_P2.29x1.98mm_MountingHoles +Connector_Dsub:DSUB-44-HD_Socket_Horizontal_P2.29x1.90mm_EdgePinOffset3.03mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-44-HD_Socket_Horizontal_P2.29x2.54mm_EdgePinOffset8.35mm_Housed_MountingHolesOffset10.89mm +Connector_Dsub:DSUB-44-HD_Socket_Vertical_P2.29x1.98mm_MountingHoles +Connector_Dsub:DSUB-62-HD_Pins_Horizontal_P2.41x1.90mm_EdgePinOffset3.03mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-62-HD_Pins_Horizontal_P2.41x2.54mm_EdgePinOffset8.35mm_Housed_MountingHolesOffset10.89mm +Connector_Dsub:DSUB-62-HD_Pins_Vertical_P2.41x1.98mm_MountingHoles +Connector_Dsub:DSUB-62-HD_Socket_Horizontal_P2.41x1.90mm_EdgePinOffset3.03mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-62-HD_Socket_Horizontal_P2.41x2.54mm_EdgePinOffset8.35mm_Housed_MountingHolesOffset10.89mm +Connector_Dsub:DSUB-62-HD_Socket_Vertical_P2.41x1.98mm_MountingHoles +Connector_Dsub:DSUB-9_Pins_EdgeMount_P2.77mm +Connector_Dsub:DSUB-9_Pins_Horizontal_P2.77x2.54mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-9_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset15.98mm +Connector_Dsub:DSUB-9_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset8.20mm +Connector_Dsub:DSUB-9_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset4.94mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-9_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset7.70mm_Housed_MountingHolesOffset9.12mm +Connector_Dsub:DSUB-9_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-9_Pins_Horizontal_P2.77x2.84mm_EdgePinOffset9.90mm_Housed_MountingHolesOffset11.32mm +Connector_Dsub:DSUB-9_Pins_Vertical_P2.77x2.84mm +Connector_Dsub:DSUB-9_Pins_Vertical_P2.77x2.84mm_MountingHoles +Connector_Dsub:DSUB-9_Socket_EdgeMount_P2.77mm +Connector_Dsub:DSUB-9_Socket_Horizontal_P2.77x2.54mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-9_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset15.98mm +Connector_Dsub:DSUB-9_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset14.56mm_Housed_MountingHolesOffset8.20mm +Connector_Dsub:DSUB-9_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset4.94mm_Housed_MountingHolesOffset4.94mm +Connector_Dsub:DSUB-9_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset7.70mm_Housed_MountingHolesOffset9.12mm +Connector_Dsub:DSUB-9_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset9.40mm +Connector_Dsub:DSUB-9_Socket_Horizontal_P2.77x2.84mm_EdgePinOffset9.90mm_Housed_MountingHolesOffset11.32mm +Connector_Dsub:DSUB-9_Socket_Vertical_P2.77x2.84mm +Connector_Dsub:DSUB-9_Socket_Vertical_P2.77x2.84mm_MountingHoles +Connector_FFC-FPC:Hirose_FH12-10S-0.5SH_1x10-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-11S-0.5SH_1x11-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-12S-0.5SH_1x12-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-13S-0.5SH_1x13-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-14S-0.5SH_1x14-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-15S-0.5SH_1x15-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-16S-0.5SH_1x16-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-17S-0.5SH_1x17-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-18S-0.5SH_1x18-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-19S-0.5SH_1x19-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-20S-0.5SH_1x20-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-22S-0.5SH_1x22-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-24S-0.5SH_1x24-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-25S-0.5SH_1x25-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-26S-0.5SH_1x26-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-28S-0.5SH_1x28-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-30S-0.5SH_1x30-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-32S-0.5SH_1x32-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-33S-0.5SH_1x33-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-34S-0.5SH_1x34-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-35S-0.5SH_1x35-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-36S-0.5SH_1x36-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-40S-0.5SH_1x40-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-45S-0.5SH_1x45-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-50S-0.5SH_1x50-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-53S-0.5SH_1x53-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-6S-0.5SH_1x06-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH12-8S-0.5SH_1x08-1MP_P0.50mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-13S-0.3SHW_2Rows-13Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-15S-0.3SHW_2Rows-15Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-17S-0.3SHW_2Rows-17Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-19S-0.3SHW_2Rows-19Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-21S-0.3SHW_2Rows-21Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-23S-0.3SHW_2Rows-23Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-25S-0.3SHW_2Rows-25Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-27S-0.3SHW_2Rows-27Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-29S-0.3SHW_2Rows-29Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-31S-0.3SHW_2Rows-31Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-33S-0.3SHW_2Rows-33Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-35S-0.3SHW_2Rows-35Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-37S-0.3SHW_2Rows-37Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-39S-0.3SHW_2Rows-39Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-41S-0.3SHW_2Rows-41Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-45S-0.3SHW_2Rows-45Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-51S-0.3SHW_2Rows-51Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-55S-0.3SHW_2Rows-55Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-57S-0.3SHW_2Rows-57Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-61S-0.3SHW_2Rows-61Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH26-71S-0.3SHW_2Rows-71Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Hirose_FH41-30S-0.5SH_1x30_1MP_1SH_P0.5mm_Horizontal +Connector_FFC-FPC:JAE_FF0825SA1_2Rows-25Pins_P0.40mm_Horizontal +Connector_FFC-FPC:JAE_FF0829SA1_2Rows-29Pins_P0.40mm_Horizontal +Connector_FFC-FPC:JAE_FF0841SA1_2Rows-41Pins_P0.40mm_Horizontal +Connector_FFC-FPC:JAE_FF0851SA1_2Rows-51Pins_P0.40mm_Horizontal +Connector_FFC-FPC:JAE_FF0871SA1_2Rows-71Pins_P0.40mm_Horizontal +Connector_FFC-FPC:JAE_FF0881SA1_2Rows-81Pins_P0.40mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S04FCA-00_1x4-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S05FCA-00_1x5-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S06FCA-00_1x6-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S07FCA-00_1x7-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S08FCA-00_1x8-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S09FCA-00_1x9-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S10FCA-00_1x10-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S11FCA-00_1x11-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S12FCA-00_1x12-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S13FCA-00_1x13-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S14FCA-00_1x14-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S15FCA-00_1x15-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S16FCA-00_1x16-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S17FCA-00_1x17-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S18FCA-00_1x18-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S19FCA-00_1x19-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S20FCA-00_1x20-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S21FCA-00_1x21-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S22FCA-00_1x22-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S23FCA-00_1x23-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S24FCA-00_1x24-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S25FCA-00_1x25-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S26FCA-00_1x26-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S27FCA-00_1x27-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S28FCA-00_1x28-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:JUSHUO_AFA07-S29FCA-00_1x29-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:Jushuo_AFC07-S06FCA-00_1x6-1MP_P0.50_Horizontal +Connector_FFC-FPC:Jushuo_AFC07-S24FCA-00_1x24-1MP_P0.50_Horizontal +Connector_FFC-FPC:Molex_200528-0040_1x04-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0050_1x05-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0060_1x06-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0070_1x07-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0080_1x08-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0090_1x09-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0100_1x10-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0110_1x11-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0120_1x12-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0130_1x13-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0140_1x14-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0150_1x15-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0160_1x16-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0170_1x17-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0180_1x18-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0190_1x19-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0200_1x20-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0210_1x21-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0220_1x22-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0230_1x23-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0240_1x24-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0250_1x25-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0260_1x26-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0270_1x27-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0280_1x28-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0290_1x29-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_200528-0300_1x30-1MP_P1.00mm_Horizontal +Connector_FFC-FPC:Molex_502231-1500_1x15-1SH_P0.5mm_Vertical +Connector_FFC-FPC:Molex_502231-2400_1x24-1SH_P0.5mm_Vertical +Connector_FFC-FPC:Molex_502231-3300_1x33-1SH_P0.5mm_Vertical +Connector_FFC-FPC:Molex_502244-1530_1x15-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:Molex_502244-2430_1x24-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:Molex_502244-3330_1x33-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:Molex_502250-1791_2Rows-17Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Molex_502250-2191_2Rows-21Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Molex_502250-2391_2Rows-23Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Molex_502250-2791_2Rows-27Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Molex_502250-3391_2Rows-33Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Molex_502250-3591_2Rows-35Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Molex_502250-3991_2Rows-39Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Molex_502250-4191_2Rows-41Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Molex_502250-5191_2Rows-51Pins-1MP_P0.60mm_Horizontal +Connector_FFC-FPC:Molex_52559-3652_2x18-1MP_P0.5mm_Vertical +Connector_FFC-FPC:Molex_54132-5033_1x50-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:Molex_54548-1071_1x10-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:Omron_XF2M-4015-1A_1x40-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_0-1734839-5_1x05-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_0-1734839-6_1x06-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_0-1734839-7_1x07-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_0-1734839-8_1x08-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_0-1734839-9_1x09-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-0_1x10-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-1_1x11-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-2_1x12-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-3_1x13-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-4_1x14-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-5_1x15-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-6_1x16-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-7_1x17-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-8_1x18-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-1734839-9_1x19-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_1-84952-0_1x10-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84952-1_1x11-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84952-2_1x12-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84952-3_1x13-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84952-4_1x14-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84952-5_1x15-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84952-6_1x16-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84952-7_1x17-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84952-8_1x18-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84952-9_1x19-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-0_1x10-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-1_1x11-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-2_1x12-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-3_1x13-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-4_1x14-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-5_1x15-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-6_1x16-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-7_1x17-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-8_1x18-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_1-84953-9_1x19-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-0_1x20-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-1_1x21-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-2_1x22-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-3_1x23-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-4_1x24-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-5_1x25-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-6_1x26-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-7_1x27-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-8_1x28-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-1734839-9_1x29-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_2-84952-0_1x20-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84952-1_1x21-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84952-2_1x22-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84952-3_1x23-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84952-4_1x24-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84952-5_1x25-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84952-6_1x26-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84952-7_1x27-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84952-8_1x28-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84952-9_1x29-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-0_1x20-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-1_1x21-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-2_1x22-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-3_1x23-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-4_1x24-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-5_1x25-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-6_1x26-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-7_1x27-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-8_1x28-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_2-84953-9_1x29-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-0_1x30-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-1_1x31-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-2_1x32-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-3_1x33-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-4_1x34-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-5_1x35-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-6_1x36-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-7_1x37-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-8_1x38-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-1734839-9_1x39-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_3-84952-0_1x30-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_3-84953-0_1x30-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-0_1x40-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-1_1x41-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-2_1x42-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-3_1x43-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-4_1x44-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-5_1x45-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-6_1x46-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-7_1x47-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-8_1x48-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_4-1734839-9_1x49-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_5-1734839-0_1x50-1MP_P0.5mm_Horizontal +Connector_FFC-FPC:TE_84952-4_1x04-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84952-5_1x05-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84952-6_1x06-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84952-7_1x07-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84952-8_1x08-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84952-9_1x09-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84953-4_1x04-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84953-5_1x05-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84953-6_1x06-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84953-7_1x07-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84953-8_1x08-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:TE_84953-9_1x09-1MP_P1.0mm_Horizontal +Connector_FFC-FPC:Wuerth_68611214422_1x12-1MP_P1.0mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110213001xxx_1x02-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14110213002xxx_1x02-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110213010xxx_1x02-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110313001xxx_1x03-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14110313002xxx_1x03-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110313010xxx_1x03-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110413001xxx_1x04-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14110413002xxx_1x04-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110413010xxx_1x04-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110513001xxx_1x05-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14110513002xxx_1x05-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110513010xxx_1x05-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110613001xxx_1x06-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14110613002xxx_1x06-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110613010xxx_1x06-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110713001xxx_1x07-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14110713002xxx_1x07-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110713010xxx_1x07-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110813001xxx_1x08-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14110813002xxx_1x08-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110813010xxx_1x08-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110913001xxx_1x09-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14110913002xxx_1x09-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14110913010xxx_1x09-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14111013001xxx_1x10-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14111013002xxx_1x10-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14111013010xxx_1x10-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14111113001xxx_1x11-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14111113002xxx_1x11-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14111113010xxx_1x11-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14111213001xxx_1x12-MP_P2.54mm_Vertical +Connector_Harting:Harting_har-flexicon_14111213002xxx_1x12-MP_P2.54mm_Horizontal +Connector_Harting:Harting_har-flexicon_14111213010xxx_1x12-MP_P2.54mm_Horizontal +Connector_Harwin:Harwin_Gecko-G125-FVX0605L0X_2x03_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-FVX1005L0X_2x05_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-FVX1205L0X_2x06_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-FVX1605L0X_2x08_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-FVX2005L0X_2x10_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-FVX2605L0X_2x13_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-FVX3405L0X_2x17_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-FVX5005L0X_2x25_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX0605L0X_2x03_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX0605L1X_2x03_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX1005L0X_2x05_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX1005L1X_2x05_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX1205L0X_2x06_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX1205L1X_2x06_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX1605L0X_2x08_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX1605L1X_2x08_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX2005L0X_2x10_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX2005L1X_2x10_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX2605L0X_2x13_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX2605L1X_2x13_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX3405L0X_2x17_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX3405L1X_2x17_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX5005L0X_2x25_P1.25mm_Vertical +Connector_Harwin:Harwin_Gecko-G125-MVX5005L1X_2x25_P1.25mm_Vertical +Connector_Harwin:Harwin_LTek-Male_02_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_02_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_03_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_03_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_04_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_04_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_05_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_05_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_06_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_06_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_07_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_07_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_17_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_17_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_22_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_22_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x02_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x02_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x03_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x03_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x04_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x04_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x05_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x05_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x06_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x06_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x07_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x07_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x08_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x08_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x09_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x09_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x10_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x10_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x13_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x13_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x17_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x17_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_LTek-Male_2x22_P2.00mm_Vertical +Connector_Harwin:Harwin_LTek-Male_2x22_P2.00mm_Vertical_StrainRelief +Connector_Harwin:Harwin_M20-7810245_2x02_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7810345_2x03_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7810445_2x04_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7810545_2x05_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7810645_2x06_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7810745_2x07_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7810845_2x08_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7810945_2x09_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7811045_2x10_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7811245_2x12_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7811545_2x15_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-7812045_2x20_P2.54mm_Vertical +Connector_Harwin:Harwin_M20-89003xx_1x03_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89004xx_1x04_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89005xx_1x05_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89006xx_1x06_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89007xx_1x07_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89008xx_1x08_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89009xx_1x09_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89010xx_1x10_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89011xx_1x11_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89012xx_1x12_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89013xx_1x13_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89014xx_1x14_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89015xx_1x15_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89016xx_1x16_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89017xx_1x17_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89018xx_1x18_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89019xx_1x19_P2.54mm_Horizontal +Connector_Harwin:Harwin_M20-89020xx_1x20_P2.54mm_Horizontal +Connector_Hirose:Hirose_BM23FR0.6-16DP-0.35V_2x08_1MP_Vertical +Connector_Hirose:Hirose_BM23FR0.6-16DS-0.35V_2x08_P0.35_1MP_Vertical +Connector_Hirose:Hirose_BM24_BM24-40DP-2-0.35V_2x20_P0.35mm_PowerPin2_Vertical +Connector_Hirose:Hirose_BM24_BM24-40DS-2-0.35V_2x20_P0.35mm_PowerPin2_Vertical +Connector_Hirose:Hirose_DF11-10DP-2DSA_2x05_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-12DP-2DSA_2x06_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-14DP-2DSA_2x07_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-16DP-2DSA_2x08_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-18DP-2DSA_2x09_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-20DP-2DSA_2x10_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-22DP-2DSA_2x11_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-24DP-2DSA_2x12_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-26DP-2DSA_2x13_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-28DP-2DSA_2x14_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-30DP-2DSA_2x15_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-32DP-2DSA_2x16_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-4DP-2DSA_2x02_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-6DP-2DSA_2x03_P2.00mm_Vertical +Connector_Hirose:Hirose_DF11-8DP-2DSA_2x04_P2.00mm_Vertical +Connector_Hirose:Hirose_DF12_DF12C3.0-10DS-0.5V_2x05_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12C3.0-14DS-0.5V_2x07_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12C3.0-20DS-0.5V_2x10_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12C3.0-30DS-0.5V_2x15_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12C3.0-32DS-0.5V_2x16_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12C3.0-36DS-0.5V_2x18_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12C3.0-40DS-0.5V_2x20_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12C3.0-50DS-0.5V_2x25_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12C3.0-60DS-0.5V_2x30_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-10DP-0.5V_2x05_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-14DP-0.5V_2x07_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-20DP-0.5V_2x10_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-30DP-0.5V_2x15_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-32DP-0.5V_2x16_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-36DP-0.5V_2x18_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-40DP-0.5V_2x20_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-50DP-0.5V_2x25_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-60DP-0.5V_2x30_P0.50mm_Vertical +Connector_Hirose:Hirose_DF12_DF12E3.0-80DP-0.5V_2x40_P0.50mm_Vertical +Connector_Hirose:Hirose_DF13-02P-1.25DSA_1x02_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-02P-1.25DS_1x02_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-03P-1.25DSA_1x03_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-03P-1.25DS_1x03_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-04P-1.25DSA_1x04_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-04P-1.25DS_1x04_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-05P-1.25DSA_1x05_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-05P-1.25DS_1x05_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-06P-1.25DSA_1x06_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-06P-1.25DS_1x06_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-07P-1.25DSA_1x07_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-07P-1.25DS_1x07_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-08P-1.25DSA_1x08_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-08P-1.25DS_1x08_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-09P-1.25DSA_1x09_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-09P-1.25DS_1x09_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-10P-1.25DSA_1x10_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-10P-1.25DS_1x10_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-11P-1.25DSA_1x11_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-11P-1.25DS_1x11_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-12P-1.25DSA_1x12_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-12P-1.25DS_1x12_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-13P-1.25DSA_1x13_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-14P-1.25DSA_1x14_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-14P-1.25DS_1x14_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13-15P-1.25DSA_1x15_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13-15P-1.25DS_1x15_P1.25mm_Horizontal +Connector_Hirose:Hirose_DF13C_CL535-0402-2-51_1x02-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0403-5-51_1x03-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0404-8-51_1x04-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0405-0-51_1x05-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0406-3-51_1x06-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0407-6-51_1x07-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0408-9-51_1x08-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0409-1-51_1x09-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0410-4-51_1x10-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0411-3-51_1x11-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0412-6-51_1x12-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0414-1-51_1x14-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF13C_CL535-0415-4-51_1x15-1MP_P1.25mm_Vertical +Connector_Hirose:Hirose_DF3EA-02P-2H_1x02-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-03P-2H_1x03-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-04P-2H_1x04-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-05P-2H_1x05-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-06P-2H_1x06-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-07P-2H_1x07-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-08P-2H_1x08-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-09P-2H_1x09-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-10P-2H_1x10-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-11P-2H_1x11-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-12P-2H_1x12-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-13P-2H_1x13-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-14P-2H_1x14-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF3EA-15P-2H_1x15-1MP_P2.00mm_Horizontal +Connector_Hirose:Hirose_DF52-10S-0.8H_1x10-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-11S-0.8H_1x11-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-12S-0.8H_1x12-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-14S-0.8H_1x14-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-15S-0.8H_1x15-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-2S-0.8H_1x02-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-3S-0.8H_1x03-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-4S-0.8H_1x04-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-5S-0.8H_1x05-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-6S-0.8H_1x06-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-7S-0.8H_1x07-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-8S-0.8H_1x08-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF52-9S-0.8H_1x09-1MP_P0.80mm_Horizontal +Connector_Hirose:Hirose_DF63-5P-3.96DSA_1x05_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63-6P-3.96DSA_1x06_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63M-1P-3.96DSA_1x01_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63M-2P-3.96DSA_1x02_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63M-3P-3.96DSA_1x03_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63M-4P-3.96DSA_1x04_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63R-1P-3.96DSA_1x01_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63R-2P-3.96DSA_1x02_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63R-3P-3.96DSA_1x03_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63R-4P-3.96DSA_1x04_P3.96mm_Vertical +Connector_Hirose:Hirose_DF63R-5P-3.96DSA_1x05_P3.96mm_Vertical +Connector_Hirose_FX8:Hirose_FX8-100P-SV_2x50_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-100S-SV_2x50_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-120P-SV_2x60_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-120S-SV_2x60_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-140P-SV_2x70_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-140S-SV_2x70_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-60P-SV_2x30_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-60S-SV_2x30_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-80P-SV_2x40_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-80S-SV_2x40_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-90P-SV_2x45_P0.6mm +Connector_Hirose_FX8:Hirose_FX8-90S-SV_2x45_P0.6mm +Connector_IDC:IDC-Header_2x03_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x03_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x03_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x04_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x04_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x04_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x05-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x05-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x05-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x05-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x05-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x05_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x05_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x05_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x05_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x05_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x05_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x05_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x05_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x06-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x06-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x06-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x06-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x06-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x06_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x06_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x06_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x06_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x06_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x06_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x06_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x06_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x07-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x07-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x07-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x07-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x07-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x07_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x07_P2.54mm_Horizontal_Lock +Connector_IDC:IDC-Header_2x07_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x07_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x07_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x07_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x07_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x07_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x07_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x08-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x08-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x08-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x08-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x08-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x08_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x08_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x08_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x08_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x08_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x08_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x08_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x08_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x09_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x09_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x09_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x10-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x10-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x10-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x10-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x10-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x10_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x10_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x10_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x10_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x10_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x10_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x10_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x10_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x11_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x11_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x11_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x12-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x12-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x12-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x12-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x12-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x12_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x12_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x12_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x12_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x12_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x12_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x12_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x12_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x13-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x13-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x13-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x13-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x13-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x13_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x13_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x13_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x13_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x13_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x13_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x13_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x13_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x15-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x15-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x15-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x15-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x15-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x15_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x15_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x15_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x15_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x15_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x15_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x15_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x17-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x17-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x17-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x17-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x17-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x17_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x17_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x17_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x17_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x17_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x17_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x17_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x20-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x20-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x20-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x20-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x20-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x20_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x20_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x20_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x20_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x20_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x20_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x20_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x20_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x22_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x22_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x22_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x25-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x25-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x25-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x25-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x25-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x25_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x25_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x25_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x25_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x25_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x25_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x25_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x25_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x30-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x30-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x30-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x30-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x30-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x30_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x30_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x30_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x30_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x30_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x30_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x30_P2.54mm_Vertical +Connector_IDC:IDC-Header_2x30_P2.54mm_Vertical_SMD +Connector_IDC:IDC-Header_2x32-1MP_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x32-1MP_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x32-1MP_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x32-1MP_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x32-1MP_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x32_P2.54mm_Horizontal +Connector_IDC:IDC-Header_2x32_P2.54mm_Latch12.0mm_Vertical +Connector_IDC:IDC-Header_2x32_P2.54mm_Latch6.5mm_Vertical +Connector_IDC:IDC-Header_2x32_P2.54mm_Latch9.5mm_Vertical +Connector_IDC:IDC-Header_2x32_P2.54mm_Latch_Horizontal +Connector_IDC:IDC-Header_2x32_P2.54mm_Latch_Vertical +Connector_IDC:IDC-Header_2x32_P2.54mm_Vertical +Connector_JAE:JAE_LY20-10P-DLT1_2x05_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-10P-DT1_2x05_P2.00mm_Vertical +Connector_JAE:JAE_LY20-12P-DLT1_2x06_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-12P-DT1_2x06_P2.00mm_Vertical +Connector_JAE:JAE_LY20-14P-DLT1_2x07_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-14P-DT1_2x07_P2.00mm_Vertical +Connector_JAE:JAE_LY20-16P-DLT1_2x08_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-16P-DT1_2x08_P2.00mm_Vertical +Connector_JAE:JAE_LY20-18P-DLT1_2x09_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-18P-DT1_2x09_P2.00mm_Vertical +Connector_JAE:JAE_LY20-20P-DLT1_2x10_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-20P-DT1_2x10_P2.00mm_Vertical +Connector_JAE:JAE_LY20-22P-DLT1_2x11_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-22P-DT1_2x11_P2.00mm_Vertical +Connector_JAE:JAE_LY20-24P-DLT1_2x12_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-24P-DT1_2x12_P2.00mm_Vertical +Connector_JAE:JAE_LY20-26P-DLT1_2x13_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-26P-DT1_2x13_P2.00mm_Vertical +Connector_JAE:JAE_LY20-28P-DLT1_2x14_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-28P-DT1_2x14_P2.00mm_Vertical +Connector_JAE:JAE_LY20-30P-DLT1_2x15_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-30P-DT1_2x15_P2.00mm_Vertical +Connector_JAE:JAE_LY20-32P-DLT1_2x16_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-32P-DT1_2x16_P2.00mm_Vertical +Connector_JAE:JAE_LY20-34P-DLT1_2x17_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-34P-DT1_2x17_P2.00mm_Vertical +Connector_JAE:JAE_LY20-36P-DLT1_2x18_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-36P-DT1_2x18_P2.00mm_Vertical +Connector_JAE:JAE_LY20-38P-DLT1_2x19_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-38P-DT1_2x19_P2.00mm_Vertical +Connector_JAE:JAE_LY20-40P-DLT1_2x20_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-40P-DT1_2x20_P2.00mm_Vertical +Connector_JAE:JAE_LY20-42P-DLT1_2x21_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-42P-DT1_2x21_P2.00mm_Vertical +Connector_JAE:JAE_LY20-44P-DLT1_2x22_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-44P-DT1_2x22_P2.00mm_Vertical +Connector_JAE:JAE_LY20-4P-DLT1_2x02_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-4P-DT1_2x02_P2.00mm_Vertical +Connector_JAE:JAE_LY20-6P-DLT1_2x03_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-6P-DT1_2x03_P2.00mm_Vertical +Connector_JAE:JAE_LY20-8P-DLT1_2x04_P2.00mm_Horizontal +Connector_JAE:JAE_LY20-8P-DT1_2x04_P2.00mm_Vertical +Connector_JAE:JAE_MM70-314-310B1 +Connector_JAE:JAE_SIM_Card_SF72S006 +Connector_JAE_WP7B:JAE_WP7B-P034VA1-R8000_2x17-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-P034VA1-R8000_Longpads_2x17-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-P040VA1-R8000_2x20-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-P040VA1-R8000_Longpads_2x20-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-P050VA1-R8000_2x25-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-P050VA1-R8000_Longpads_2x25-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-P060VA1-R8000_2x30-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-P060VA1-R8000_Longpads_2x30-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-P070VA1-R8000_2x35-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-P070VA1-R8000_Longpads_2x35-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S034VA1-R8000_2x17-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S034VA1-R8000_Longpads_2x17-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S040VA1-R8000_2x20-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S040VA1-R8000_Longpads_2x20-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S050VA1-R8000_2x25-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S050VA1-R8000_Longpads_2x25-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S060VA1-R8000_2x30-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S060VA1-R8000_Longpads_2x30-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S070VA1-R8000_2x35-1MP_P0.4mm +Connector_JAE_WP7B:JAE_WP7B-S070VA1-R8000_Longpads_2x35-1MP_P0.4mm +Connector_JST:JST_ACH_BM01B-ACHSS-A-GAN-ETF_1x01-1MP_P1.20mm_Vertical +Connector_JST:JST_ACH_BM02B-ACHSS-GAN-ETF_1x02-1MP_P1.20mm_Vertical +Connector_JST:JST_ACH_BM03B-ACHSS-GAN-ETF_1x03-1MP_P1.20mm_Vertical +Connector_JST:JST_ACH_BM04B-ACHSS-A-GAN-ETF_1x04-1MP_P1.20mm_Vertical +Connector_JST:JST_ACH_BM05B-ACHSS-A-GAN-ETF_1x05-1MP_P1.20mm_Vertical +Connector_JST:JST_AUH_BM03B-AUHKS-GA-TB_1x03-1MP_P1.50mm_Vertical +Connector_JST:JST_AUH_BM05B-AUHKS-GA-TB_1x05-1MP_P1.50mm_Vertical +Connector_JST:JST_EH_B10B-EH-A_1x10_P2.50mm_Vertical +Connector_JST:JST_EH_B11B-EH-A_1x11_P2.50mm_Vertical +Connector_JST:JST_EH_B12B-EH-A_1x12_P2.50mm_Vertical +Connector_JST:JST_EH_B13B-EH-A_1x13_P2.50mm_Vertical +Connector_JST:JST_EH_B14B-EH-A_1x14_P2.50mm_Vertical +Connector_JST:JST_EH_B15B-EH-A_1x15_P2.50mm_Vertical +Connector_JST:JST_EH_B2B-EH-A_1x02_P2.50mm_Vertical +Connector_JST:JST_EH_B3B-EH-A_1x03_P2.50mm_Vertical +Connector_JST:JST_EH_B4B-EH-A_1x04_P2.50mm_Vertical +Connector_JST:JST_EH_B5B-EH-A_1x05_P2.50mm_Vertical +Connector_JST:JST_EH_B6B-EH-A_1x06_P2.50mm_Vertical +Connector_JST:JST_EH_B7B-EH-A_1x07_P2.50mm_Vertical +Connector_JST:JST_EH_B8B-EH-A_1x08_P2.50mm_Vertical +Connector_JST:JST_EH_B9B-EH-A_1x09_P2.50mm_Vertical +Connector_JST:JST_EH_S10B-EH_1x10_P2.50mm_Horizontal +Connector_JST:JST_EH_S11B-EH_1x11_P2.50mm_Horizontal +Connector_JST:JST_EH_S12B-EH_1x12_P2.50mm_Horizontal +Connector_JST:JST_EH_S13B-EH_1x13_P2.50mm_Horizontal +Connector_JST:JST_EH_S14B-EH_1x14_P2.50mm_Horizontal +Connector_JST:JST_EH_S15B-EH_1x15_P2.50mm_Horizontal +Connector_JST:JST_EH_S2B-EH_1x02_P2.50mm_Horizontal +Connector_JST:JST_EH_S3B-EH_1x03_P2.50mm_Horizontal +Connector_JST:JST_EH_S4B-EH_1x04_P2.50mm_Horizontal +Connector_JST:JST_EH_S5B-EH_1x05_P2.50mm_Horizontal +Connector_JST:JST_EH_S6B-EH_1x06_P2.50mm_Horizontal +Connector_JST:JST_EH_S7B-EH_1x07_P2.50mm_Horizontal +Connector_JST:JST_EH_S8B-EH_1x08_P2.50mm_Horizontal +Connector_JST:JST_EH_S9B-EH_1x09_P2.50mm_Horizontal +Connector_JST:JST_GH_BM02B-GHS-TBT_1x02-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM03B-GHS-TBT_1x03-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM04B-GHS-TBT_1x04-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM05B-GHS-TBT_1x05-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM06B-GHS-TBT_1x06-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM07B-GHS-TBT_1x07-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM08B-GHS-TBT_1x08-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM09B-GHS-TBT_1x09-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM10B-GHS-TBT_1x10-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM11B-GHS-TBT_1x11-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM12B-GHS-TBT_1x12-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM13B-GHS-TBT_1x13-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM14B-GHS-TBT_1x14-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_BM15B-GHS-TBT_1x15-1MP_P1.25mm_Vertical +Connector_JST:JST_GH_SM02B-GHS-TB_1x02-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM03B-GHS-TB_1x03-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM04B-GHS-TB_1x04-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM05B-GHS-TB_1x05-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM06B-GHS-TB_1x06-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM07B-GHS-TB_1x07-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM08B-GHS-TB_1x08-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM09B-GHS-TB_1x09-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM10B-GHS-TB_1x10-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM11B-GHS-TB_1x11-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM12B-GHS-TB_1x12-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM13B-GHS-TB_1x13-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM14B-GHS-TB_1x14-1MP_P1.25mm_Horizontal +Connector_JST:JST_GH_SM15B-GHS-TB_1x15-1MP_P1.25mm_Horizontal +Connector_JST:JST_J2100_B06B-J21DK-GGXR_2x03_P2.50x4.00mm_Vertical +Connector_JST:JST_J2100_B08B-J21DK-GGXR_2x04_P2.50x4.00mm_Vertical +Connector_JST:JST_J2100_B10B-J21DK-GGXR_2x05_P2.50x4.00mm_Vertical +Connector_JST:JST_J2100_B12B-J21DK-GGXR_2x06_P2.50x4.00mm_Vertical +Connector_JST:JST_J2100_B16B-J21DK-GGXR_2x08_P2.50x4.00mm_Vertical +Connector_JST:JST_J2100_B20B-J21DK-GGXR_2x10_P2.50x4.00mm_Vertical +Connector_JST:JST_J2100_S06B-J21DK-GGXR_2x03_P2.50mm_Horizontal +Connector_JST:JST_J2100_S08B-J21DK-GGXR_2x04_P2.50mm_Horizontal +Connector_JST:JST_J2100_S10B-J21DK-GGXR_2x05_P2.50mm_Horizontal +Connector_JST:JST_J2100_S12B-J21DK-GGXR_2x06_P2.50mm_Horizontal +Connector_JST:JST_J2100_S16B-J21DK-GGXR_2x08_P2.50mm_Horizontal +Connector_JST:JST_J2100_S20B-J21DK-GGXR_2x10_P2.50mm_Horizontal +Connector_JST:JST_JWPF_B02B-JWPF-SK-R_1x02_P2.00mm_Vertical +Connector_JST:JST_JWPF_B03B-JWPF-SK-R_1x03_P2.00mm_Vertical +Connector_JST:JST_JWPF_B04B-JWPF-SK-R_1x04_P2.00mm_Vertical +Connector_JST:JST_JWPF_B06B-JWPF-SK-R_2x03_P2.00mm_Vertical +Connector_JST:JST_JWPF_B08B-JWPF-SK-R_2x04_P2.00mm_Vertical +Connector_JST:JST_LEA_SM02B-LEASS-TF_1x02-1MP_P4.20mm_Horizontal +Connector_JST:JST_NV_B02P-NV_1x02_P5.00mm_Vertical +Connector_JST:JST_NV_B03P-NV_1x03_P5.00mm_Vertical +Connector_JST:JST_NV_B04P-NV_1x04_P5.00mm_Vertical +Connector_JST:JST_PHD_B10B-PHDSS_2x05_P2.00mm_Vertical +Connector_JST:JST_PHD_B12B-PHDSS_2x06_P2.00mm_Vertical +Connector_JST:JST_PHD_B14B-PHDSS_2x07_P2.00mm_Vertical +Connector_JST:JST_PHD_B16B-PHDSS_2x08_P2.00mm_Vertical +Connector_JST:JST_PHD_B18B-PHDSS_2x09_P2.00mm_Vertical +Connector_JST:JST_PHD_B20B-PHDSS_2x10_P2.00mm_Vertical +Connector_JST:JST_PHD_B22B-PHDSS_2x11_P2.00mm_Vertical +Connector_JST:JST_PHD_B24B-PHDSS_2x12_P2.00mm_Vertical +Connector_JST:JST_PHD_B26B-PHDSS_2x13_P2.00mm_Vertical +Connector_JST:JST_PHD_B28B-PHDSS_2x14_P2.00mm_Vertical +Connector_JST:JST_PHD_B30B-PHDSS_2x15_P2.00mm_Vertical +Connector_JST:JST_PHD_B32B-PHDSS_2x16_P2.00mm_Vertical +Connector_JST:JST_PHD_B34B-PHDSS_2x17_P2.00mm_Vertical +Connector_JST:JST_PHD_B8B-PHDSS_2x04_P2.00mm_Vertical +Connector_JST:JST_PHD_S10B-PHDSS_2x05_P2.00mm_Horizontal +Connector_JST:JST_PHD_S12B-PHDSS_2x06_P2.00mm_Horizontal +Connector_JST:JST_PHD_S14B-PHDSS_2x07_P2.00mm_Horizontal +Connector_JST:JST_PHD_S16B-PHDSS_2x08_P2.00mm_Horizontal +Connector_JST:JST_PHD_S18B-PHDSS_2x09_P2.00mm_Horizontal +Connector_JST:JST_PHD_S20B-PHDSS_2x10_P2.00mm_Horizontal +Connector_JST:JST_PHD_S22B-PHDSS_2x11_P2.00mm_Horizontal +Connector_JST:JST_PHD_S24B-PHDSS_2x12_P2.00mm_Horizontal +Connector_JST:JST_PHD_S26B-PHDSS_2x13_P2.00mm_Horizontal +Connector_JST:JST_PHD_S28B-PHDSS_2x14_P2.00mm_Horizontal +Connector_JST:JST_PHD_S30B-PHDSS_2x15_P2.00mm_Horizontal +Connector_JST:JST_PHD_S32B-PHDSS_2x16_P2.00mm_Horizontal +Connector_JST:JST_PHD_S34B-PHDSS_2x17_P2.00mm_Horizontal +Connector_JST:JST_PHD_S8B-PHDSS_2x04_P2.00mm_Horizontal +Connector_JST:JST_PH_B10B-PH-K_1x10_P2.00mm_Vertical +Connector_JST:JST_PH_B10B-PH-SM4-TB_1x10-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B11B-PH-K_1x11_P2.00mm_Vertical +Connector_JST:JST_PH_B11B-PH-SM4-TB_1x11-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B12B-PH-K_1x12_P2.00mm_Vertical +Connector_JST:JST_PH_B12B-PH-SM4-TB_1x12-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B13B-PH-K_1x13_P2.00mm_Vertical +Connector_JST:JST_PH_B13B-PH-SM4-TB_1x13-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B14B-PH-K_1x14_P2.00mm_Vertical +Connector_JST:JST_PH_B14B-PH-SM4-TB_1x14-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B15B-PH-K_1x15_P2.00mm_Vertical +Connector_JST:JST_PH_B15B-PH-SM4-TB_1x15-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B16B-PH-K_1x16_P2.00mm_Vertical +Connector_JST:JST_PH_B16B-PH-SM4-TB_1x16-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B2B-PH-K_1x02_P2.00mm_Vertical +Connector_JST:JST_PH_B2B-PH-SM4-TB_1x02-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B3B-PH-K_1x03_P2.00mm_Vertical +Connector_JST:JST_PH_B3B-PH-SM4-TB_1x03-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B4B-PH-K_1x04_P2.00mm_Vertical +Connector_JST:JST_PH_B4B-PH-SM4-TB_1x04-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B5B-PH-K_1x05_P2.00mm_Vertical +Connector_JST:JST_PH_B5B-PH-SM4-TB_1x05-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B6B-PH-K_1x06_P2.00mm_Vertical +Connector_JST:JST_PH_B6B-PH-SM4-TB_1x06-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B7B-PH-K_1x07_P2.00mm_Vertical +Connector_JST:JST_PH_B7B-PH-SM4-TB_1x07-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B8B-PH-K_1x08_P2.00mm_Vertical +Connector_JST:JST_PH_B8B-PH-SM4-TB_1x08-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_B9B-PH-K_1x09_P2.00mm_Vertical +Connector_JST:JST_PH_B9B-PH-SM4-TB_1x09-1MP_P2.00mm_Vertical +Connector_JST:JST_PH_S10B-PH-K_1x10_P2.00mm_Horizontal +Connector_JST:JST_PH_S10B-PH-SM4-TB_1x10-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S11B-PH-K_1x11_P2.00mm_Horizontal +Connector_JST:JST_PH_S11B-PH-SM4-TB_1x11-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S12B-PH-K_1x12_P2.00mm_Horizontal +Connector_JST:JST_PH_S12B-PH-SM4-TB_1x12-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S13B-PH-K_1x13_P2.00mm_Horizontal +Connector_JST:JST_PH_S13B-PH-SM4-TB_1x13-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S14B-PH-K_1x14_P2.00mm_Horizontal +Connector_JST:JST_PH_S14B-PH-SM4-TB_1x14-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S15B-PH-K_1x15_P2.00mm_Horizontal +Connector_JST:JST_PH_S15B-PH-SM4-TB_1x15-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S16B-PH-K_1x16_P2.00mm_Horizontal +Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal +Connector_JST:JST_PH_S2B-PH-SM4-TB_1x02-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S3B-PH-K_1x03_P2.00mm_Horizontal +Connector_JST:JST_PH_S3B-PH-SM4-TB_1x03-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S4B-PH-K_1x04_P2.00mm_Horizontal +Connector_JST:JST_PH_S4B-PH-SM4-TB_1x04-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S5B-PH-K_1x05_P2.00mm_Horizontal +Connector_JST:JST_PH_S5B-PH-SM4-TB_1x05-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S6B-PH-K_1x06_P2.00mm_Horizontal +Connector_JST:JST_PH_S6B-PH-SM4-TB_1x06-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S7B-PH-K_1x07_P2.00mm_Horizontal +Connector_JST:JST_PH_S7B-PH-SM4-TB_1x07-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S8B-PH-K_1x08_P2.00mm_Horizontal +Connector_JST:JST_PH_S8B-PH-SM4-TB_1x08-1MP_P2.00mm_Horizontal +Connector_JST:JST_PH_S9B-PH-K_1x09_P2.00mm_Horizontal +Connector_JST:JST_PH_S9B-PH-SM4-TB_1x09-1MP_P2.00mm_Horizontal +Connector_JST:JST_PUD_B08B-PUDSS_2x04_P2.00mm_Vertical +Connector_JST:JST_PUD_B10B-PUDSS_2x05_P2.00mm_Vertical +Connector_JST:JST_PUD_B12B-PUDSS_2x06_P2.00mm_Vertical +Connector_JST:JST_PUD_B14B-PUDSS_2x07_P2.00mm_Vertical +Connector_JST:JST_PUD_B16B-PUDSS_2x08_P2.00mm_Vertical +Connector_JST:JST_PUD_B18B-PUDSS_2x09_P2.00mm_Vertical +Connector_JST:JST_PUD_B20B-PUDSS_2x10_P2.00mm_Vertical +Connector_JST:JST_PUD_B22B-PUDSS_2x11_P2.00mm_Vertical +Connector_JST:JST_PUD_B24B-PUDSS_2x12_P2.00mm_Vertical +Connector_JST:JST_PUD_B26B-PUDSS_2x13_P2.00mm_Vertical +Connector_JST:JST_PUD_B28B-PUDSS_2x14_P2.00mm_Vertical +Connector_JST:JST_PUD_B30B-PUDSS_2x15_P2.00mm_Vertical +Connector_JST:JST_PUD_B32B-PUDSS_2x16_P2.00mm_Vertical +Connector_JST:JST_PUD_B34B-PUDSS_2x17_P2.00mm_Vertical +Connector_JST:JST_PUD_B36B-PUDSS_2x18_P2.00mm_Vertical +Connector_JST:JST_PUD_B38B-PUDSS_2x19_P2.00mm_Vertical +Connector_JST:JST_PUD_B40B-PUDSS_2x20_P2.00mm_Vertical +Connector_JST:JST_PUD_S08B-PUDSS-1_2x04_P2.00mm_Horizontal +Connector_JST:JST_PUD_S10B-PUDSS-1_2x05_P2.00mm_Horizontal +Connector_JST:JST_PUD_S12B-PUDSS-1_2x06_P2.00mm_Horizontal +Connector_JST:JST_PUD_S14B-PUDSS-1_2x07_P2.00mm_Horizontal +Connector_JST:JST_PUD_S16B-PUDSS-1_2x08_P2.00mm_Horizontal +Connector_JST:JST_PUD_S18B-PUDSS-1_2x09_P2.00mm_Horizontal +Connector_JST:JST_PUD_S20B-PUDSS-1_2x10_P2.00mm_Horizontal +Connector_JST:JST_PUD_S22B-PUDSS-1_2x11_P2.00mm_Horizontal +Connector_JST:JST_PUD_S24B-PUDSS-1_2x12_P2.00mm_Horizontal +Connector_JST:JST_PUD_S26B-PUDSS-1_2x13_P2.00mm_Horizontal +Connector_JST:JST_PUD_S28B-PUDSS-1_2x14_P2.00mm_Horizontal +Connector_JST:JST_PUD_S30B-PUDSS-1_2x15_P2.00mm_Horizontal +Connector_JST:JST_PUD_S32B-PUDSS-1_2x16_P2.00mm_Horizontal +Connector_JST:JST_PUD_S34B-PUDSS-1_2x17_P2.00mm_Horizontal +Connector_JST:JST_PUD_S36B-PUDSS-1_2x18_P2.00mm_Horizontal +Connector_JST:JST_PUD_S38B-PUDSS-1_2x19_P2.00mm_Horizontal +Connector_JST:JST_PUD_S40B-PUDSS-1_2x20_P2.00mm_Horizontal +Connector_JST:JST_SFH_SM02B-SFHRS-TF_1x02-1MP_P4.20mm_Horizontal +Connector_JST:JST_SHL_SM02B-SHLS-TF_1x02-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM05B-SHLS-TF_1x05-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM06B-SHLS-TF_1x06-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM07B-SHLS-TF_1x07-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM08B-SHLS-TF_1x08-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM10B-SHLS-TF_1x10-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM11B-SHLS-TF_1x11-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM12B-SHLS-TF_1x12-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM14B-SHLS-TF_1x14-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM16B-SHLS-TF_1x16-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM20B-SHLS-TF_1x20-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM22B-SHLS-TF_1x22-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM26B-SHLS-TF_1x26-1MP_P1.00mm_Horizontal +Connector_JST:JST_SHL_SM30B-SHLS-TF_1x30-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_BM02B-SRSS-TB_1x02-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM03B-SRSS-TB_1x03-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM04B-SRSS-TB_1x04-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM05B-SRSS-TB_1x05-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM06B-SRSS-TB_1x06-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM07B-SRSS-TB_1x07-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM08B-SRSS-TB_1x08-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM09B-SRSS-TB_1x09-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM10B-SRSS-TB_1x10-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM11B-SRSS-TB_1x11-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM12B-SRSS-TB_1x12-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM13B-SRSS-TB_1x13-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM14B-SRSS-TB_1x14-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_BM15B-SRSS-TB_1x15-1MP_P1.00mm_Vertical +Connector_JST:JST_SH_SM02B-SRSS-TB_1x02-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM03B-SRSS-TB_1x03-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM04B-SRSS-TB_1x04-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM05B-SRSS-TB_1x05-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM06B-SRSS-TB_1x06-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM07B-SRSS-TB_1x07-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM08B-SRSS-TB_1x08-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM09B-SRSS-TB_1x09-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM10B-SRSS-TB_1x10-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM11B-SRSS-TB_1x11-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM12B-SRSS-TB_1x12-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM13B-SRSS-TB_1x13-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM14B-SRSS-TB_1x14-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM15B-SRSS-TB_1x15-1MP_P1.00mm_Horizontal +Connector_JST:JST_SH_SM20B-SRSS-TB_1x20-1MP_P1.00mm_Horizontal +Connector_JST:JST_SUR_BM02B-SURS-TF_1x02-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM03B-SURS-TF_1x03-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM04B-SURS-TF_1x04-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM05B-SURS-TF_1x05-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM06B-SURS-TF_1x06-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM08B-SURS-TF_1x08-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM10B-SURS-TF_1x10-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM12B-SURS-TF_1x12-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM14B-SURS-TF_1x14-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM15B-SURS-TF_1x15-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM16B-SURS-TF_1x16-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM17B-SURS-TF_1x17-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_BM20B-SURS-TF_1x20-1MP_P0.80mm_Vertical +Connector_JST:JST_SUR_SM02B-SURS-TF_1x02-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM03B-SURS-TF_1x03-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM04B-SURS-TF_1x04-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM05B-SURS-TF_1x05-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM06B-SURS-TF_1x06-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM08B-SURS-TF_1x08-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM10B-SURS-TF_1x10-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM12B-SURS-TF_1x12-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM14B-SURS-TF_1x14-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM15B-SURS-TF_1x15-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM16B-SURS-TF_1x16-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM17B-SURS-TF_1x17-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM20B-SURS-TF_1x20-1MP_P0.80mm_Horizontal +Connector_JST:JST_SUR_SM22B-SURS-TF_1x22-1MP_P0.80mm_Horizontal +Connector_JST:JST_VH_B10P-VH-B_1x10_P3.96mm_Vertical +Connector_JST:JST_VH_B10P-VH-FB-B_1x10_P3.96mm_Vertical +Connector_JST:JST_VH_B10P-VH_1x10_P3.96mm_Vertical +Connector_JST:JST_VH_B10PS-VH_1x10_P3.96mm_Horizontal +Connector_JST:JST_VH_B11P-VH-B_1x11_P3.96mm_Vertical +Connector_JST:JST_VH_B2P-VH-B_1x02_P3.96mm_Vertical +Connector_JST:JST_VH_B2P-VH-FB-B_1x02_P3.96mm_Vertical +Connector_JST:JST_VH_B2P-VH_1x02_P3.96mm_Vertical +Connector_JST:JST_VH_B2P3-VH_1x02_P7.92mm_Vertical +Connector_JST:JST_VH_B2PS-VH_1x02_P3.96mm_Horizontal +Connector_JST:JST_VH_B3P-VH-B_1x03_P3.96mm_Vertical +Connector_JST:JST_VH_B3P-VH-FB-B_1x03_P3.96mm_Vertical +Connector_JST:JST_VH_B3P-VH_1x03_P3.96mm_Vertical +Connector_JST:JST_VH_B3PS-VH_1x03_P3.96mm_Horizontal +Connector_JST:JST_VH_B4P-VH-B_1x04_P3.96mm_Vertical +Connector_JST:JST_VH_B4P-VH-FB-B_1x04_P3.96mm_Vertical +Connector_JST:JST_VH_B4P-VH_1x04_P3.96mm_Vertical +Connector_JST:JST_VH_B4PS-VH_1x04_P3.96mm_Horizontal +Connector_JST:JST_VH_B5P-VH-B_1x05_P3.96mm_Vertical +Connector_JST:JST_VH_B5P-VH-FB-B_1x05_P3.96mm_Vertical +Connector_JST:JST_VH_B5P-VH_1x05_P3.96mm_Vertical +Connector_JST:JST_VH_B5PS-VH_1x05_P3.96mm_Horizontal +Connector_JST:JST_VH_B6P-VH-B_1x06_P3.96mm_Vertical +Connector_JST:JST_VH_B6P-VH-FB-B_1x06_P3.96mm_Vertical +Connector_JST:JST_VH_B6P-VH_1x06_P3.96mm_Vertical +Connector_JST:JST_VH_B6PS-VH_1x06_P3.96mm_Horizontal +Connector_JST:JST_VH_B7P-VH-B_1x07_P3.96mm_Vertical +Connector_JST:JST_VH_B7P-VH-FB-B_1x07_P3.96mm_Vertical +Connector_JST:JST_VH_B7P-VH_1x07_P3.96mm_Vertical +Connector_JST:JST_VH_B7PS-VH_1x07_P3.96mm_Horizontal +Connector_JST:JST_VH_B8P-VH-B_1x08_P3.96mm_Vertical +Connector_JST:JST_VH_B8P-VH-FB-B_1x08_P3.96mm_Vertical +Connector_JST:JST_VH_B8P-VH_1x08_P3.96mm_Vertical +Connector_JST:JST_VH_B8PS-VH_1x08_P3.96mm_Horizontal +Connector_JST:JST_VH_B9P-VH-B_1x09_P3.96mm_Vertical +Connector_JST:JST_VH_B9P-VH-FB-B_1x09_P3.96mm_Vertical +Connector_JST:JST_VH_B9P-VH_1x09_P3.96mm_Vertical +Connector_JST:JST_VH_B9PS-VH_1x09_P3.96mm_Horizontal +Connector_JST:JST_VH_S2P-VH_1x02_P3.96mm_Horizontal +Connector_JST:JST_VH_S3P-VH_1x03_P3.96mm_Horizontal +Connector_JST:JST_VH_S4P-VH_1x04_P3.96mm_Horizontal +Connector_JST:JST_VH_S5P-VH_1x05_P3.96mm_Horizontal +Connector_JST:JST_VH_S6P-VH_1x06_P3.96mm_Horizontal +Connector_JST:JST_VH_S7P-VH_1x07_P3.96mm_Horizontal +Connector_JST:JST_XAG_SM05B-XAGKS-BN-TB_1x05-1MP_P2.50mm_Horizontal +Connector_JST:JST_XA_B02B-XASK-1-A_1x02_P2.50mm_Vertical +Connector_JST:JST_XA_B02B-XASK-1_1x02_P2.50mm_Vertical +Connector_JST:JST_XA_B03B-XASK-1-A_1x03_P2.50mm_Vertical +Connector_JST:JST_XA_B03B-XASK-1_1x03_P2.50mm_Vertical +Connector_JST:JST_XA_B04B-XASK-1-A_1x04_P2.50mm_Vertical +Connector_JST:JST_XA_B04B-XASK-1_1x04_P2.50mm_Vertical +Connector_JST:JST_XA_B05B-XASK-1-A_1x05_P2.50mm_Vertical +Connector_JST:JST_XA_B05B-XASK-1_1x05_P2.50mm_Vertical +Connector_JST:JST_XA_B06B-XASK-1-A_1x06_P2.50mm_Vertical +Connector_JST:JST_XA_B06B-XASK-1_1x06_P2.50mm_Vertical +Connector_JST:JST_XA_B07B-XASK-1-A_1x07_P2.50mm_Vertical +Connector_JST:JST_XA_B07B-XASK-1_1x07_P2.50mm_Vertical +Connector_JST:JST_XA_B08B-XASK-1-A_1x08_P2.50mm_Vertical +Connector_JST:JST_XA_B08B-XASK-1_1x08_P2.50mm_Vertical +Connector_JST:JST_XA_B09B-XASK-1-A_1x09_P2.50mm_Vertical +Connector_JST:JST_XA_B09B-XASK-1_1x09_P2.50mm_Vertical +Connector_JST:JST_XA_B10B-XASK-1-A_1x10_P2.50mm_Vertical +Connector_JST:JST_XA_B10B-XASK-1_1x10_P2.50mm_Vertical +Connector_JST:JST_XA_B11B-XASK-1-A_1x11_P2.50mm_Vertical +Connector_JST:JST_XA_B11B-XASK-1_1x11_P2.50mm_Vertical +Connector_JST:JST_XA_B12B-XASK-1-A_1x12_P2.50mm_Vertical +Connector_JST:JST_XA_B12B-XASK-1_1x12_P2.50mm_Vertical +Connector_JST:JST_XA_B13B-XASK-1-A_1x13_P2.50mm_Vertical +Connector_JST:JST_XA_B13B-XASK-1_1x13_P2.50mm_Vertical +Connector_JST:JST_XA_B14B-XASK-1-A_1x14_P2.50mm_Vertical +Connector_JST:JST_XA_B14B-XASK-1_1x14_P2.50mm_Vertical +Connector_JST:JST_XA_B15B-XASK-1-A_1x15_P2.50mm_Vertical +Connector_JST:JST_XA_B15B-XASK-1_1x15_P2.50mm_Vertical +Connector_JST:JST_XA_B18B-XASK-1_1x18_P2.50mm_Vertical +Connector_JST:JST_XA_B20B-XASK-1-A_1x20_P2.50mm_Vertical +Connector_JST:JST_XA_B20B-XASK-1_1x20_P2.50mm_Vertical +Connector_JST:JST_XA_S02B-XASK-1N-BN_1x02_P2.50mm_Horizontal +Connector_JST:JST_XA_S02B-XASK-1_1x02_P2.50mm_Horizontal +Connector_JST:JST_XA_S03B-XASK-1N-BN_1x03_P2.50mm_Horizontal +Connector_JST:JST_XA_S03B-XASK-1_1x03_P2.50mm_Horizontal +Connector_JST:JST_XA_S04B-XASK-1N-BN_1x04_P2.50mm_Horizontal +Connector_JST:JST_XA_S04B-XASK-1_1x04_P2.50mm_Horizontal +Connector_JST:JST_XA_S05B-XASK-1N-BN_1x05_P2.50mm_Horizontal +Connector_JST:JST_XA_S05B-XASK-1_1x05_P2.50mm_Horizontal +Connector_JST:JST_XA_S06B-XASK-1N-BN_1x06_P2.50mm_Horizontal +Connector_JST:JST_XA_S06B-XASK-1_1x06_P2.50mm_Horizontal +Connector_JST:JST_XA_S07B-XASK-1N-BN_1x07_P2.50mm_Horizontal +Connector_JST:JST_XA_S07B-XASK-1_1x07_P2.50mm_Horizontal +Connector_JST:JST_XA_S08B-XASK-1N-BN_1x08_P2.50mm_Horizontal +Connector_JST:JST_XA_S08B-XASK-1_1x08_P2.50mm_Horizontal +Connector_JST:JST_XA_S09B-XASK-1N-BN_1x09_P2.50mm_Horizontal +Connector_JST:JST_XA_S09B-XASK-1_1x09_P2.50mm_Horizontal +Connector_JST:JST_XA_S10B-XASK-1N-BN_1x10_P2.50mm_Horizontal +Connector_JST:JST_XA_S10B-XASK-1_1x10_P2.50mm_Horizontal +Connector_JST:JST_XA_S11B-XASK-1N-BN_1x11_P2.50mm_Horizontal +Connector_JST:JST_XA_S11B-XASK-1_1x11_P2.50mm_Horizontal +Connector_JST:JST_XA_S12B-XASK-1N-BN_1x12_P2.50mm_Horizontal +Connector_JST:JST_XA_S12B-XASK-1_1x12_P2.50mm_Horizontal +Connector_JST:JST_XA_S13B-XASK-1N-BN_1x13_P2.50mm_Horizontal +Connector_JST:JST_XA_S13B-XASK-1_1x13_P2.50mm_Horizontal +Connector_JST:JST_XA_S14B-XASK-1N-BN_1x14_P2.50mm_Horizontal +Connector_JST:JST_XA_S14B-XASK-1_1x14_P2.50mm_Horizontal +Connector_JST:JST_XH_B10B-XH-AM_1x10_P2.50mm_Vertical +Connector_JST:JST_XH_B10B-XH-A_1x10_P2.50mm_Vertical +Connector_JST:JST_XH_B11B-XH-A_1x11_P2.50mm_Vertical +Connector_JST:JST_XH_B12B-XH-AM_1x12_P2.50mm_Vertical +Connector_JST:JST_XH_B12B-XH-A_1x12_P2.50mm_Vertical +Connector_JST:JST_XH_B13B-XH-A_1x13_P2.50mm_Vertical +Connector_JST:JST_XH_B14B-XH-A_1x14_P2.50mm_Vertical +Connector_JST:JST_XH_B15B-XH-A_1x15_P2.50mm_Vertical +Connector_JST:JST_XH_B16B-XH-A_1x16_P2.50mm_Vertical +Connector_JST:JST_XH_B1B-XH-AM_1x01_P2.50mm_Vertical +Connector_JST:JST_XH_B20B-XH-A_1x20_P2.50mm_Vertical +Connector_JST:JST_XH_B2B-XH-AM_1x02_P2.50mm_Vertical +Connector_JST:JST_XH_B2B-XH-A_1x02_P2.50mm_Vertical +Connector_JST:JST_XH_B3B-XH-AM_1x03_P2.50mm_Vertical +Connector_JST:JST_XH_B3B-XH-A_1x03_P2.50mm_Vertical +Connector_JST:JST_XH_B4B-XH-AM_1x04_P2.50mm_Vertical +Connector_JST:JST_XH_B4B-XH-A_1x04_P2.50mm_Vertical +Connector_JST:JST_XH_B5B-XH-AM_1x05_P2.50mm_Vertical +Connector_JST:JST_XH_B5B-XH-A_1x05_P2.50mm_Vertical +Connector_JST:JST_XH_B6B-XH-AM_1x06_P2.50mm_Vertical +Connector_JST:JST_XH_B6B-XH-A_1x06_P2.50mm_Vertical +Connector_JST:JST_XH_B7B-XH-AM_1x07_P2.50mm_Vertical +Connector_JST:JST_XH_B7B-XH-A_1x07_P2.50mm_Vertical +Connector_JST:JST_XH_B8B-XH-AM_1x08_P2.50mm_Vertical +Connector_JST:JST_XH_B8B-XH-A_1x08_P2.50mm_Vertical +Connector_JST:JST_XH_B9B-XH-AM_1x09_P2.50mm_Vertical +Connector_JST:JST_XH_B9B-XH-A_1x09_P2.50mm_Vertical +Connector_JST:JST_XH_S10B-XH-A-1_1x10_P2.50mm_Horizontal +Connector_JST:JST_XH_S10B-XH-A_1x10_P2.50mm_Horizontal +Connector_JST:JST_XH_S11B-XH-A-1_1x11_P2.50mm_Horizontal +Connector_JST:JST_XH_S11B-XH-A_1x11_P2.50mm_Horizontal +Connector_JST:JST_XH_S12B-XH-A-1_1x12_P2.50mm_Horizontal +Connector_JST:JST_XH_S12B-XH-A_1x12_P2.50mm_Horizontal +Connector_JST:JST_XH_S13B-XH-A-1_1x13_P2.50mm_Horizontal +Connector_JST:JST_XH_S13B-XH-A_1x13_P2.50mm_Horizontal +Connector_JST:JST_XH_S14B-XH-A-1_1x14_P2.50mm_Horizontal +Connector_JST:JST_XH_S14B-XH-A_1x14_P2.50mm_Horizontal +Connector_JST:JST_XH_S15B-XH-A-1_1x15_P2.50mm_Horizontal +Connector_JST:JST_XH_S15B-XH-A_1x15_P2.50mm_Horizontal +Connector_JST:JST_XH_S16B-XH-A_1x16_P2.50mm_Horizontal +Connector_JST:JST_XH_S2B-XH-A-1_1x02_P2.50mm_Horizontal +Connector_JST:JST_XH_S2B-XH-A_1x02_P2.50mm_Horizontal +Connector_JST:JST_XH_S3B-XH-A-1_1x03_P2.50mm_Horizontal +Connector_JST:JST_XH_S3B-XH-A_1x03_P2.50mm_Horizontal +Connector_JST:JST_XH_S3B-XH-SM4-TB_1x03-1MP_P2.50mm_Horizontal +Connector_JST:JST_XH_S4B-XH-A-1_1x04_P2.50mm_Horizontal +Connector_JST:JST_XH_S4B-XH-A_1x04_P2.50mm_Horizontal +Connector_JST:JST_XH_S4B-XH-SM4-TB_1x04-1MP_P2.50mm_Horizontal +Connector_JST:JST_XH_S5B-XH-A-1_1x05_P2.50mm_Horizontal +Connector_JST:JST_XH_S5B-XH-A_1x05_P2.50mm_Horizontal +Connector_JST:JST_XH_S6B-XH-A-1_1x06_P2.50mm_Horizontal +Connector_JST:JST_XH_S6B-XH-A_1x06_P2.50mm_Horizontal +Connector_JST:JST_XH_S6B-XH-SM4-TB_1x06-1MP_P2.50mm_Horizontal +Connector_JST:JST_XH_S7B-XH-A-1_1x07_P2.50mm_Horizontal +Connector_JST:JST_XH_S7B-XH-A_1x07_P2.50mm_Horizontal +Connector_JST:JST_XH_S8B-XH-A-1_1x08_P2.50mm_Horizontal +Connector_JST:JST_XH_S8B-XH-A_1x08_P2.50mm_Horizontal +Connector_JST:JST_XH_S9B-XH-A-1_1x09_P2.50mm_Horizontal +Connector_JST:JST_XH_S9B-XH-A_1x09_P2.50mm_Horizontal +Connector_JST:JST_ZE_B02B-ZESK-1D_1x02_P1.50mm_Vertical +Connector_JST:JST_ZE_B03B-ZESK-1D_1x03_P1.50mm_Vertical +Connector_JST:JST_ZE_B03B-ZESK-D_1x03_P1.50mm_Vertical +Connector_JST:JST_ZE_B04B-ZESK-1D_1x04_P1.50mm_Vertical +Connector_JST:JST_ZE_B04B-ZESK-D_1x04_P1.50mm_Vertical +Connector_JST:JST_ZE_B05B-ZESK-1D_1x05_P1.50mm_Vertical +Connector_JST:JST_ZE_B05B-ZESK-D_1x05_P1.50mm_Vertical +Connector_JST:JST_ZE_B06B-ZESK-1D_1x06_P1.50mm_Vertical +Connector_JST:JST_ZE_B06B-ZESK-D_1x06_P1.50mm_Vertical +Connector_JST:JST_ZE_B07B-ZESK-1D_1x07_P1.50mm_Vertical +Connector_JST:JST_ZE_B07B-ZESK-D_1x07_P1.50mm_Vertical +Connector_JST:JST_ZE_B08B-ZESK-1D_1x08_P1.50mm_Vertical +Connector_JST:JST_ZE_B08B-ZESK-D_1x08_P1.50mm_Vertical +Connector_JST:JST_ZE_B09B-ZESK-1D_1x09_P1.50mm_Vertical +Connector_JST:JST_ZE_B09B-ZESK-D_1x09_P1.50mm_Vertical +Connector_JST:JST_ZE_B10B-ZESK-1D_1x10_P1.50mm_Vertical +Connector_JST:JST_ZE_B10B-ZESK-D_1x10_P1.50mm_Vertical +Connector_JST:JST_ZE_B11B-ZESK-1D_1x11_P1.50mm_Vertical +Connector_JST:JST_ZE_B11B-ZESK-D_1x11_P1.50mm_Vertical +Connector_JST:JST_ZE_B12B-ZESK-1D_1x12_P1.50mm_Vertical +Connector_JST:JST_ZE_B12B-ZESK-D_1x12_P1.50mm_Vertical +Connector_JST:JST_ZE_B13B-ZESK-1D_1x13_P1.50mm_Vertical +Connector_JST:JST_ZE_B13B-ZESK-D_1x13_P1.50mm_Vertical +Connector_JST:JST_ZE_B14B-ZESK-1D_1x14_P1.50mm_Vertical +Connector_JST:JST_ZE_B14B-ZESK-D_1x14_P1.50mm_Vertical +Connector_JST:JST_ZE_B15B-ZESK-1D_1x15_P1.50mm_Vertical +Connector_JST:JST_ZE_B15B-ZESK-D_1x15_P1.50mm_Vertical +Connector_JST:JST_ZE_B16B-ZESK-1D_1x16_P1.50mm_Vertical +Connector_JST:JST_ZE_B16B-ZESK-D_1x16_P1.50mm_Vertical +Connector_JST:JST_ZE_BM02B-ZESS-TBT_1x02-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM03B-ZESS-TBT_1x03-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM04B-ZESS-TBT_1x04-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM05B-ZESS-TBT_1x05-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM06B-ZESS-TBT_1x06-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM07B-ZESS-TBT_1x07-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM08B-ZESS-TBT_1x08-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM09B-ZESS-TBT_1x09-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM10B-ZESS-TBT_1x10-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM11B-ZESS-TBT_1x11-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM12B-ZESS-TBT_1x12-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM13B-ZESS-TBT_1x13-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM14B-ZESS-TBT_1x14-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM15B-ZESS-TBT_1x15-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_BM16B-ZESS-TBT_1x16-1MP_P1.50mm_Vertical +Connector_JST:JST_ZE_S02B-ZESK-2D_1x02_P1.50mm_Horizontal +Connector_JST:JST_ZE_S03B-ZESK-2D_1x03_P1.50mm_Horizontal +Connector_JST:JST_ZE_S04B-ZESK-2D_1x04_P1.50mm_Horizontal +Connector_JST:JST_ZE_S05B-ZESK-2D_1x05_P1.50mm_Horizontal +Connector_JST:JST_ZE_S06B-ZESK-2D_1x06_P1.50mm_Horizontal +Connector_JST:JST_ZE_S07B-ZESK-2D_1x07_P1.50mm_Horizontal +Connector_JST:JST_ZE_S08B-ZESK-2D_1x08_P1.50mm_Horizontal +Connector_JST:JST_ZE_S09B-ZESK-2D_1x09_P1.50mm_Horizontal +Connector_JST:JST_ZE_S10B-ZESK-2D_1x10_P1.50mm_Horizontal +Connector_JST:JST_ZE_S11B-ZESK-2D_1x11_P1.50mm_Horizontal +Connector_JST:JST_ZE_S12B-ZESK-2D_1x12_P1.50mm_Horizontal +Connector_JST:JST_ZE_S13B-ZESK-2D_1x13_P1.50mm_Horizontal +Connector_JST:JST_ZE_S14B-ZESK-2D_1x14_P1.50mm_Horizontal +Connector_JST:JST_ZE_S15B-ZESK-2D_1x15_P1.50mm_Horizontal +Connector_JST:JST_ZE_S16B-ZESK-2D_1x16_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM02B-ZESS-TB_1x02-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM03B-ZESS-TB_1x03-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM04B-ZESS-TB_1x04-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM05B-ZESS-TB_1x05-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM06B-ZESS-TB_1x06-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM07B-ZESS-TB_1x07-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM08B-ZESS-TB_1x08-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM09B-ZESS-TB_1x09-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM10B-ZESS-TB_1x10-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM11B-ZESS-TB_1x11-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM12B-ZESS-TB_1x12-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM13B-ZESS-TB_1x13-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM14B-ZESS-TB_1x14-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM15B-ZESS-TB_1x15-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZE_SM16B-ZESS-TB_1x16-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_B10B-ZR-SM4-TF_1x10-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B10B-ZR_1x10_P1.50mm_Vertical +Connector_JST:JST_ZH_B11B-ZR-SM4-TF_1x11-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B11B-ZR_1x11_P1.50mm_Vertical +Connector_JST:JST_ZH_B12B-ZR-SM4-TF_1x12-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B12B-ZR_1x12_P1.50mm_Vertical +Connector_JST:JST_ZH_B13B-ZR-SM4-TF_1x13-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B2B-ZR-SM4-TF_1x02-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B2B-ZR_1x02_P1.50mm_Vertical +Connector_JST:JST_ZH_B3B-ZR-SM4-TF_1x03-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B3B-ZR_1x03_P1.50mm_Vertical +Connector_JST:JST_ZH_B4B-ZR-SM4-TF_1x04-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B4B-ZR_1x04_P1.50mm_Vertical +Connector_JST:JST_ZH_B5B-ZR-SM4-TF_1x05-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B5B-ZR_1x05_P1.50mm_Vertical +Connector_JST:JST_ZH_B6B-ZR-SM4-TF_1x06-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B6B-ZR_1x06_P1.50mm_Vertical +Connector_JST:JST_ZH_B7B-ZR-SM4-TF_1x07-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B7B-ZR_1x07_P1.50mm_Vertical +Connector_JST:JST_ZH_B8B-ZR-SM4-TF_1x08-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B8B-ZR_1x08_P1.50mm_Vertical +Connector_JST:JST_ZH_B9B-ZR-SM4-TF_1x09-1MP_P1.50mm_Vertical +Connector_JST:JST_ZH_B9B-ZR_1x09_P1.50mm_Vertical +Connector_JST:JST_ZH_S10B-ZR-SM4A-TF_1x10-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S11B-ZR-SM4A-TF_1x11-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S12B-ZR-SM4A-TF_1x12-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S13B-ZR-SM4A-TF_1x13-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S2B-ZR-SM4A-TF_1x02-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S3B-ZR-SM4A-TF_1x03-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S4B-ZR-SM4A-TF_1x04-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S5B-ZR-SM4A-TF_1x05-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S6B-ZR-SM4A-TF_1x06-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S7B-ZR-SM4A-TF_1x07-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S8B-ZR-SM4A-TF_1x08-1MP_P1.50mm_Horizontal +Connector_JST:JST_ZH_S9B-ZR-SM4A-TF_1x09-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502382-0270_1x02-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-0370_1x03-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-0470_1x04-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-0570_1x05-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-0670_1x06-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-0770_1x07-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-0870_1x08-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-0970_1x09-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-1070_1x10-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-1170_1x11-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-1270_1x12-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-1370_1x13-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-1470_1x14-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502382-1570_1x15-1MP_P1.25mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502386-0270_1x02-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-0370_1x03-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-0470_1x04-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-0570_1x05-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-0670_1x06-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-0770_1x07-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-0870_1x08-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-0970_1x09-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-1070_1x10-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-1170_1x11-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-1270_1x12-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-1370_1x13-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-1470_1x14-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502386-1570_1x15-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502443-0270_1x02-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-0370_1x03-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-0470_1x04-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-0570_1x05-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-0670_1x06-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-0770_1x07-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-0870_1x08-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-0970_1x09-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-1270_1x12-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-1370_1x13-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-1470_1x14-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502443-1570_1x15-1MP_P2.00mm_Vertical +Connector_Molex:Molex_CLIK-Mate_502494-0270_1x02-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502494-0370_1x03-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502494-0470_1x04-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502494-0670_1x06-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502494-0870_1x08-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502494-1070_1x10-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502494-1270_1x12-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502494-1370_1x13-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502494-1470_1x14-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502494-1570_1x15-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-0270_1x02-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-0370_1x03-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-0470_1x04-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-0570_1x05-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-0670_1x06-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-0770_1x07-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-0870_1x08-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-0970_1x09-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-1070_1x10-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-1170_1x11-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-1270_1x12-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-1370_1x13-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-1470_1x14-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_502585-1570_1x15-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_CLIK-Mate_505405-0270_1x02-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-0370_1x03-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-0470_1x04-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-0570_1x05-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-0670_1x06-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-0770_1x07-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-0870_1x08-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-0970_1x09-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-1070_1x10-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-1170_1x11-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-1270_1x12-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-1370_1x13-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-1470_1x14-1MP_P1.50mm_Vertical +Connector_Molex:Molex_CLIK-Mate_505405-1570_1x15-1MP_P1.50mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-02A_1x02_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-03A_1x03_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-04A_1x04_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-05A_1x05_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-06A_1x06_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-07A_1x07_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-08A_1x08_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-09A_1x09_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-10A_1x10_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-11A_1x11_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-12A_1x12_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-13A_1x13_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-14A_1x14_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-15A_1x15_P2.54mm_Vertical +Connector_Molex:Molex_KK-254_AE-6410-16A_1x16_P2.54mm_Vertical +Connector_Molex:Molex_KK-396_5273-02A_1x02_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-03A_1x03_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-04A_1x04_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-05A_1x05_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-06A_1x06_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-07A_1x07_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-08A_1x08_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-09A_1x09_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-10A_1x10_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-11A_1x11_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_5273-12A_1x12_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0002_1x02_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0003_1x03_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0004_1x04_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0005_1x05_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0006_1x06_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0007_1x07_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0008_1x08_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0009_1x09_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0010_1x10_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0011_1x11_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0012_1x12_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0013_1x13_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0014_1x14_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0015_1x15_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0016_1x16_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0017_1x17_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41791-0018_1x18_P3.96mm_Vertical +Connector_Molex:Molex_KK-396_A-41792-0002_1x02_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0003_1x03_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0004_1x04_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0005_1x05_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0006_1x06_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0007_1x07_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0008_1x08_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0009_1x09_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0010_1x10_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0011_1x11_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0012_1x12_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0013_1x13_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0014_1x14_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0015_1x15_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0016_1x16_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0017_1x17_P3.96mm_Horizontal +Connector_Molex:Molex_KK-396_A-41792-0018_1x18_P3.96mm_Horizontal +Connector_Molex:Molex_Mega-Fit_76825-0002_2x01_P5.70mm_Horizontal +Connector_Molex:Molex_Mega-Fit_76825-0004_2x02_P5.70mm_Horizontal +Connector_Molex:Molex_Mega-Fit_76825-0006_2x03_P5.70mm_Horizontal +Connector_Molex:Molex_Mega-Fit_76825-0008_2x04_P5.70mm_Horizontal +Connector_Molex:Molex_Mega-Fit_76825-0010_2x05_P5.70mm_Horizontal +Connector_Molex:Molex_Mega-Fit_76825-0012_2x06_P5.70mm_Horizontal +Connector_Molex:Molex_Mega-Fit_76829-0002_2x01_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0004_2x02_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0006_2x03_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0008_2x04_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0010_2x05_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0012_2x06_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0102_2x01_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0104_2x02_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0106_2x03_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0108_2x04_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0110_2x05_P5.70mm_Vertical +Connector_Molex:Molex_Mega-Fit_76829-0112_2x06_P5.70mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0200_2x01_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0210_2x01-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0212_2x01_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0215_2x01_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0218_2x01-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0221_2x01-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0400_2x02_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0410_2x02-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0412_2x02_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0415_2x02_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0418_2x02-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0421_2x02-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0600_2x03_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0610_2x03-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0612_2x03_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0615_2x03_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0618_2x03-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0621_2x03-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0800_2x04_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0810_2x04-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-0812_2x04_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0815_2x04_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0818_2x04-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-0821_2x04-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1000_2x05_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1010_2x05-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1012_2x05_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1015_2x05_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1018_2x05-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1021_2x05-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1200_2x06_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1210_2x06-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1212_2x06_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1215_2x06_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1218_2x06-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1221_2x06-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1400_2x07_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1410_2x07-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1412_2x07_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1415_2x07_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1418_2x07-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1421_2x07-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1600_2x08_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1610_2x08-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1612_2x08_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1615_2x08_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1618_2x08-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1621_2x08-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1800_2x09_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1810_2x09-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-1812_2x09_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1815_2x09_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1818_2x09-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-1821_2x09-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-2000_2x10_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-2010_2x10-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-2012_2x10_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-2015_2x10_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-2018_2x10-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-2021_2x10-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-2200_2x11_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-2210_2x11-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-2212_2x11_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-2215_2x11_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-2218_2x11-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-2221_2x11-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-2400_2x12_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-2410_2x12-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43045-2412_2x12_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-2415_2x12_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-2418_2x12-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43045-2421_2x12-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0200_1x02_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0210_1x02-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0210_1x02-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-0215_1x02_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0221_1x02_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0224_1x02-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0300_1x03_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0310_1x03-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0310_1x03-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-0315_1x03_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0321_1x03_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0324_1x03-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0400_1x04_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0410_1x04-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0410_1x04-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-0415_1x04_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0421_1x04_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0424_1x04-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0500_1x05_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0510_1x05-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0510_1x05-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-0515_1x05_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0521_1x05_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0524_1x05-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0600_1x06_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0610_1x06-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0610_1x06-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-0615_1x06_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0621_1x06_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0624_1x06-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0700_1x07_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0710_1x07-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0710_1x07-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-0715_1x07_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0721_1x07_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0724_1x07-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0800_1x08_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0810_1x08-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0810_1x08-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-0815_1x08_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0821_1x08_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0824_1x08-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0900_1x09_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0910_1x09-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-0910_1x09-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-0915_1x09_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0921_1x09_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-0924_1x09-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-1000_1x10_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-1010_1x10-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-1010_1x10-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-1015_1x10_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-1021_1x10_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-1024_1x10-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-1100_1x11_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-1110_1x11-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-1110_1x11-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-1115_1x11_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-1121_1x11_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-1124_1x11-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-1200_1x12_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-1210_1x12-1MP_P3.00mm_Horizontal +Connector_Molex:Molex_Micro-Fit_3.0_43650-1210_1x12-1MP_P3.00mm_Horizontal_PnP +Connector_Molex:Molex_Micro-Fit_3.0_43650-1215_1x12_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-1221_1x12_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Fit_3.0_43650-1224_1x12-1MP_P3.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-0270_1x02_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-0370_1x03_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-0470_1x04_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-0570_1x05_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-0670_1x06_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-0770_1x07_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-0870_1x08_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-0970_1x09_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-1070_1x10_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-1170_1x11_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-1270_1x12_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-1370_1x13_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-1470_1x14_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53253-1570_1x15_P2.00mm_Vertical +Connector_Molex:Molex_Micro-Latch_53254-0270_1x02_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-0370_1x03_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-0470_1x04_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-0570_1x05_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-0670_1x06_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-0770_1x07_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-0870_1x08_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-0970_1x09_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-1070_1x10_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-1170_1x11_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-1270_1x12_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-1370_1x13_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-1470_1x14_P2.00mm_Horizontal +Connector_Molex:Molex_Micro-Latch_53254-1570_1x15_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55932-0210_1x02_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0230_1x02_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0310_1x03_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0330_1x03_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0410_1x04_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0430_1x04_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0510_1x05_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0530_1x05_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0610_1x06_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0630_1x06_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0710_1x07_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0730_1x07_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0810_1x08_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0830_1x08_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0910_1x09_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-0930_1x09_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1010_1x10_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1030_1x10_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1110_1x11_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1130_1x11_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1210_1x12_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1230_1x12_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1310_1x13_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1330_1x13_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1410_1x14_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1430_1x14_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1510_1x15_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55932-1530_1x15_P2.00mm_Vertical +Connector_Molex:Molex_MicroClasp_55935-0210_1x02_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0230_1x02_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0310_1x03_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0330_1x03_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0410_1x04_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0430_1x04_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0510_1x05_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0530_1x05_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0610_1x06_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0630_1x06_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0710_1x07_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0730_1x07_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0810_1x08_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0830_1x08_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0910_1x09_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-0930_1x09_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1010_1x10_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1030_1x10_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1110_1x11_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1130_1x11_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1210_1x12_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1230_1x12_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1310_1x13_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1330_1x13_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1410_1x14_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1430_1x14_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1510_1x15_P2.00mm_Horizontal +Connector_Molex:Molex_MicroClasp_55935-1530_1x15_P2.00mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5566-02A2_2x01_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-02A_2x01_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-04A2_2x02_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-04A_2x02_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-06A2_2x03_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-06A_2x03_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-08A2_2x04_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-08A_2x04_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-10A2_2x05_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-10A_2x05_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-12A2_2x06_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-12A_2x06_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-14A2_2x07_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-14A_2x07_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-16A2_2x08_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-16A_2x08_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-18A2_2x09_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-18A_2x09_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-20A2_2x10_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-20A_2x10_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-22A2_2x11_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-22A_2x11_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-24A2_2x12_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5566-24A_2x12_P4.20mm_Vertical +Connector_Molex:Molex_Mini-Fit_Jr_5569-02A1_2x01_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-02A2_2x01_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-04A1_2x02_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-04A2_2x02_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-06A1_2x03_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-06A2_2x03_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-08A1_2x04_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-08A2_2x04_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-10A1_2x05_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-10A2_2x05_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-12A1_2x06_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-12A2_2x06_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-14A1_2x07_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-14A2_2x07_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-16A1_2x08_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-16A2_2x08_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-18A1_2x09_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-18A2_2x09_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-20A1_2x10_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-20A2_2x10_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-22A1_2x11_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-22A2_2x11_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-24A1_2x12_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Jr_5569-24A2_2x12_P4.20mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Sr_42819-22XX_1x02_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_42819-22XX_1x02_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_42819-32XX_1x03_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_42819-32XX_1x03_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_42819-42XX_1x04_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_42819-42XX_1x04_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_42819-52XX_1x05_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_42819-52XX_1x05_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_42819-62XX_1x06_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_42819-62XX_1x06_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_42820-22XX_1x02_P10.00mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Sr_42820-22XX_1x02_P10.00mm_Horizontal_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_42820-32XX_1x03_P10.00mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Sr_42820-32XX_1x03_P10.00mm_Horizontal_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_42820-42XX_1x04_P10.00mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Sr_42820-42XX_1x04_P10.00mm_Horizontal_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_42820-52XX_1x05_P10.00mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Sr_42820-52XX_1x05_P10.00mm_Horizontal_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_42820-62XX_1x06_P10.00mm_Horizontal +Connector_Molex:Molex_Mini-Fit_Sr_42820-62XX_1x06_P10.00mm_Horizontal_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx06_2x03_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx06_2x03_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx08_2x04_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx08_2x04_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx10_2x05_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx10_2x05_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx12_2x06_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx12_2x06_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx14_2x07_P10.00mm_Vertical +Connector_Molex:Molex_Mini-Fit_Sr_43915-xx14_2x07_P10.00mm_Vertical_ThermalVias +Connector_Molex:Molex_Nano-Fit_105309-xx02_1x02_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105309-xx03_1x03_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105309-xx04_1x04_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105309-xx05_1x05_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105309-xx06_1x06_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105309-xx07_1x07_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105309-xx08_1x08_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105310-xx04_2x02_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105310-xx06_2x03_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105310-xx08_2x04_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105310-xx10_2x05_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105310-xx12_2x06_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105310-xx14_2x07_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105310-xx16_2x08_P2.50mm_Vertical +Connector_Molex:Molex_Nano-Fit_105313-xx02_1x02_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105313-xx03_1x03_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105313-xx04_1x04_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105313-xx05_1x05_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105313-xx06_1x06_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105313-xx07_1x07_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105313-xx08_1x08_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105314-xx04_2x02_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105314-xx06_2x03_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105314-xx08_2x04_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105314-xx10_2x05_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105314-xx12_2x06_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105314-xx14_2x07_P2.50mm_Horizontal +Connector_Molex:Molex_Nano-Fit_105314-xx16_2x08_P2.50mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-0270_1x02-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-0370_1x03-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-0470_1x04-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-0570_1x05-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-0670_1x06-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-0770_1x07-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-0870_1x08-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-0970_1x09-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-1070_1x10-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-1270_1x12-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-1470_1x14-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-1570_1x15-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-1870_1x18-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Panelmate_53780-3070_1x30-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-0207_1x02-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-0307_1x03-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-0407_1x04-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-0507_1x05-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-0607_1x06-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-0707_1x07-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-0807_1x08-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-0907_1x09-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-1007_1x10-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-1107_1x11-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-1207_1x12-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-1307_1x13-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-1407_1x14-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_202396-1507_1x15-1MP_P1.00mm_Horizontal +Connector_Molex:Molex_Pico-Clasp_501331-0207_1x02-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-0307_1x03-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-0407_1x04-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-0507_1x05-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-0607_1x06-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-0707_1x07-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-0807_1x08-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-0907_1x09-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-1007_1x10-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-1107_1x11-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-1207_1x12-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-1307_1x13-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-1407_1x14-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-Clasp_501331-1507_1x15-1MP_P1.00mm_Vertical +Connector_Molex:Molex_Pico-EZmate_78171-0002_1x02-1MP_P1.20mm_Vertical +Connector_Molex:Molex_Pico-EZmate_78171-0003_1x03-1MP_P1.20mm_Vertical +Connector_Molex:Molex_Pico-EZmate_78171-0004_1x04-1MP_P1.20mm_Vertical +Connector_Molex:Molex_Pico-EZmate_78171-0005_1x05-1MP_P1.20mm_Vertical +Connector_Molex:Molex_Pico-EZmate_Slim_202656-0021_1x02-1MP_P1.20mm_Vertical +Connector_Molex:Molex_Pico-Lock_205338-0002_1x02-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_Pico-Lock_205338-0004_1x04-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_Pico-Lock_205338-0006_1x06-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_Pico-Lock_205338-0008_1x08-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_Pico-Lock_205338-0010_1x10-1MP_P2.00mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-0291_1x02-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-0391_1x03-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-0491_1x04-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-0591_1x05-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-0691_1x06-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-0791_1x07-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-0891_1x08-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-0991_1x09-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-1091_1x10-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-1191_1x11-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-Lock_504050-1291_1x12-1MP_P1.50mm_Horizontal +Connector_Molex:Molex_Pico-SPOX_87437-1443_1x14-P1.5mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-0210_1x02_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-0310_1x03_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-0410_1x04_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-0510_1x05_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-0610_1x06_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-0710_1x07_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-0810_1x08_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-0910_1x09_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-1010_1x10_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-1110_1x11_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-1210_1x12_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-1310_1x13_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-1410_1x14_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53047-1510_1x15_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53048-0210_1x02_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-0310_1x03_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-0410_1x04_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-0510_1x05_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-0610_1x06_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-0710_1x07_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-0810_1x08_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-0910_1x09_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-1010_1x10_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-1110_1x11_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-1210_1x12_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-1310_1x13_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-1410_1x14_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53048-1510_1x15_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-0271_1x02-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-0371_1x03-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-0471_1x04-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-0571_1x05-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-0671_1x06-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-0771_1x07-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-0871_1x08-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-0971_1x09-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-1071_1x10-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-1171_1x11-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-1271_1x12-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-1371_1x13-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-1471_1x14-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-1571_1x15-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53261-1771_1x17-1MP_P1.25mm_Horizontal +Connector_Molex:Molex_PicoBlade_53398-0271_1x02-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-0371_1x03-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-0471_1x04-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-0571_1x05-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-0671_1x06-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-0771_1x07-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-0871_1x08-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-0971_1x09-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-1071_1x10-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-1171_1x11-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-1271_1x12-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-1371_1x13-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-1471_1x14-1MP_P1.25mm_Vertical +Connector_Molex:Molex_PicoBlade_53398-1571_1x15-1MP_P1.25mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0004_2x02_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0006_2x03_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0008_2x04_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0010_2x05_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0012_2x06_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0014_2x07_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0016_2x08_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0018_2x09_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0020_2x10_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0022_2x11_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0024_2x12_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90325-0026_2x13_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0004_2x02_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0006_2x03_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0008_2x04_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0010_2x05_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0012_2x06_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0014_2x07_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0016_2x08_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0018_2x09_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0020_2x10_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0022_2x11_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0024_2x12_P1.27mm_Vertical +Connector_Molex:Molex_Picoflex_90814-0026_2x13_P1.27mm_Vertical +Connector_Molex:Molex_Sabre_43160-0102_1x02_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-0102_1x02_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_43160-0103_1x03_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-0103_1x03_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_43160-0104_1x04_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-0104_1x04_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_43160-0105_1x05_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-0105_1x05_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_43160-0106_1x06_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-0106_1x06_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_43160-1102_1x02_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_43160-1102_1x02_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_Sabre_43160-1103_1x03_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_43160-1103_1x03_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_Sabre_43160-1104_1x04_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_43160-1104_1x04_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_Sabre_43160-1105_1x05_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_43160-1105_1x05_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_Sabre_43160-1106_1x06_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_43160-1106_1x06_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_Sabre_43160-2102_1x02_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-2102_1x02_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_43160-2103_1x03_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-2103_1x03_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_43160-2104_1x04_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-2104_1x04_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_43160-2105_1x05_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-2105_1x05_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_43160-2106_1x06_P7.49mm_Vertical +Connector_Molex:Molex_Sabre_43160-2106_1x06_P7.49mm_Vertical_ThermalVias +Connector_Molex:Molex_Sabre_46007-1102_1x02_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_46007-1102_1x02_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_Sabre_46007-1103_1x03_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_46007-1103_1x03_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_Sabre_46007-1104_1x04_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_46007-1104_1x04_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_Sabre_46007-1105_1x05_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_46007-1105_1x05_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_Sabre_46007-1106_1x06_P7.49mm_Horizontal +Connector_Molex:Molex_Sabre_46007-1106_1x06_P7.49mm_Horizontal_ThermalVias +Connector_Molex:Molex_SlimStack_501920-3001_2x15_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_501920-4001_2x20_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_501920-5001_2x25_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_502426-0810_2x04_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-1410_2x07_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-2010_2x10_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-2210_2x11_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-2410_2x12_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-2610_2x13_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-3010_2x15_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-3210_2x16_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-3410_2x17_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-4010_2x20_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-4410_2x22_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-5010_2x25_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-6010_2x30_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-6410_2x32_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502426-8010_2x40_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-0820_2x04_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-1410_2x07_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-2010_2x10_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-2210_2x11_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-2410_2x12_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-2610_2x13_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-3010_2x15_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-3210_2x16_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-3410_2x17_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-4010_2x20_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-4410_2x22_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-5010_2x25_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-6010_2x30_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-6410_2x32_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_502430-8010_2x40_P0.40mm_Vertical +Connector_Molex:Molex_SlimStack_52991-0208_2x10_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_52991-0308_2x15_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_52991-0408_2x20_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_52991-0508_2x25_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_52991-0608_2x30_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_52991-0708_2x35_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_52991-0808_2x40_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_53748-0208_2x10_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_53748-0308_2x15_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_53748-0408_2x20_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_53748-0608_2x30_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_53748-0708_2x35_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_53748-0808_2x40_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0164_2x08_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0204_2x10_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0224_2x11_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0244_2x12_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0304_2x15_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0344_2x17_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0404_2x20_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0504_2x25_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0604_2x30_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_54722-0804_2x40_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0161_2x08_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0201_2x10_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0221_2x11_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0241_2x12_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0301_2x15_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0341_2x17_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0401_2x20_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0501_2x25_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0601_2x30_P0.50mm_Vertical +Connector_Molex:Molex_SlimStack_55560-0801_2x40_P0.50mm_Vertical +Connector_Molex:Molex_SL_171971-0002_1x02_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0003_1x03_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0004_1x04_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0005_1x05_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0006_1x06_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0007_1x07_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0008_1x08_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0009_1x09_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0010_1x10_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0011_1x11_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0012_1x12_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0013_1x13_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0014_1x14_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0015_1x15_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0016_1x16_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0017_1x17_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0018_1x18_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0019_1x19_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0020_1x20_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0021_1x21_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0022_1x22_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0023_1x23_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0024_1x24_P2.54mm_Vertical +Connector_Molex:Molex_SL_171971-0025_1x25_P2.54mm_Vertical +Connector_Molex:Molex_SPOX_5267-02A_1x02_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-03A_1x03_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-04A_1x04_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-05A_1x05_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-06A_1x06_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-07A_1x07_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-08A_1x08_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-09A_1x09_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-10A_1x10_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-11A_1x11_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-12A_1x12_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-13A_1x13_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-14A_1x14_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5267-15A_1x15_P2.50mm_Vertical +Connector_Molex:Molex_SPOX_5268-02A_1x02_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-03A_1x03_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-04A_1x04_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-05A_1x05_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-06A_1x06_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-07A_1x07_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-08A_1x08_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-09A_1x09_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-10A_1x10_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-11A_1x11_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-12A_1x12_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-13A_1x13_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-14A_1x14_P2.50mm_Horizontal +Connector_Molex:Molex_SPOX_5268-15A_1x15_P2.50mm_Horizontal +Connector_PCBEdge:4UCON_10156_2x40_P1.27mm_Socket_Horizontal +Connector_PCBEdge:BUS_AT +Connector_PCBEdge:BUS_PCI +Connector_PCBEdge:BUS_PCIexpress_x1 +Connector_PCBEdge:BUS_PCIexpress_x16 +Connector_PCBEdge:BUS_PCIexpress_x4 +Connector_PCBEdge:BUS_PCIexpress_x8 +Connector_PCBEdge:BUS_PCI_Express_Mini +Connector_PCBEdge:BUS_PCI_Express_Mini_Dual +Connector_PCBEdge:BUS_PCI_Express_Mini_Full +Connector_PCBEdge:BUS_PCI_Express_Mini_Half +Connector_PCBEdge:JAE_MM60-EZH039-Bx_BUS_PCI_Express_Holder +Connector_PCBEdge:JAE_MM60-EZH059-Bx_BUS_PCI_Express_Holder +Connector_PCBEdge:molex_EDGELOCK_2-CKT +Connector_PCBEdge:molex_EDGELOCK_4-CKT +Connector_PCBEdge:molex_EDGELOCK_6-CKT +Connector_PCBEdge:molex_EDGELOCK_8-CKT +Connector_PCBEdge:Samtec_MECF-05-01-L-DV-WT_2x05_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-05-01-L-DV_2x05_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-05-01-NP-L-DV-WT_2x05_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-05-01-NP-L-DV_2x05_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-05-02-L-DV-WT_2x05_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-05-02-L-DV_2x05_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-05-02-NP-L-DV-WT_2x05_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-05-02-NP-L-DV_2x05_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-05-0_-L-DV_2x05_P1.27mm_Polarized_Edge +Connector_PCBEdge:Samtec_MECF-05-0_-NP-L-DV_2x05_P1.27mm_Edge +Connector_PCBEdge:Samtec_MECF-08-01-L-DV-WT_2x08_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-08-01-L-DV_2x08_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-08-01-NP-L-DV-WT_2x08_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-08-01-NP-L-DV_2x08_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-08-02-L-DV-WT_2x08_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-08-02-L-DV_2x08_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-08-02-NP-L-DV-WT_2x08_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-08-02-NP-L-DV_2x08_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-08-0_-L-DV_2x08_P1.27mm_Polarized_Edge +Connector_PCBEdge:Samtec_MECF-08-0_-NP-L-DV_2x08_P1.27mm_Edge +Connector_PCBEdge:Samtec_MECF-20-01-L-DV-WT_2x20_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-20-01-L-DV_2x20_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-20-01-NP-L-DV-WT_2x20_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-20-01-NP-L-DV_2x20_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-20-02-L-DV-WT_2x20_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-20-02-L-DV_2x20_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-20-02-NP-L-DV-WT_2x20_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-20-02-NP-L-DV_2x20_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-20-0_-L-DV_2x20_P1.27mm_Polarized_Edge +Connector_PCBEdge:Samtec_MECF-20-0_-NP-L-DV_2x20_P1.27mm_Edge +Connector_PCBEdge:Samtec_MECF-30-01-L-DV-WT_2x30_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-30-01-L-DV_2x30_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-30-01-NP-L-DV-WT_2x30_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-30-01-NP-L-DV_2x30_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-30-02-L-DV-WT_2x30_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-30-02-L-DV_2x30_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-30-02-NP-L-DV-WT_2x30_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-30-02-NP-L-DV_2x30_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-30-0_-L-DV_2x30_P1.27mm_Polarized_Edge +Connector_PCBEdge:Samtec_MECF-30-0_-NP-L-DV_2x30_P1.27mm_Edge +Connector_PCBEdge:Samtec_MECF-40-01-L-DV-WT_2x40_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-40-01-L-DV_2x40_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-40-01-NP-L-DV-WT_2x40_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-40-01-NP-L-DV_2x40_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-40-02-L-DV-WT_2x40_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-40-02-L-DV_2x40_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-40-02-NP-L-DV-WT_2x40_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-40-02-NP-L-DV_2x40_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-40-0_-L-DV_2x40_P1.27mm_Polarized_Edge +Connector_PCBEdge:Samtec_MECF-40-0_-NP-L-DV_2x40_P1.27mm_Edge +Connector_PCBEdge:Samtec_MECF-50-01-L-DV-WT_2x50_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-50-01-L-DV_2x50_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-50-01-NP-L-DV-WT_2x50_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-50-01-NP-L-DV_2x50_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-50-02-L-DV-WT_2x50_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-50-02-L-DV_2x50_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-50-02-NP-L-DV-WT_2x50_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-50-02-NP-L-DV_2x50_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-50-0_-L-DV_2x50_P1.27mm_Polarized_Edge +Connector_PCBEdge:Samtec_MECF-50-0_-NP-L-DV_2x50_P1.27mm_Edge +Connector_PCBEdge:Samtec_MECF-60-01-L-DV-WT_2x60_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-60-01-L-DV_2x60_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-60-01-NP-L-DV-WT_2x60_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-60-01-NP-L-DV_2x60_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-60-02-L-DV-WT_2x60_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-60-02-L-DV_2x60_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-60-02-NP-L-DV-WT_2x60_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-60-02-NP-L-DV_2x60_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-60-0_-L-DV_2x60_P1.27mm_Polarized_Edge +Connector_PCBEdge:Samtec_MECF-60-0_-NP-L-DV_2x60_P1.27mm_Edge +Connector_PCBEdge:Samtec_MECF-70-01-L-DV-WT_2x70_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-70-01-L-DV_2x70_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-70-01-NP-L-DV-WT_2x70_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-70-01-NP-L-DV_2x70_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-70-02-L-DV-WT_2x70_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-70-02-L-DV_2x70_P1.27mm_Polarized_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-70-02-NP-L-DV-WT_2x70_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-70-02-NP-L-DV_2x70_P1.27mm_Socket_Horizontal +Connector_PCBEdge:Samtec_MECF-70-0_-L-DV_2x70_P1.27mm_Polarized_Edge +Connector_PCBEdge:Samtec_MECF-70-0_-NP-L-DV_2x70_P1.27mm_Edge +Connector_PCBEdge:SODIMM-200_1.8V_Card_edge +Connector_PCBEdge:SODIMM-200_2.5V_Card_edge +Connector_PCBEdge:SODIMM-260_DDR4_H4.0-5.2_OrientationStd_Socket +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_10-G-7,62_1x10_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_10-G_1x10_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_11-G-7,62_1x11_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_11-G_1x11_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_12-G-7,62_1x12_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_12-G_1x12_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_2-G-7,62_1x02_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_2-G_1x02_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_3-G-7,62_1x03_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_3-G_1x03_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_4-G-7,62_1x04_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_4-G_1x04_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_5-G-7,62_1x05_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_5-G_1x05_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_6-G-7,62_1x06_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_6-G_1x06_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_7-G-7,62_1x07_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_7-G_1x07_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_8-G-7,62_1x08_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_8-G_1x08_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_9-G-7,62_1x09_P7.62mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBA_2,5_9-G_1x09_P7.50mm_Horizontal +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_10-G-7,62_1x10_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_10-G_1x10_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_11-G-7,62_1x11_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_11-G_1x11_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_12-G-7,62_1x12_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_12-G_1x12_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_2-G-7,62_1x02_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_2-G_1x02_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_3-G-7,62_1x03_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_3-G_1x03_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_4-G-7,62_1x04_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_4-G_1x04_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_5-G-7,62_1x05_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_5-G_1x05_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_6-G-7,62_1x06_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_6-G_1x06_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_7-G-7,62_1x07_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_7-G_1x07_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_8-G-7,62_1x08_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_8-G_1x08_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_9-G-7,62_1x09_P7.62mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBVA_2,5_9-G_1x09_P7.50mm_Vertical +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_10-GF-7,62_1x10_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_10-GF-7,62_1x10_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_11-GF-7,62_1x11_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_11-GF-7,62_1x11_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_12-GF-7,62_1x12_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_12-GF-7,62_1x12_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_2-GF-7,62_1x02_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_2-GF-7,62_1x02_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_3-GF-7,62_1x03_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_3-GF-7,62_1x03_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_4-GF-7,62_1x04_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_4-GF-7,62_1x04_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_5-GF-7,62_1x05_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_5-GF-7,62_1x05_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_6-GF-7,62_1x06_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_6-GF-7,62_1x06_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_7-GF-7,62_1x07_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_7-GF-7,62_1x07_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_8-GF-7,62_1x08_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_8-GF-7,62_1x08_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_9-GF-7,62_1x09_P7.62mm_Vertical_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTBV_2,5_9-GF-7,62_1x09_P7.62mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_10-GF-7,62_1x10_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_10-GF-7,62_1x10_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_11-GF-7,62_1x11_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_11-GF-7,62_1x11_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_12-GF-7,62_1x12_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_12-GF-7,62_1x12_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_2-GF-7,62_1x02_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_2-GF-7,62_1x02_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_3-GF-7,62_1x03_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_3-GF-7,62_1x03_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_4-GF-7,62_1x04_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_4-GF-7,62_1x04_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_5-GF-7,62_1x05_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_5-GF-7,62_1x05_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_6-GF-7,62_1x06_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_6-GF-7,62_1x06_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_7-GF-7,62_1x07_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_7-GF-7,62_1x07_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_8-GF-7,62_1x08_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_8-GF-7,62_1x08_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_9-GF-7,62_1x09_P7.62mm_Horizontal_ThreadedFlange +Connector_Phoenix_GMSTB:PhoenixContact_GMSTB_2,5_9-GF-7,62_1x09_P7.62mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_10-G-3.5_1x10_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_10-G-3.81_1x10_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_10-GF-3.5_1x10_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_10-GF-3.5_1x10_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_10-GF-3.81_1x10_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_10-GF-3.81_1x10_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_11-G-3.5_1x11_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_11-G-3.81_1x11_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_11-GF-3.5_1x11_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_11-GF-3.5_1x11_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_11-GF-3.81_1x11_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_11-GF-3.81_1x11_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_12-G-3.5_1x12_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_12-G-3.81_1x12_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_12-GF-3.5_1x12_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_12-GF-3.5_1x12_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_12-GF-3.81_1x12_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_12-GF-3.81_1x12_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_13-G-3.5_1x13_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_13-G-3.81_1x13_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_13-GF-3.5_1x13_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_13-GF-3.5_1x13_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_13-GF-3.81_1x13_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_13-GF-3.81_1x13_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_14-G-3.5_1x14_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_14-G-3.81_1x14_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_14-GF-3.5_1x14_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_14-GF-3.5_1x14_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_14-GF-3.81_1x14_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_14-GF-3.81_1x14_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_15-G-3.5_1x15_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_15-G-3.81_1x15_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_15-GF-3.5_1x15_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_15-GF-3.5_1x15_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_15-GF-3.81_1x15_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_15-GF-3.81_1x15_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_16-G-3.5_1x16_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_16-G-3.81_1x16_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_16-GF-3.5_1x16_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_16-GF-3.5_1x16_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_16-GF-3.81_1x16_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_16-GF-3.81_1x16_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_2-G-3.5_1x02_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_2-G-3.81_1x02_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_2-GF-3.5_1x02_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_2-GF-3.5_1x02_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_2-GF-3.81_1x02_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_2-GF-3.81_1x02_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_3-G-3.5_1x03_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_3-G-3.81_1x03_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_3-GF-3.5_1x03_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_3-GF-3.5_1x03_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_3-GF-3.81_1x03_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_3-GF-3.81_1x03_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_4-G-3.5_1x04_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_4-G-3.81_1x04_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_4-GF-3.5_1x04_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_4-GF-3.5_1x04_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_4-GF-3.81_1x04_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_4-GF-3.81_1x04_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_5-G-3.5_1x05_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_5-G-3.81_1x05_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_5-GF-3.5_1x05_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_5-GF-3.5_1x05_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_5-GF-3.81_1x05_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_5-GF-3.81_1x05_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_6-G-3.5_1x06_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_6-G-3.81_1x06_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_6-GF-3.5_1x06_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_6-GF-3.5_1x06_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_6-GF-3.81_1x06_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_6-GF-3.81_1x06_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_7-G-3.5_1x07_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_7-G-3.81_1x07_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_7-GF-3.5_1x07_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_7-GF-3.5_1x07_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_7-GF-3.81_1x07_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_7-GF-3.81_1x07_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_8-G-3.5_1x08_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_8-G-3.81_1x08_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_8-GF-3.5_1x08_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_8-GF-3.5_1x08_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_8-GF-3.81_1x08_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_8-GF-3.81_1x08_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_9-G-3.5_1x09_P3.50mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_9-G-3.81_1x09_P3.81mm_Vertical +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_9-GF-3.5_1x09_P3.50mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_9-GF-3.5_1x09_P3.50mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_9-GF-3.81_1x09_P3.81mm_Vertical_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MCV_1,5_9-GF-3.81_1x09_P3.81mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_10-G-3.5_1x10_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_10-G-3.81_1x10_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_10-GF-3.5_1x10_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_10-GF-3.5_1x10_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_10-GF-3.81_1x10_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_10-GF-3.81_1x10_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_11-G-3.5_1x11_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_11-G-3.81_1x11_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_11-GF-3.5_1x11_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_11-GF-3.5_1x11_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_11-GF-3.81_1x11_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_11-GF-3.81_1x11_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_12-G-3.5_1x12_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_12-G-3.81_1x12_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_12-GF-3.5_1x12_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_12-GF-3.5_1x12_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_12-GF-3.81_1x12_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_12-GF-3.81_1x12_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_13-G-3.5_1x13_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_13-G-3.81_1x13_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_13-GF-3.5_1x13_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_13-GF-3.5_1x13_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_13-GF-3.81_1x13_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_13-GF-3.81_1x13_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_14-G-3.5_1x14_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_14-G-3.81_1x14_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_14-GF-3.5_1x14_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_14-GF-3.5_1x14_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_14-GF-3.81_1x14_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_14-GF-3.81_1x14_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_15-G-3.5_1x15_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_15-G-3.81_1x15_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_15-GF-3.5_1x15_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_15-GF-3.5_1x15_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_15-GF-3.81_1x15_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_15-GF-3.81_1x15_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_16-G-3.5_1x16_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_16-G-3.81_1x16_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_16-GF-3.5_1x16_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_16-GF-3.5_1x16_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_16-GF-3.81_1x16_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_16-GF-3.81_1x16_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_2-G-3.5_1x02_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_2-G-3.81_1x02_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_2-GF-3.5_1x02_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_2-GF-3.5_1x02_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_2-GF-3.81_1x02_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_2-GF-3.81_1x02_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_3-G-3.5_1x03_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_3-G-3.81_1x03_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_3-GF-3.5_1x03_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_3-GF-3.5_1x03_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_3-GF-3.81_1x03_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_3-GF-3.81_1x03_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_4-G-3.5_1x04_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_4-G-3.81_1x04_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_4-GF-3.5_1x04_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_4-GF-3.5_1x04_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_4-GF-3.81_1x04_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_4-GF-3.81_1x04_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_5-G-3.5_1x05_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_5-G-3.81_1x05_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_5-GF-3.5_1x05_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_5-GF-3.5_1x05_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_5-GF-3.81_1x05_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_5-GF-3.81_1x05_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_6-G-3.5_1x06_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_6-G-3.81_1x06_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_6-GF-3.5_1x06_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_6-GF-3.5_1x06_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_6-GF-3.81_1x06_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_6-GF-3.81_1x06_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_7-G-3.5_1x07_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_7-G-3.81_1x07_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_7-GF-3.5_1x07_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_7-GF-3.5_1x07_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_7-GF-3.81_1x07_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_7-GF-3.81_1x07_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_8-G-3.5_1x08_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_8-G-3.81_1x08_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_8-GF-3.5_1x08_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_8-GF-3.5_1x08_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_8-GF-3.81_1x08_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_8-GF-3.81_1x08_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_9-G-3.5_1x09_P3.50mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_9-G-3.81_1x09_P3.81mm_Horizontal +Connector_Phoenix_MC:PhoenixContact_MC_1,5_9-GF-3.5_1x09_P3.50mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_9-GF-3.5_1x09_P3.50mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC:PhoenixContact_MC_1,5_9-GF-3.81_1x09_P3.81mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC:PhoenixContact_MC_1,5_9-GF-3.81_1x09_P3.81mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_10-G-5.08_1x10_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_10-GF-5.08_1x10_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_10-GF-5.08_1x10_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_11-G-5.08_1x11_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_11-GF-5.08_1x11_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_11-GF-5.08_1x11_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_12-G-5.08_1x12_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_12-GF-5.08_1x12_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_12-GF-5.08_1x12_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_2-G-5.08_1x02_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_2-GF-5.08_1x02_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_2-GF-5.08_1x02_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_3-G-5.08_1x03_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_3-GF-5.08_1x03_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_3-GF-5.08_1x03_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_4-G-5.08_1x04_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_4-GF-5.08_1x04_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_4-GF-5.08_1x04_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_5-G-5.08_1x05_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_5-GF-5.08_1x05_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_5-GF-5.08_1x05_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_6-G-5.08_1x06_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_6-GF-5.08_1x06_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_6-GF-5.08_1x06_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_7-G-5.08_1x07_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_7-GF-5.08_1x07_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_7-GF-5.08_1x07_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_8-G-5.08_1x08_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_8-GF-5.08_1x08_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_8-GF-5.08_1x08_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_9-G-5.08_1x09_P5.08mm_Vertical +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_9-GF-5.08_1x09_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MCV_1,5_9-GF-5.08_1x09_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_10-G-5.08_1x10_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_10-GF-5.08_1x10_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_10-GF-5.08_1x10_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_11-G-5.08_1x11_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_11-GF-5.08_1x11_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_11-GF-5.08_1x11_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_12-G-5.08_1x12_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_12-GF-5.08_1x12_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_12-GF-5.08_1x12_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_2-G-5.08_1x02_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_2-GF-5.08_1x02_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_2-GF-5.08_1x02_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_3-G-5.08_1x03_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_3-GF-5.08_1x03_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_3-GF-5.08_1x03_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_4-G-5.08_1x04_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_4-GF-5.08_1x04_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_4-GF-5.08_1x04_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_5-G-5.08_1x05_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_5-GF-5.08_1x05_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_5-GF-5.08_1x05_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_6-G-5.08_1x06_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_6-GF-5.08_1x06_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_6-GF-5.08_1x06_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_7-G-5.08_1x07_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_7-GF-5.08_1x07_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_7-GF-5.08_1x07_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_8-G-5.08_1x08_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_8-GF-5.08_1x08_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_8-GF-5.08_1x08_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_9-G-5.08_1x09_P5.08mm_Horizontal +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_9-GF-5.08_1x09_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MC_HighVoltage:PhoenixContact_MC_1,5_9-GF-5.08_1x09_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_10-G-5,08_1x10_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_10-G_1x10_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_11-G-5,08_1x11_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_11-G_1x11_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_12-G-5,08_1x12_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_12-G_1x12_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_13-G-5,08_1x13_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_13-G_1x13_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_14-G-5,08_1x14_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_14-G_1x14_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_15-G-5,08_1x15_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_15-G_1x15_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_16-G-5,08_1x16_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_16-G_1x16_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_2-G-5,08_1x02_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_2-G_1x02_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_3-G-5,08_1x03_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_3-G_1x03_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_4-G-5,08_1x04_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_4-G_1x04_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_5-G-5,08_1x05_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_5-G_1x05_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_6-G-5,08_1x06_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_6-G_1x06_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_7-G-5,08_1x07_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_7-G_1x07_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_8-G-5,08_1x08_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_8-G_1x08_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_9-G-5,08_1x09_P5.08mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBA_2,5_9-G_1x09_P5.00mm_Horizontal +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_10-G-5,08_1x10_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_10-G_1x10_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_11-G-5,08_1x11_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_11-G_1x11_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_12-G-5,08_1x12_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_12-G_1x12_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_13-G-5,08_1x13_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_13-G_1x13_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_14-G-5,08_1x14_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_14-G_1x14_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_15-G-5,08_1x15_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_15-G_1x15_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_16-G-5,08_1x16_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_16-G_1x16_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_2-G-5,08_1x02_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_2-G_1x02_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_3-G-5,08_1x03_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_3-G_1x03_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_4-G-5,08_1x04_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_4-G_1x04_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_5-G-5,08_1x05_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_5-G_1x05_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_6-G-5,08_1x06_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_6-G_1x06_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_7-G-5,08_1x07_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_7-G_1x07_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_8-G-5,08_1x08_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_8-G_1x08_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_9-G-5,08_1x09_P5.08mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBVA_2,5_9-G_1x09_P5.00mm_Vertical +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_10-GF-5,08_1x10_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_10-GF-5,08_1x10_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_10-GF_1x10_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_10-GF_1x10_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_11-GF-5,08_1x11_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_11-GF-5,08_1x11_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_11-GF_1x11_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_11-GF_1x11_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_12-GF-5,08_1x12_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_12-GF-5,08_1x12_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_12-GF_1x12_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_12-GF_1x12_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_13-GF-5,08_1x13_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_13-GF-5,08_1x13_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_13-GF_1x13_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_13-GF_1x13_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_14-GF-5,08_1x14_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_14-GF-5,08_1x14_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_14-GF_1x14_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_14-GF_1x14_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_15-GF-5,08_1x15_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_15-GF-5,08_1x15_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_15-GF_1x15_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_15-GF_1x15_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_16-GF-5,08_1x16_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_16-GF-5,08_1x16_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_16-GF_1x16_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_16-GF_1x16_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_2-GF-5,08_1x02_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_2-GF-5,08_1x02_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_2-GF_1x02_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_2-GF_1x02_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_3-GF-5,08_1x03_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_3-GF-5,08_1x03_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_3-GF_1x03_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_3-GF_1x03_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_4-GF-5,08_1x04_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_4-GF-5,08_1x04_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_4-GF_1x04_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_4-GF_1x04_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_5-GF-5,08_1x05_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_5-GF-5,08_1x05_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_5-GF_1x05_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_5-GF_1x05_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_6-GF-5,08_1x06_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_6-GF-5,08_1x06_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_6-GF_1x06_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_6-GF_1x06_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_7-GF-5,08_1x07_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_7-GF-5,08_1x07_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_7-GF_1x07_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_7-GF_1x07_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_8-GF-5,08_1x08_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_8-GF-5,08_1x08_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_8-GF_1x08_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_8-GF_1x08_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_9-GF-5,08_1x09_P5.08mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_9-GF-5,08_1x09_P5.08mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_9-GF_1x09_P5.00mm_Vertical_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTBV_2,5_9-GF_1x09_P5.00mm_Vertical_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_10-GF-5,08_1x10_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_10-GF-5,08_1x10_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_10-GF_1x10_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_10-GF_1x10_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_11-GF-5,08_1x11_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_11-GF-5,08_1x11_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_11-GF_1x11_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_11-GF_1x11_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_12-GF-5,08_1x12_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_12-GF-5,08_1x12_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_12-GF_1x12_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_12-GF_1x12_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_13-GF-5,08_1x13_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_13-GF-5,08_1x13_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_13-GF_1x13_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_13-GF_1x13_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_14-GF-5,08_1x14_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_14-GF-5,08_1x14_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_14-GF_1x14_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_14-GF_1x14_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_15-GF-5,08_1x15_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_15-GF-5,08_1x15_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_15-GF_1x15_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_15-GF_1x15_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_16-GF-5,08_1x16_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_16-GF-5,08_1x16_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_16-GF_1x16_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_16-GF_1x16_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_2-GF-5,08_1x02_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_2-GF-5,08_1x02_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_2-GF_1x02_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_2-GF_1x02_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_3-GF-5,08_1x03_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_3-GF-5,08_1x03_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_3-GF_1x03_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_3-GF_1x03_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_4-GF-5,08_1x04_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_4-GF-5,08_1x04_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_4-GF_1x04_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_4-GF_1x04_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_5-GF-5,08_1x05_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_5-GF-5,08_1x05_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_5-GF_1x05_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_5-GF_1x05_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_6-GF-5,08_1x06_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_6-GF-5,08_1x06_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_6-GF_1x06_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_6-GF_1x06_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_7-GF-5,08_1x07_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_7-GF-5,08_1x07_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_7-GF_1x07_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_7-GF_1x07_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_8-GF-5,08_1x08_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_8-GF-5,08_1x08_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_8-GF_1x08_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_8-GF_1x08_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_9-GF-5,08_1x09_P5.08mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_9-GF-5,08_1x09_P5.08mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_9-GF_1x09_P5.00mm_Horizontal_ThreadedFlange +Connector_Phoenix_MSTB:PhoenixContact_MSTB_2,5_9-GF_1x09_P5.00mm_Horizontal_ThreadedFlange_MountHole +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_10-H-3.5_1x10_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_11-H-3.5_1x11_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_12-H-3.5_1x12_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_2-H-3.5_1x02_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_3-H-3.5_1x03_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_4-H-3.5_1x04_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_5-H-3.5_1x05_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_6-H-3.5_1x06_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_7-H-3.5_1x07_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_8-H-3.5_1x08_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_1.5_9-H-3.5_1x09_P3.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_1-H-5.0_1x01_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_10-H-5.0-EX_1x10_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_10-H-5.0_1x10_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_10-V-5.0-EX_1x10_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_11-H-5.0-EX_1x11_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_11-H-5.0_1x11_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_11-V-5.0-EX_1x11_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_12-H-5.0-EX_1x12_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_12-H-5.0_1x12_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_12-V-5.0-EX_1x12_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_2-H-5.0-EX_1x02_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_2-H-5.0_1x02_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_2-V-5.0-EX_1x02_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_3-H-5.0-EX_1x03_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_3-H-5.0_1x03_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_3-V-5.0-EX_1x03_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_4-H-5.0-EX_1x04_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_4-H-5.0_1x04_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_4-V-5.0-EX_1x04_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_5-H-5.0-EX_1x05_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_5-H-5.0_1x05_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_5-V-5.0-EX_1x05_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_6-H-5.0-EX_1x06_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_6-H-5.0_1x06_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_6-V-5.0-EX_1x06_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_7-H-5.0-EX_1x07_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_7-H-5.0_1x07_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_7-V-5.0-EX_1x07_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_8-H-5.0-EX_1x08_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_8-H-5.0_1x08_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_8-V-5.0-EX_1x08_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_9-H-5.0-EX_1x09_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_9-H-5.0_1x09_P5.0mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_2.5_9-V-5.0-EX_1x09_P5.0mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_1-H-7.5_1x01_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_1-V-7.5_1x01_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_10-H-7.5-ZB_1x10_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_10-V-7.5-ZB_1x10_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_11-H-7.5-ZB_1x11_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_11-V-7.5-ZB_1x11_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_12-H-7.5-ZB_1x12_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_12-V-7.5-ZB_1x12_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_2-H-7.5-ZB_1x02_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_2-V-7.5_1x02_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_3-H-7.5-ZB_1x03_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_3-H-7.5_1x03_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_3-V-7.5-ZB_1x03_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_4-H-7.5-ZB_1x04_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_5-H-7.5-ZB_1x05_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_5-V-7.5-ZB_1x05_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_6-H-7.5-ZB_1x06_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_6-V-7.5-ZB_1x06_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_7-H-7.5-ZB_1x07_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_7-V-7.5-ZB_1x07_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_8-H-7.5-ZB_1x08_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_8-V-7.5-ZB_1x08_P7.5mm_Vertical +Connector_Phoenix_SPT:PhoenixContact_SPT_5_9-H-7.5-ZB_1x09_P7.5mm_Horizontal +Connector_Phoenix_SPT:PhoenixContact_SPT_5_9-V-7.5-ZB_1x09_P7.5mm_Vertical +Connector_Pin:Pin_D0.7mm_L6.5mm_W1.8mm_FlatFork +Connector_Pin:Pin_D0.9mm_L10.0mm_W2.4mm_FlatFork +Connector_Pin:Pin_D1.0mm_L10.0mm +Connector_Pin:Pin_D1.0mm_L10.0mm_LooseFit +Connector_Pin:Pin_D1.1mm_L10.2mm_W3.5mm_Flat +Connector_Pin:Pin_D1.1mm_L8.5mm_W2.5mm_FlatFork +Connector_Pin:Pin_D1.2mm_L10.2mm_W2.9mm_FlatFork +Connector_Pin:Pin_D1.2mm_L11.3mm_W3.0mm_Flat +Connector_Pin:Pin_D1.3mm_L10.0mm_W3.5mm_Flat +Connector_Pin:Pin_D1.3mm_L11.0mm +Connector_Pin:Pin_D1.3mm_L11.0mm_LooseFit +Connector_Pin:Pin_D1.3mm_L11.3mm_W2.8mm_Flat +Connector_Pin:Pin_D1.4mm_L8.5mm_W2.8mm_FlatFork +Connector_PinHeader_1.00mm:PinHeader_1x01_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x01_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x02_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x02_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x02_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x02_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x03_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x03_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x03_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x03_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x04_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x04_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x04_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x04_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x05_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x05_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x05_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x05_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x06_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x06_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x06_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x06_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x07_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x07_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x07_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x07_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x08_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x08_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x08_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x08_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x09_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x09_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x09_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x09_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x10_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x10_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x10_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x10_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x11_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x11_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x11_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x11_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x12_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x12_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x12_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x12_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x13_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x13_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x13_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x13_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x14_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x14_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x14_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x14_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x15_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x15_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x15_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x15_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x16_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x16_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x16_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x16_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x17_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x17_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x17_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x17_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x18_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x18_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x18_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x18_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x19_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x19_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x19_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x19_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x20_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x20_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x20_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x20_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x21_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x21_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x21_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x21_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x22_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x22_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x22_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x22_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x23_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x23_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x23_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x23_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x24_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x24_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x24_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x24_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x25_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x25_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x25_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x25_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x26_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x26_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x26_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x26_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x27_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x27_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x27_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x27_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x28_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x28_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x28_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x28_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x29_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x29_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x29_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x29_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x30_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x30_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x30_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x30_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x31_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x31_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x31_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x31_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x32_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x32_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x32_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x32_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x33_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x33_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x33_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x33_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x34_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x34_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x34_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x34_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x35_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x35_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x35_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x35_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x36_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x36_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x36_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x36_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x37_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x37_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x37_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x37_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x38_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x38_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x38_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x38_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x39_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x39_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x39_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x39_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_1x40_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_1x40_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_1x40_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.00mm:PinHeader_1x40_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.00mm:PinHeader_2x01_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x01_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x01_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x02_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x02_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x02_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x03_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x03_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x03_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x04_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x04_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x04_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x05_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x05_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x05_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x06_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x06_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x06_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x07_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x07_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x07_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x08_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x08_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x08_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x09_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x09_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x09_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x10_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x10_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x10_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x11_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x11_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x11_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x12_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x12_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x12_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x13_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x13_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x13_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x14_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x14_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x14_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x15_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x15_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x15_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x16_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x16_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x16_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x17_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x17_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x17_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x18_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x18_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x18_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x19_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x19_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x19_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x20_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x20_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x20_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x21_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x21_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x21_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x22_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x22_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x22_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x23_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x23_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x23_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x24_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x24_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x24_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x25_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x25_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x25_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x26_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x26_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x26_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x27_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x27_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x27_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x28_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x28_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x28_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x29_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x29_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x29_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x30_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x30_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x30_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x31_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x31_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x31_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x32_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x32_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x32_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x33_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x33_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x33_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x34_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x34_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x34_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x35_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x35_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x35_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x36_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x36_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x36_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x37_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x37_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x37_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x38_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x38_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x38_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x39_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x39_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x39_P1.00mm_Vertical_SMD +Connector_PinHeader_1.00mm:PinHeader_2x40_P1.00mm_Horizontal +Connector_PinHeader_1.00mm:PinHeader_2x40_P1.00mm_Vertical +Connector_PinHeader_1.00mm:PinHeader_2x40_P1.00mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_1x01_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x01_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x02_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x02_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x02_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x02_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x03_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x03_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x03_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x03_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x04_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x04_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x04_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x04_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x05_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x05_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x05_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x05_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x06_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x06_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x06_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x06_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x07_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x07_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x07_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x07_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x08_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x08_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x08_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x08_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x09_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x09_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x09_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x09_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x10_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x10_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x10_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x10_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x11_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x11_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x11_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x11_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x12_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x12_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x12_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x12_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x13_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x13_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x13_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x13_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x14_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x14_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x14_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x14_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x15_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x15_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x15_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x15_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x16_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x16_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x16_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x16_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x17_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x17_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x17_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x17_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x18_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x18_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x18_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x18_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x19_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x19_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x19_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x19_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x20_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x20_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x20_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x20_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x21_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x21_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x21_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x21_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x22_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x22_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x22_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x22_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x23_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x23_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x23_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x23_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x24_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x24_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x24_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x24_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x25_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x25_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x25_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x25_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x26_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x26_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x26_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x26_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x27_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x27_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x27_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x27_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x28_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x28_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x28_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x28_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x29_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x29_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x29_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x29_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x30_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x30_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x30_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x30_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x31_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x31_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x31_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x31_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x32_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x32_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x32_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x32_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x33_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x33_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x33_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x33_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x34_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x34_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x34_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x34_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x35_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x35_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x35_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x35_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x36_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x36_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x36_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x36_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x37_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x37_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x37_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x37_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x38_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x38_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x38_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x38_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x39_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x39_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x39_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x39_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_1x40_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_1x40_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_1x40_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinHeader_1.27mm:PinHeader_1x40_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinHeader_1.27mm:PinHeader_2x01_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x01_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x01_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x02_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x02_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x02_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x03_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x03_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x03_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x04_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x04_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x04_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x05_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x05_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x05_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x06_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x06_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x06_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x07_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x07_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x07_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x08_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x08_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x08_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x09_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x09_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x09_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x10_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x10_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x10_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x11_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x11_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x11_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x12_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x12_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x12_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x13_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x13_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x13_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x14_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x14_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x14_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x15_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x15_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x15_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x16_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x16_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x16_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x17_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x17_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x17_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x18_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x18_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x18_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x19_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x19_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x19_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x20_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x20_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x20_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x21_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x21_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x21_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x22_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x22_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x22_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x23_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x23_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x23_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x24_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x24_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x24_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x25_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x25_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x25_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x26_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x26_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x26_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x27_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x27_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x27_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x28_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x28_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x28_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x29_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x29_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x29_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x30_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x30_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x30_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x31_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x31_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x31_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x32_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x32_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x32_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x33_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x33_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x33_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x34_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x34_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x34_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x35_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x35_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x35_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x36_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x36_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x36_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x37_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x37_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x37_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x38_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x38_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x38_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x39_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x39_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x39_P1.27mm_Vertical_SMD +Connector_PinHeader_1.27mm:PinHeader_2x40_P1.27mm_Horizontal +Connector_PinHeader_1.27mm:PinHeader_2x40_P1.27mm_Vertical +Connector_PinHeader_1.27mm:PinHeader_2x40_P1.27mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_1x01_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x01_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x02_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x02_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x02_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x02_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x03_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x03_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x03_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x03_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x04_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x04_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x04_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x04_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x05_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x05_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x05_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x05_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x06_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x06_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x06_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x06_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x07_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x07_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x07_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x07_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x08_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x08_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x08_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x08_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x09_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x09_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x09_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x09_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x10_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x10_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x10_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x10_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x11_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x11_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x11_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x11_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x12_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x12_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x12_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x12_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x13_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x13_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x13_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x13_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x14_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x14_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x14_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x14_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x15_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x15_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x15_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x15_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x16_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x16_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x16_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x16_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x17_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x17_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x17_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x17_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x18_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x18_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x18_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x18_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x19_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x19_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x19_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x19_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x20_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x20_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x20_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x20_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x21_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x21_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x21_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x21_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x22_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x22_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x22_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x22_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x23_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x23_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x23_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x23_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x24_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x24_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x24_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x24_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x25_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x25_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x25_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x25_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x26_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x26_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x26_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x26_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x27_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x27_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x27_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x27_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x28_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x28_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x28_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x28_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x29_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x29_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x29_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x29_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x30_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x30_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x30_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x30_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x31_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x31_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x31_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x31_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x32_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x32_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x32_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x32_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x33_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x33_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x33_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x33_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x34_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x34_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x34_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x34_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x35_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x35_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x35_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x35_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x36_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x36_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x36_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x36_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x37_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x37_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x37_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x37_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x38_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x38_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x38_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x38_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x39_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x39_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x39_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x39_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_1x40_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_1x40_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_1x40_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.00mm:PinHeader_1x40_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.00mm:PinHeader_2x01_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x01_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x01_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x02_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x02_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x02_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x03_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x03_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x03_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x04_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x04_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x04_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x05_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x05_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x05_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x06_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x06_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x06_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x07_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x07_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x07_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x08_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x08_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x08_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x09_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x09_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x09_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x10_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x10_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x10_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x11_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x11_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x11_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x12_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x12_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x12_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x13_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x13_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x13_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x14_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x14_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x14_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x15_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x15_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x15_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x16_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x16_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x16_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x17_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x17_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x17_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x18_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x18_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x18_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x19_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x19_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x19_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x20_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x20_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x20_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x21_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x21_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x21_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x22_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x22_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x22_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x23_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x23_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x23_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x24_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x24_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x24_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x25_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x25_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x25_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x26_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x26_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x26_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x27_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x27_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x27_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x28_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x28_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x28_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x29_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x29_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x29_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x30_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x30_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x30_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x31_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x31_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x31_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x32_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x32_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x32_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x33_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x33_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x33_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x34_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x34_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x34_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x35_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x35_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x35_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x36_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x36_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x36_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x37_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x37_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x37_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x38_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x38_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x38_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x39_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x39_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x39_P2.00mm_Vertical_SMD +Connector_PinHeader_2.00mm:PinHeader_2x40_P2.00mm_Horizontal +Connector_PinHeader_2.00mm:PinHeader_2x40_P2.00mm_Vertical +Connector_PinHeader_2.00mm:PinHeader_2x40_P2.00mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_1x01_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x01_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x05_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x05_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x05_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x05_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x06_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x06_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x06_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x06_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x07_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x07_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x07_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x07_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x08_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x08_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x08_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x08_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x09_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x09_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x09_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x09_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x10_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x10_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x10_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x10_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x11_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x11_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x11_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x11_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x12_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x12_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x12_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x12_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x13_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x13_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x13_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x13_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x14_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x14_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x14_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x14_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x15_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x15_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x15_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x15_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x16_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x16_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x16_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x16_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x17_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x17_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x17_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x17_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x18_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x18_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x18_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x18_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x19_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x19_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x19_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x19_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x20_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x20_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x20_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x20_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x21_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x21_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x21_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x21_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x22_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x22_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x22_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x22_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x23_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x23_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x23_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x23_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x24_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x24_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x24_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x24_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x25_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x25_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x25_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x25_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x26_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x26_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x26_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x26_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x27_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x27_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x27_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x27_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x28_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x28_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x28_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x28_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x29_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x29_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x29_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x29_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x30_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x30_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x30_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x30_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x31_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x31_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x31_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x31_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x32_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x32_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x32_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x32_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x33_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x33_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x33_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x33_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x34_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x34_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x34_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x34_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x35_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x35_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x35_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x35_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x36_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x36_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x36_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x36_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x37_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x37_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x37_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x37_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x38_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x38_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x38_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x38_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x39_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x39_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x39_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x39_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_1x40_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_1x40_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_1x40_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinHeader_2.54mm:PinHeader_1x40_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinHeader_2.54mm:PinHeader_2x01_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x01_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x01_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x02_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x02_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x02_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x04_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x04_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x04_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x05_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x05_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x05_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x06_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x06_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x06_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x07_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x07_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x07_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x08_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x08_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x08_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x09_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x09_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x09_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x10_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x10_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x10_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x11_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x11_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x11_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x12_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x12_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x12_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x13_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x13_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x13_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x14_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x14_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x14_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x15_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x15_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x15_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x16_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x16_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x16_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x17_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x17_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x17_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x18_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x18_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x18_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x19_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x19_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x19_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x20_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x20_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x20_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x21_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x21_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x21_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x22_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x22_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x22_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x23_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x23_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x23_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x24_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x24_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x24_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x25_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x25_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x25_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x26_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x26_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x26_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x27_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x27_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x27_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x28_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x28_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x28_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x29_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x29_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x29_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x30_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x30_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x30_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x31_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x31_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x31_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x32_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x32_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x32_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x33_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x33_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x33_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x34_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x34_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x34_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x35_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x35_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x35_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x36_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x36_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x36_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x37_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x37_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x37_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x38_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x38_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x38_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x39_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x39_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x39_P2.54mm_Vertical_SMD +Connector_PinHeader_2.54mm:PinHeader_2x40_P2.54mm_Horizontal +Connector_PinHeader_2.54mm:PinHeader_2x40_P2.54mm_Vertical +Connector_PinHeader_2.54mm:PinHeader_2x40_P2.54mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_1x02_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x02_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x02_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x03_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x03_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x03_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x04_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x04_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x04_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x05_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x05_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x05_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x06_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x06_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x06_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x07_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x07_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x07_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x08_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x08_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x08_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x09_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x09_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x09_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x10_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x10_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x10_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x11_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x11_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x11_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x12_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x12_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x12_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x13_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x13_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x13_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x14_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x14_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x14_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x15_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x15_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x15_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x16_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x16_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x16_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x17_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x17_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x17_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x18_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x18_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x18_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x19_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x19_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x19_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x20_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x20_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x20_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x21_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x21_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x21_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x22_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x22_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x22_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x23_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x23_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x23_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x24_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x24_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x24_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x25_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x25_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x25_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x26_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x26_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x26_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x27_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x27_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x27_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x28_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x28_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x28_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x29_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x29_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x29_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x30_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x30_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x30_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x31_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x31_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x31_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x32_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x32_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x32_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x33_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x33_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x33_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x34_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x34_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x34_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x35_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x35_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x35_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x36_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x36_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x36_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x37_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x37_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x37_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x38_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x38_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x38_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x39_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x39_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x39_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_1x40_P1.00mm_Vertical +Connector_PinSocket_1.00mm:PinSocket_1x40_P1.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.00mm:PinSocket_1x40_P1.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.00mm:PinSocket_2x02_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x03_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x04_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x05_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x06_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x07_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x08_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x09_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x10_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x11_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x12_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x13_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x14_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x15_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x16_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x17_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x18_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x19_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x20_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x21_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x22_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x23_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x24_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x25_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x26_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x27_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x28_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x29_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x30_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x31_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x32_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x33_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x34_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x35_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x36_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x37_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x38_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x39_P1.00mm_Vertical_SMD +Connector_PinSocket_1.00mm:PinSocket_2x40_P1.00mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_1x01_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x02_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x02_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x02_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x03_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x03_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x03_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x04_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x04_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x04_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x05_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x05_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x05_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x06_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x06_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x06_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x07_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x07_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x07_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x08_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x08_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x08_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x09_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x09_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x09_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x10_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x10_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x10_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x11_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x11_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x11_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x12_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x12_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x12_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x13_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x13_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x13_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x14_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x14_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x14_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x15_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x15_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x15_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x16_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x16_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x16_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x17_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x17_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x17_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x18_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x18_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x18_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x19_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x19_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x19_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x20_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x20_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x20_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x21_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x21_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x21_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x22_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x22_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x22_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x23_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x23_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x23_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x24_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x24_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x24_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x25_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x25_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x25_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x26_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x26_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x26_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x27_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x27_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x27_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x28_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x28_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x28_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x29_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x29_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x29_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x30_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x30_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x30_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x31_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x31_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x31_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x32_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x32_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x32_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x33_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x33_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x33_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x34_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x34_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x34_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x35_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x35_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x35_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x36_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x36_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x36_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x37_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x37_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x37_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x38_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x38_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x38_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x39_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x39_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x39_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_1x40_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_1x40_P1.27mm_Vertical_SMD_Pin1Left +Connector_PinSocket_1.27mm:PinSocket_1x40_P1.27mm_Vertical_SMD_Pin1Right +Connector_PinSocket_1.27mm:PinSocket_2x01_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x01_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x02_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x02_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x03_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x03_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x03_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x04_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x04_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x04_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x05_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x05_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x05_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x06_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x06_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x06_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x07_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x07_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x07_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x08_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x08_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x08_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x09_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x09_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x09_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x10_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x10_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x10_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x11_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x11_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x11_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x12_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x12_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x12_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x13_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x13_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x13_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x14_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x14_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x14_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x15_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x15_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x15_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x16_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x16_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x16_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x17_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x17_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x17_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x18_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x18_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x18_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x19_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x19_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x19_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x20_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x20_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x20_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x21_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x21_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x21_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x22_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x22_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x22_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x23_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x23_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x23_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x24_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x24_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x24_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x25_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x25_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x25_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x26_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x26_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x26_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x27_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x27_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x27_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x28_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x28_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x28_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x29_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x29_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x29_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x30_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x30_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x30_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x31_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x31_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x31_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x32_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x32_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x32_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x33_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x33_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x33_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x34_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x34_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x34_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x35_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x35_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x35_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x36_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x36_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x36_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x37_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x37_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x37_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x38_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x38_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x38_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x39_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x39_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x39_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x40_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x40_P1.27mm_Vertical +Connector_PinSocket_1.27mm:PinSocket_2x40_P1.27mm_Vertical_SMD +Connector_PinSocket_1.27mm:PinSocket_2x41_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x42_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x43_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x44_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x45_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x46_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x47_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x48_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x49_P1.27mm_Horizontal +Connector_PinSocket_1.27mm:PinSocket_2x50_P1.27mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x01_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x01_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x02_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x02_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x02_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x02_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x03_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x03_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x03_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x03_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x04_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x04_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x04_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x04_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x05_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x05_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x05_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x05_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x06_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x06_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x06_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x06_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x07_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x07_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x07_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x07_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x08_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x08_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x08_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x08_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x09_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x09_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x09_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x09_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x10_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x10_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x10_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x10_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x11_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x11_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x11_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x11_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x12_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x12_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x12_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x12_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x13_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x13_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x13_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x13_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x14_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x14_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x14_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x14_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x15_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x15_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x15_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x15_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x16_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x16_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x16_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x16_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x17_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x17_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x17_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x17_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x18_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x18_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x18_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x18_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x19_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x19_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x19_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x19_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x20_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x20_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x20_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x20_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x21_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x21_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x21_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x21_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x22_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x22_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x22_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x22_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x23_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x23_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x23_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x23_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x24_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x24_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x24_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x24_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x25_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x25_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x25_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x25_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x26_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x26_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x26_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x26_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x27_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x27_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x27_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x27_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x28_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x28_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x28_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x28_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x29_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x29_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x29_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x29_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x30_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x30_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x30_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x30_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x31_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x31_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x31_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x31_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x32_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x32_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x32_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x32_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x33_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x33_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x33_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x33_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x34_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x34_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x34_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x34_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x35_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x35_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x35_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x35_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x36_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x36_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x36_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x36_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x37_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x37_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x37_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x37_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x38_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x38_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x38_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x38_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x39_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x39_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x39_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x39_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_1x40_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_1x40_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_1x40_P2.00mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.00mm:PinSocket_1x40_P2.00mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.00mm:PinSocket_2x01_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x01_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x01_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x02_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x02_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x02_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x03_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x03_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x03_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x04_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x04_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x04_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x05_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x05_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x05_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x06_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x06_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x06_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x07_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x07_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x07_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x08_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x08_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x08_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x09_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x09_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x09_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x10_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x10_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x10_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x11_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x11_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x11_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x12_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x12_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x12_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x13_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x13_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x13_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x14_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x14_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x14_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x15_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x15_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x15_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x16_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x16_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x16_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x17_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x17_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x17_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x18_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x18_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x18_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x19_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x19_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x19_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x20_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x20_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x20_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x21_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x21_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x21_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x22_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x22_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x22_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x23_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x23_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x23_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x24_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x24_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x24_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x25_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x25_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x25_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x26_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x26_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x26_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x27_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x27_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x27_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x28_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x28_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x28_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x29_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x29_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x29_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x30_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x30_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x30_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x31_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x31_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x31_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x32_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x32_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x32_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x33_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x33_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x33_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x34_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x34_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x34_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x35_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x35_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x35_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x36_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x36_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x36_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x37_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x37_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x37_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x38_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x38_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x38_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x39_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x39_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x39_P2.00mm_Vertical_SMD +Connector_PinSocket_2.00mm:PinSocket_2x40_P2.00mm_Horizontal +Connector_PinSocket_2.00mm:PinSocket_2x40_P2.00mm_Vertical +Connector_PinSocket_2.00mm:PinSocket_2x40_P2.00mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_1x01_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x01_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x02_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x02_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x02_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x02_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x03_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x03_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x03_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x03_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x06_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x06_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x06_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x06_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x07_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x07_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x07_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x07_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x09_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x09_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x09_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x09_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x10_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x10_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x10_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x10_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x11_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x11_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x11_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x11_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x12_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x12_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x12_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x12_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x13_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x13_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x13_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x13_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x14_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x14_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x14_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x14_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x15_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x15_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x15_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x15_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x16_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x16_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x16_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x16_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x17_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x17_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x17_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x17_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x18_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x18_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x18_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x18_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x19_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x19_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x19_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x19_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x20_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x20_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x20_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x20_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x21_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x21_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x21_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x21_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x22_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x22_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x22_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x22_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x23_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x23_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x23_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x23_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x24_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x24_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x24_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x24_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x25_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x25_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x25_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x25_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x26_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x26_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x26_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x26_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x27_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x27_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x27_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x27_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x28_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x28_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x28_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x28_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x29_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x29_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x29_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x29_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x30_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x30_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x30_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x30_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x31_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x31_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x31_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x31_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x32_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x32_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x32_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x32_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x33_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x33_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x33_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x33_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x34_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x34_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x34_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x34_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x35_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x35_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x35_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x35_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x36_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x36_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x36_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x36_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x37_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x37_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x37_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x37_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x38_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x38_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x38_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x38_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x39_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x39_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x39_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x39_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_1x40_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_1x40_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_1x40_P2.54mm_Vertical_SMD_Pin1Left +Connector_PinSocket_2.54mm:PinSocket_1x40_P2.54mm_Vertical_SMD_Pin1Right +Connector_PinSocket_2.54mm:PinSocket_2x01_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x01_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x01_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x02_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x02_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x02_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x03_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x03_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x03_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x04_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x04_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x04_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x05_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x05_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x05_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x06_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x06_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x06_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x07_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x07_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x07_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x08_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x08_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x08_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x09_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x09_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x09_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x10_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x10_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x10_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x11_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x11_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x11_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x12_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x12_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x12_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x13_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x13_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x13_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x14_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x14_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x14_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x15_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x15_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x15_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x16_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x16_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x16_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x17_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x17_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x17_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x18_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x18_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x18_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x19_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x19_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x19_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x20_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x20_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x20_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x21_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x21_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x21_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x22_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x22_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x22_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x23_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x23_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x23_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x24_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x24_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x24_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x25_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x25_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x25_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x26_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x26_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x26_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x27_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x27_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x27_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x28_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x28_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x28_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x29_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x29_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x29_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x30_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x30_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x30_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x31_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x31_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x31_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x32_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x32_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x32_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x33_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x33_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x33_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x34_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x34_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x34_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x35_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x35_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x35_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x36_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x36_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x36_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x37_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x37_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x37_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x38_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x38_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x38_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x39_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x39_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x39_P2.54mm_Vertical_SMD +Connector_PinSocket_2.54mm:PinSocket_2x40_P2.54mm_Horizontal +Connector_PinSocket_2.54mm:PinSocket_2x40_P2.54mm_Vertical +Connector_PinSocket_2.54mm:PinSocket_2x40_P2.54mm_Vertical_SMD +Connector_RJ:RJ12_Amphenol_54601-x06_Horizontal +Connector_RJ:RJ14_Connfly_DS1133-S4_Horizontal +Connector_RJ:RJ25_Wayconn_MJEA-660X1_Horizontal +Connector_RJ:RJ45_Abracon_ARJP11A-MA_Horizontal +Connector_RJ:RJ45_Amphenol_54602-x08_Horizontal +Connector_RJ:RJ45_Amphenol_RJHSE5380-08 +Connector_RJ:RJ45_Amphenol_RJHSE5380 +Connector_RJ:RJ45_Amphenol_RJHSE538X-02 +Connector_RJ:RJ45_Amphenol_RJHSE538X-04 +Connector_RJ:RJ45_Amphenol_RJHSE538X +Connector_RJ:RJ45_Amphenol_RJMG1BD3B8K1ANR +Connector_RJ:RJ45_Bel_SI-60062-F +Connector_RJ:RJ45_BEL_SS74301-00x_Vertical +Connector_RJ:RJ45_Bel_V895-1001-AW_Vertical +Connector_RJ:RJ45_Cetus_J1B1211CCD_Horizontal +Connector_RJ:RJ45_Connfly_DS1128-09-S8xx-S_Horizontal +Connector_RJ:RJ45_HALO_HFJ11-x2450E-LxxRL_Horizontal +Connector_RJ:RJ45_HALO_HFJ11-x2450ERL_Horizontal +Connector_RJ:RJ45_HALO_HFJ11-x2450HRL_Horizontal +Connector_RJ:RJ45_Hanrun_HR911105A_Horizontal +Connector_RJ:RJ45_Kycon_G7LX-A88S7-BP-xx_Horizontal +Connector_RJ:RJ45_Molex_0855135013_Vertical +Connector_RJ:RJ45_Molex_9346520x_Horizontal +Connector_RJ:RJ45_Ninigi_GE +Connector_RJ:RJ45_OST_PJ012-8P8CX_Vertical +Connector_RJ:RJ45_Plug_Metz_AJP92A8813 +Connector_RJ:RJ45_Pulse_JK00177NL_Horizontal +Connector_RJ:RJ45_Pulse_JK0654219NL_Horizontal +Connector_RJ:RJ45_Pulse_JXD6-0001NL_Horizontal +Connector_RJ:RJ45_RCH_RC01937 +Connector_RJ:RJ45_UDE_RB1-125B8G1A +Connector_RJ:RJ45_Wuerth_74980111211_Horizontal +Connector_RJ:RJ45_Wuerth_7499010001A_Horizontal +Connector_RJ:RJ45_Wuerth_7499010121A_Horizontal +Connector_RJ:RJ45_Wuerth_7499010211A_Horizontal +Connector_RJ:RJ45_Wuerth_7499111446_Horizontal +Connector_RJ:RJ45_Wuerth_7499151120_Horizontal +Connector_RJ:RJ9_Evercom_5301-440xxx_Horizontal +Connector_Samtec:Samtec_FMC_ASP-134486-01_10x40_P1.27mm_Vertical +Connector_Samtec:Samtec_FMC_ASP-134602-01_10x40_P1.27mm_Vertical +Connector_Samtec:Samtec_FMC_ASP-134604-01_4x40_Vertical +Connector_Samtec:Samtec_LSHM-105-xx.x-x-DV-N_2x05_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-105-xx.x-x-DV-S_2x05-1SH_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-110-xx.x-x-DV-N_2x10_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-110-xx.x-x-DV-S_2x10-1SH_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-120-xx.x-x-DV-N_2x20_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-120-xx.x-x-DV-S_2x20-1SH_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-130-xx.x-x-DV-N_2x30_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-130-xx.x-x-DV-S_2x30-1SH_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-140-xx.x-x-DV-N_2x40_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-140-xx.x-x-DV-S_2x40-1SH_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-150-xx.x-x-DV-N_2x50_P0.50mm_Vertical +Connector_Samtec:Samtec_LSHM-150-xx.x-x-DV-S_2x50-1SH_P0.50mm_Vertical +Connector_Samtec_HLE_SMD:Samtec_HLE-102-02-xxx-DV-BE-LC_2x02_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-102-02-xxx-DV-BE_2x02_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-102-02-xxx-DV-LC_2x02_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-102-02-xxx-DV_2x02_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-103-02-xxx-DV-BE-LC_2x03_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-103-02-xxx-DV-BE_2x03_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-103-02-xxx-DV-LC_2x03_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-103-02-xxx-DV_2x03_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-104-02-xxx-DV-A_2x04_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-104-02-xxx-DV-BE-A_2x04_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-104-02-xxx-DV-BE-LC_2x04_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-104-02-xxx-DV-BE_2x04_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-104-02-xxx-DV-LC_2x04_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-104-02-xxx-DV_2x04_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-105-02-xxx-DV-A_2x05_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-105-02-xxx-DV-BE-A_2x05_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-105-02-xxx-DV-BE-LC_2x05_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-105-02-xxx-DV-BE_2x05_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-105-02-xxx-DV-LC_2x05_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-105-02-xxx-DV_2x05_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-106-02-xxx-DV-A_2x06_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-106-02-xxx-DV-BE-A_2x06_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-106-02-xxx-DV-BE-LC_2x06_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-106-02-xxx-DV-BE_2x06_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-106-02-xxx-DV-LC_2x06_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-106-02-xxx-DV_2x06_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-107-02-xxx-DV-A_2x07_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-107-02-xxx-DV-BE-A_2x07_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-107-02-xxx-DV-BE-LC_2x07_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-107-02-xxx-DV-BE_2x07_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-107-02-xxx-DV-LC_2x07_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-107-02-xxx-DV_2x07_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-108-02-xxx-DV-A_2x08_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-108-02-xxx-DV-BE-A_2x08_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-108-02-xxx-DV-BE-LC_2x08_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-108-02-xxx-DV-BE_2x08_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-108-02-xxx-DV-LC_2x08_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-108-02-xxx-DV_2x08_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-109-02-xxx-DV-A_2x09_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-109-02-xxx-DV-BE-A_2x09_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-109-02-xxx-DV-BE-LC_2x09_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-109-02-xxx-DV-BE_2x09_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-109-02-xxx-DV-LC_2x09_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-109-02-xxx-DV_2x09_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-110-02-xxx-DV-A_2x10_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-110-02-xxx-DV-BE-A_2x10_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-110-02-xxx-DV-BE-LC_2x10_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-110-02-xxx-DV-BE_2x10_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-110-02-xxx-DV-LC_2x10_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-110-02-xxx-DV_2x10_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-111-02-xxx-DV-A_2x11_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-111-02-xxx-DV-BE-A_2x11_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-111-02-xxx-DV-BE-LC_2x11_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-111-02-xxx-DV-BE_2x11_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-111-02-xxx-DV-LC_2x11_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-111-02-xxx-DV_2x11_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-112-02-xxx-DV-A_2x12_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-112-02-xxx-DV-BE-A_2x12_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-112-02-xxx-DV-BE-LC_2x12_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-112-02-xxx-DV-BE_2x12_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-112-02-xxx-DV-LC_2x12_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-112-02-xxx-DV_2x12_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-113-02-xxx-DV-A_2x13_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-113-02-xxx-DV-BE-A_2x13_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-113-02-xxx-DV-BE-LC_2x13_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-113-02-xxx-DV-BE_2x13_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-113-02-xxx-DV-LC_2x13_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-113-02-xxx-DV_2x13_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-114-02-xxx-DV-A_2x14_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-114-02-xxx-DV-BE-A_2x14_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-114-02-xxx-DV-BE-LC_2x14_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-114-02-xxx-DV-BE_2x14_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-114-02-xxx-DV-LC_2x14_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-114-02-xxx-DV_2x14_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-115-02-xxx-DV-A_2x15_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-115-02-xxx-DV-BE-A_2x15_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-115-02-xxx-DV-BE-LC_2x15_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-115-02-xxx-DV-BE_2x15_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-115-02-xxx-DV-LC_2x15_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-115-02-xxx-DV_2x15_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-116-02-xxx-DV-A_2x16_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-116-02-xxx-DV-BE-A_2x16_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-116-02-xxx-DV-BE-LC_2x16_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-116-02-xxx-DV-BE_2x16_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-116-02-xxx-DV-LC_2x16_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-116-02-xxx-DV_2x16_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-117-02-xxx-DV-A_2x17_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-117-02-xxx-DV-BE-A_2x17_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-117-02-xxx-DV-BE-LC_2x17_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-117-02-xxx-DV-BE_2x17_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-117-02-xxx-DV-LC_2x17_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-117-02-xxx-DV_2x17_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-118-02-xxx-DV-A_2x18_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-118-02-xxx-DV-BE-A_2x18_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-118-02-xxx-DV-BE-LC_2x18_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-118-02-xxx-DV-BE_2x18_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-118-02-xxx-DV-LC_2x18_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-118-02-xxx-DV_2x18_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-119-02-xxx-DV-A_2x19_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-119-02-xxx-DV-BE-A_2x19_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-119-02-xxx-DV-BE-LC_2x19_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-119-02-xxx-DV-BE_2x19_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-119-02-xxx-DV-LC_2x19_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-119-02-xxx-DV_2x19_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-120-02-xxx-DV-A_2x20_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-120-02-xxx-DV-BE-A_2x20_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-120-02-xxx-DV-BE-LC_2x20_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-120-02-xxx-DV-BE_2x20_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-120-02-xxx-DV-LC_2x20_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-120-02-xxx-DV_2x20_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-121-02-xxx-DV-A_2x21_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-121-02-xxx-DV-BE-A_2x21_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-121-02-xxx-DV-BE-LC_2x21_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-121-02-xxx-DV-BE_2x21_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-121-02-xxx-DV-LC_2x21_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-121-02-xxx-DV_2x21_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-122-02-xxx-DV-A_2x22_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-122-02-xxx-DV-BE-A_2x22_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-122-02-xxx-DV-BE-LC_2x22_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-122-02-xxx-DV-BE_2x22_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-122-02-xxx-DV-LC_2x22_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-122-02-xxx-DV_2x22_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-123-02-xxx-DV-A_2x23_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-123-02-xxx-DV-BE-A_2x23_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-123-02-xxx-DV-BE-LC_2x23_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-123-02-xxx-DV-BE_2x23_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-123-02-xxx-DV-LC_2x23_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-123-02-xxx-DV_2x23_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-124-02-xxx-DV-A_2x24_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-124-02-xxx-DV-BE-A_2x24_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-124-02-xxx-DV-BE-LC_2x24_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-124-02-xxx-DV-BE_2x24_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-124-02-xxx-DV-LC_2x24_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-124-02-xxx-DV_2x24_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-125-02-xxx-DV-A_2x25_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-125-02-xxx-DV-BE-A_2x25_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-125-02-xxx-DV-BE-LC_2x25_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-125-02-xxx-DV-BE_2x25_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-125-02-xxx-DV-LC_2x25_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-125-02-xxx-DV_2x25_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-126-02-xxx-DV-A_2x26_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-126-02-xxx-DV-BE-A_2x26_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-126-02-xxx-DV-BE-LC_2x26_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-126-02-xxx-DV-BE_2x26_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-126-02-xxx-DV-LC_2x26_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-126-02-xxx-DV_2x26_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-127-02-xxx-DV-A_2x27_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-127-02-xxx-DV-BE-A_2x27_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-127-02-xxx-DV-BE-LC_2x27_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-127-02-xxx-DV-BE_2x27_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-127-02-xxx-DV-LC_2x27_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-127-02-xxx-DV_2x27_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-128-02-xxx-DV-A_2x28_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-128-02-xxx-DV-BE-A_2x28_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-128-02-xxx-DV-BE-LC_2x28_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-128-02-xxx-DV-BE_2x28_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-128-02-xxx-DV-LC_2x28_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-128-02-xxx-DV_2x28_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-129-02-xxx-DV-A_2x29_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-129-02-xxx-DV-BE-A_2x29_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-129-02-xxx-DV-BE-LC_2x29_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-129-02-xxx-DV-BE_2x29_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-129-02-xxx-DV-LC_2x29_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-129-02-xxx-DV_2x29_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-130-02-xxx-DV-A_2x30_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-130-02-xxx-DV-BE-A_2x30_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-130-02-xxx-DV-BE-LC_2x30_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-130-02-xxx-DV-BE_2x30_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-130-02-xxx-DV-LC_2x30_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-130-02-xxx-DV_2x30_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-131-02-xxx-DV-A_2x31_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-131-02-xxx-DV-BE-A_2x31_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-131-02-xxx-DV-BE-LC_2x31_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-131-02-xxx-DV-BE_2x31_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-131-02-xxx-DV-LC_2x31_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-131-02-xxx-DV_2x31_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-132-02-xxx-DV-A_2x32_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-132-02-xxx-DV-BE-A_2x32_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-132-02-xxx-DV-BE-LC_2x32_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-132-02-xxx-DV-BE_2x32_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-132-02-xxx-DV-LC_2x32_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-132-02-xxx-DV_2x32_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-133-02-xxx-DV-A_2x33_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-133-02-xxx-DV-BE-A_2x33_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-133-02-xxx-DV-BE-LC_2x33_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-133-02-xxx-DV-BE_2x33_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-133-02-xxx-DV-LC_2x33_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-133-02-xxx-DV_2x33_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-134-02-xxx-DV-A_2x34_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-134-02-xxx-DV-BE-A_2x34_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-134-02-xxx-DV-BE-LC_2x34_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-134-02-xxx-DV-BE_2x34_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-134-02-xxx-DV-LC_2x34_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-134-02-xxx-DV_2x34_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-135-02-xxx-DV-A_2x35_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-135-02-xxx-DV-BE-A_2x35_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-135-02-xxx-DV-BE-LC_2x35_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-135-02-xxx-DV-BE_2x35_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-135-02-xxx-DV-LC_2x35_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-135-02-xxx-DV_2x35_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-136-02-xxx-DV-A_2x36_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-136-02-xxx-DV-BE-A_2x36_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-136-02-xxx-DV-BE-LC_2x36_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-136-02-xxx-DV-BE_2x36_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-136-02-xxx-DV-LC_2x36_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-136-02-xxx-DV_2x36_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-137-02-xxx-DV-A_2x37_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-137-02-xxx-DV-BE-A_2x37_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-137-02-xxx-DV-BE-LC_2x37_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-137-02-xxx-DV-BE_2x37_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-137-02-xxx-DV-LC_2x37_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-137-02-xxx-DV_2x37_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-138-02-xxx-DV-A_2x38_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-138-02-xxx-DV-BE-A_2x38_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-138-02-xxx-DV-BE-LC_2x38_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-138-02-xxx-DV-BE_2x38_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-138-02-xxx-DV-LC_2x38_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-138-02-xxx-DV_2x38_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-139-02-xxx-DV-A_2x39_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-139-02-xxx-DV-BE-A_2x39_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-139-02-xxx-DV-BE-LC_2x39_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-139-02-xxx-DV-BE_2x39_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-139-02-xxx-DV-LC_2x39_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-139-02-xxx-DV_2x39_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-140-02-xxx-DV-A_2x40_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-140-02-xxx-DV-BE-A_2x40_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-140-02-xxx-DV-BE-LC_2x40_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-140-02-xxx-DV-BE_2x40_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-140-02-xxx-DV-LC_2x40_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-140-02-xxx-DV_2x40_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-141-02-xxx-DV-A_2x41_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-141-02-xxx-DV-BE-A_2x41_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-141-02-xxx-DV-BE-LC_2x41_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-141-02-xxx-DV-BE_2x41_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-141-02-xxx-DV-LC_2x41_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-141-02-xxx-DV_2x41_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-142-02-xxx-DV-A_2x42_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-142-02-xxx-DV-BE-A_2x42_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-142-02-xxx-DV-BE-LC_2x42_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-142-02-xxx-DV-BE_2x42_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-142-02-xxx-DV-LC_2x42_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-142-02-xxx-DV_2x42_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-143-02-xxx-DV-A_2x43_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-143-02-xxx-DV-BE-A_2x43_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-143-02-xxx-DV-BE-LC_2x43_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-143-02-xxx-DV-BE_2x43_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-143-02-xxx-DV-LC_2x43_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-143-02-xxx-DV_2x43_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-144-02-xxx-DV-A_2x44_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-144-02-xxx-DV-BE-A_2x44_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-144-02-xxx-DV-BE-LC_2x44_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-144-02-xxx-DV-BE_2x44_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-144-02-xxx-DV-LC_2x44_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-144-02-xxx-DV_2x44_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-145-02-xxx-DV-A_2x45_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-145-02-xxx-DV-BE-A_2x45_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-145-02-xxx-DV-BE-LC_2x45_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-145-02-xxx-DV-BE_2x45_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-145-02-xxx-DV-LC_2x45_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-145-02-xxx-DV_2x45_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-146-02-xxx-DV-A_2x46_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-146-02-xxx-DV-BE-A_2x46_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-146-02-xxx-DV-BE-LC_2x46_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-146-02-xxx-DV-BE_2x46_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-146-02-xxx-DV-LC_2x46_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-146-02-xxx-DV_2x46_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-147-02-xxx-DV-A_2x47_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-147-02-xxx-DV-BE-A_2x47_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-147-02-xxx-DV-BE-LC_2x47_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-147-02-xxx-DV-BE_2x47_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-147-02-xxx-DV-LC_2x47_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-147-02-xxx-DV_2x47_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-148-02-xxx-DV-A_2x48_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-148-02-xxx-DV-BE-A_2x48_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-148-02-xxx-DV-BE-LC_2x48_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-148-02-xxx-DV-BE_2x48_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-148-02-xxx-DV-LC_2x48_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-148-02-xxx-DV_2x48_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-149-02-xxx-DV-A_2x49_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-149-02-xxx-DV-BE-A_2x49_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-149-02-xxx-DV-BE-LC_2x49_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-149-02-xxx-DV-BE_2x49_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-149-02-xxx-DV-LC_2x49_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-149-02-xxx-DV_2x49_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-150-02-xxx-DV-A_2x50_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-150-02-xxx-DV-BE-A_2x50_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-150-02-xxx-DV-BE-LC_2x50_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-150-02-xxx-DV-BE_2x50_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-150-02-xxx-DV-LC_2x50_P2.54mm_Horizontal +Connector_Samtec_HLE_SMD:Samtec_HLE-150-02-xxx-DV_2x50_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-104-02-xx-DV-PE-LC_2x04_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-104-02-xx-DV-PE_2x04_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-104-02-xx-DV-TE_2x04_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-105-02-xx-DV-PE-LC_2x05_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-105-02-xx-DV-PE_2x05_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-105-02-xx-DV-TE_2x05_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-106-02-xx-DV-PE-LC_2x06_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-106-02-xx-DV-PE_2x06_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-106-02-xx-DV-TE_2x06_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-107-02-xx-DV-PE-LC_2x07_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-107-02-xx-DV-PE_2x07_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-107-02-xx-DV-TE_2x07_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-108-02-xx-DV-PE-LC_2x08_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-108-02-xx-DV-PE_2x08_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-108-02-xx-DV-TE_2x08_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-109-02-xx-DV-PE-LC_2x09_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-109-02-xx-DV-PE_2x09_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-109-02-xx-DV-TE_2x09_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-110-02-xx-DV-PE-LC_2x10_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-110-02-xx-DV-PE_2x10_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-110-02-xx-DV-TE_2x10_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-111-02-xx-DV-PE-LC_2x11_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-111-02-xx-DV-PE_2x11_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-111-02-xx-DV-TE_2x11_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-112-02-xx-DV-PE-LC_2x12_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-112-02-xx-DV-PE_2x12_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-112-02-xx-DV-TE_2x12_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-113-02-xx-DV-PE-LC_2x13_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-113-02-xx-DV-PE_2x13_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-113-02-xx-DV-TE_2x13_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-114-02-xx-DV-PE-LC_2x14_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-114-02-xx-DV-PE_2x14_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-114-02-xx-DV-TE_2x14_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-115-02-xx-DV-PE-LC_2x15_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-115-02-xx-DV-PE_2x15_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-115-02-xx-DV-TE_2x15_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-116-02-xx-DV-PE-LC_2x16_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-116-02-xx-DV-PE_2x16_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-116-02-xx-DV-TE_2x16_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-117-02-xx-DV-PE-LC_2x17_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-117-02-xx-DV-PE_2x17_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-117-02-xx-DV-TE_2x17_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-118-02-xx-DV-PE-LC_2x18_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-118-02-xx-DV-PE_2x18_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-118-02-xx-DV-TE_2x18_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-119-02-xx-DV-PE-LC_2x19_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-119-02-xx-DV-PE_2x19_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-119-02-xx-DV-TE_2x19_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-120-02-xx-DV-PE-LC_2x20_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-120-02-xx-DV-PE_2x20_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-120-02-xx-DV-TE_2x20_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-121-02-xx-DV-PE-LC_2x21_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-121-02-xx-DV-PE_2x21_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-121-02-xx-DV-TE_2x21_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-122-02-xx-DV-PE-LC_2x22_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-122-02-xx-DV-PE_2x22_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-122-02-xx-DV-TE_2x22_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-123-02-xx-DV-PE-LC_2x23_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-123-02-xx-DV-PE_2x23_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-123-02-xx-DV-TE_2x23_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-124-02-xx-DV-PE-LC_2x24_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-124-02-xx-DV-PE_2x24_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-124-02-xx-DV-TE_2x24_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-125-02-xx-DV-PE-LC_2x25_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-125-02-xx-DV-PE_2x25_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-125-02-xx-DV-TE_2x25_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-126-02-xx-DV-PE-LC_2x26_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-126-02-xx-DV-PE_2x26_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-126-02-xx-DV-TE_2x26_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-127-02-xx-DV-PE-LC_2x27_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-127-02-xx-DV-PE_2x27_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-127-02-xx-DV-TE_2x27_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-128-02-xx-DV-PE-LC_2x28_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-128-02-xx-DV-PE_2x28_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-128-02-xx-DV-TE_2x28_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-129-02-xx-DV-PE-LC_2x29_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-129-02-xx-DV-PE_2x29_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-129-02-xx-DV-TE_2x29_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-130-02-xx-DV-PE-LC_2x30_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-130-02-xx-DV-PE_2x30_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-130-02-xx-DV-TE_2x30_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-131-02-xx-DV-PE-LC_2x31_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-131-02-xx-DV-PE_2x31_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-131-02-xx-DV-TE_2x31_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-132-02-xx-DV-PE-LC_2x32_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-132-02-xx-DV-PE_2x32_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-132-02-xx-DV-TE_2x32_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-133-02-xx-DV-PE-LC_2x33_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-133-02-xx-DV-PE_2x33_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-133-02-xx-DV-TE_2x33_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-134-02-xx-DV-PE-LC_2x34_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-134-02-xx-DV-PE_2x34_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-134-02-xx-DV-TE_2x34_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-135-02-xx-DV-PE-LC_2x35_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-135-02-xx-DV-PE_2x35_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-135-02-xx-DV-TE_2x35_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-136-02-xx-DV-PE-LC_2x36_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-136-02-xx-DV-PE_2x36_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-136-02-xx-DV-TE_2x36_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-137-02-xx-DV-PE-LC_2x37_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-137-02-xx-DV-PE_2x37_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-137-02-xx-DV-TE_2x37_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-138-02-xx-DV-PE-LC_2x38_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-138-02-xx-DV-PE_2x38_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-138-02-xx-DV-TE_2x38_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-139-02-xx-DV-PE-LC_2x39_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-139-02-xx-DV-PE_2x39_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-139-02-xx-DV-TE_2x39_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-140-02-xx-DV-PE-LC_2x40_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-140-02-xx-DV-PE_2x40_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-140-02-xx-DV-TE_2x40_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-141-02-xx-DV-PE-LC_2x41_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-141-02-xx-DV-PE_2x41_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-141-02-xx-DV-TE_2x41_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-142-02-xx-DV-PE-LC_2x42_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-142-02-xx-DV-PE_2x42_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-142-02-xx-DV-TE_2x42_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-143-02-xx-DV-PE-LC_2x43_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-143-02-xx-DV-PE_2x43_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-143-02-xx-DV-TE_2x43_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-144-02-xx-DV-PE-LC_2x44_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-144-02-xx-DV-PE_2x44_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-144-02-xx-DV-TE_2x44_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-145-02-xx-DV-PE-LC_2x45_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-145-02-xx-DV-PE_2x45_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-145-02-xx-DV-TE_2x45_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-146-02-xx-DV-PE-LC_2x46_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-146-02-xx-DV-PE_2x46_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-146-02-xx-DV-TE_2x46_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-147-02-xx-DV-PE-LC_2x47_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-147-02-xx-DV-PE_2x47_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-147-02-xx-DV-TE_2x47_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-148-02-xx-DV-PE-LC_2x48_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-148-02-xx-DV-PE_2x48_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-148-02-xx-DV-TE_2x48_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-149-02-xx-DV-PE-LC_2x49_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-149-02-xx-DV-PE_2x49_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-149-02-xx-DV-TE_2x49_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-150-02-xx-DV-PE-LC_2x50_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-150-02-xx-DV-PE_2x50_P2.54mm_Horizontal +Connector_Samtec_HLE_THT:Samtec_HLE-150-02-xx-DV-TE_2x50_P2.54mm_Horizontal +Connector_Samtec_HPM_THT:Samtec_HPM-01-01-x-S_Straight_1x01_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-01-05-x-S_Straight_1x01_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-02-01-x-S_Straight_1x02_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-02-05-x-S_Straight_1x02_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-03-01-x-S_Straight_1x03_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-03-05-x-S_Straight_1x03_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-04-01-x-S_Straight_1x04_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-04-05-x-S_Straight_1x04_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-05-01-x-S_Straight_1x05_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-05-05-x-S_Straight_1x05_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-06-01-x-S_Straight_1x06_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-06-05-x-S_Straight_1x06_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-07-01-x-S_Straight_1x07_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-07-05-x-S_Straight_1x07_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-08-01-x-S_Straight_1x08_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-08-05-x-S_Straight_1x08_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-09-01-x-S_Straight_1x09_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-09-05-x-S_Straight_1x09_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-10-01-x-S_Straight_1x10_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-10-05-x-S_Straight_1x10_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-11-01-x-S_Straight_1x11_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-11-05-x-S_Straight_1x11_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-12-01-x-S_Straight_1x12_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-12-05-x-S_Straight_1x12_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-13-01-x-S_Straight_1x13_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-13-05-x-S_Straight_1x13_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-14-01-x-S_Straight_1x14_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-14-05-x-S_Straight_1x14_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-15-01-x-S_Straight_1x15_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-15-05-x-S_Straight_1x15_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-16-01-x-S_Straight_1x16_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-16-05-x-S_Straight_1x16_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-17-01-x-S_Straight_1x17_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-17-05-x-S_Straight_1x17_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-18-01-x-S_Straight_1x18_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-18-05-x-S_Straight_1x18_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-19-01-x-S_Straight_1x19_Pitch5.08mm +Connector_Samtec_HPM_THT:Samtec_HPM-19-05-x-S_Straight_1x19_Pitch5.08mm +Connector_Samtec_HSEC8:Samtec_HSEC8-109-01-X-DV-A-BL_2x09_P0.8mm_Pol04_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-109-01-X-DV-A-WT_2x09_P0.8mm_Pol04_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-109-X-X-DV-BL_2x09_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-109-X-X-DV_2x09_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-109-X-X-DV_2x09_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-110-01-X-DV-A-BL_2x10_P0.8mm_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-110-01-X-DV-A-WT_2x10_P0.8mm_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-110-01-X-DV-A_2x10_P0.8mm_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-110-01-X-DV_2x10_P0.8mm_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-110-03-X-DV-A-WT_2x10_P0.8mm_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-110-03-X-DV-A_2x10_P0.8mm_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-110-03-X-DV_2x10_P0.8mm_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-110-X-X-DV-BL_2x10_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-110-X-X-DV_2x10_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-110-X-X-DV_2x10_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-01-X-DV-A-BL_2x100_P0.8mm_Pol32_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-01-X-DV-A-WT_2x100_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-01-X-DV-A_2x100_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-01-X-DV_2x100_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-03-X-DV-A-WT_2x100_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-03-X-DV-A_2x100_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-03-X-DV_2x100_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-X-X-DV-BL_2x100_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-X-X-DV_2x100_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-1100-X-X-DV_2x100_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-113-01-X-DV-A-BL_2x13_P0.8mm_Pol06_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-113-01-X-DV-A-WT_2x13_P0.8mm_Pol06_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-113-01-X-DV-A_2x13_P0.8mm_Pol06_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-113-01-X-DV_2x13_P0.8mm_Pol06_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-113-X-X-DV-BL_2x13_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-113-X-X-DV_2x13_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-113-X-X-DV_2x13_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-120-01-X-DV-A-BL_2x20_P0.8mm_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-120-01-X-DV-A-WT_2x20_P0.8mm_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-120-01-X-DV-A_2x20_P0.8mm_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-120-01-X-DV_2x20_P0.8mm_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-120-03-X-DV-A-WT_2x20_P0.8mm_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-120-03-X-DV-A_2x20_P0.8mm_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-120-03-X-DV_2x20_P0.8mm_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-120-X-X-DV-BL_2x20_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-120-X-X-DV_2x20_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-120-X-X-DV_2x20_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-125-01-X-DV-A-BL_2x25_P0.8mm_Pol06_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-125-01-X-DV-A-WT_2x25_P0.8mm_Pol06_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-125-01-X-DV-A_2x25_P0.8mm_Pol06_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-125-01-X-DV_2x25_P0.8mm_Pol06_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-125-X-X-DV-BL_2x25_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-125-X-X-DV_2x25_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-125-X-X-DV_2x25_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-130-01-X-DV-A-BL_2x30_P0.8mm_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-130-01-X-DV-A-WT_2x30_P0.8mm_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-130-01-X-DV-A_2x30_P0.8mm_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-130-01-X-DV_2x30_P0.8mm_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-130-03-X-DV-A-WT_2x30_P0.8mm_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-130-03-X-DV-A_2x30_P0.8mm_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-130-03-X-DV_2x30_P0.8mm_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-130-X-X-DV-BL_2x30_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-130-X-X-DV_2x30_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-130-X-X-DV_2x30_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-137-01-X-DV-A-BL_2x37_P0.8mm_Pol21_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-137-01-X-DV-A-WT_2x37_P0.8mm_Pol21_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-137-01-X-DV-A_2x37_P0.8mm_Pol21_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-137-01-X-DV_2x37_P0.8mm_Pol21_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-137-X-X-DV-BL_2x37_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-137-X-X-DV_2x37_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-137-X-X-DV_2x37_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-140-01-X-DV-A-BL_2x40_P0.8mm_Pol22_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-140-01-X-DV-A-WT_2x40_P0.8mm_Pol22_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-140-01-X-DV-A_2x40_P0.8mm_Pol22_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-140-01-X-DV_2x40_P0.8mm_Pol22_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-140-03-X-DV-A-WT_2x40_P0.8mm_Pol22_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-140-03-X-DV-A_2x40_P0.8mm_Pol22_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-140-03-X-DV_2x40_P0.8mm_Pol22_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-140-X-X-DV-BL_2x40_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-140-X-X-DV_2x40_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-140-X-X-DV_2x40_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-149-01-X-DV-A-BL_2x49_P0.8mm_Pol27_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-149-01-X-DV-A-WT_2x49_P0.8mm_Pol27_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-149-01-X-DV-A_2x49_P0.8mm_Pol27_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-149-01-X-DV_2x49_P0.8mm_Pol27_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-149-X-X-DV-BL_2x49_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-149-X-X-DV_2x49_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-149-X-X-DV_2x49_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-150-01-X-DV-A-BL_2x50_P0.8mm_Pol27_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-150-01-X-DV-A-WT_2x50_P0.8mm_Pol27_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-150-01-X-DV-A_2x50_P0.8mm_Pol27_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-150-01-X-DV_2x50_P0.8mm_Pol27_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-150-03-X-DV-A-WT_2x50_P0.8mm_Pol27_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-150-03-X-DV-A_2x50_P0.8mm_Pol27_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-150-03-X-DV_2x50_P0.8mm_Pol27_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-150-X-X-DV-BL_2x50_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-150-X-X-DV_2x50_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-150-X-X-DV_2x50_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-160-01-X-DV-A-BL_2x60_P0.8mm_Pol32_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-160-01-X-DV-A-WT_2x60_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-160-01-X-DV-A_2x60_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-160-01-X-DV_2x60_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-160-03-X-DV-A-WT_2x60_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-160-03-X-DV-A_2x60_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-160-03-X-DV_2x60_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-160-X-X-DV-BL_2x60_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-160-X-X-DV_2x60_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-160-X-X-DV_2x60_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-170-01-X-DV-A-BL_2x70_P0.8mm_Pol32_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-170-01-X-DV-A-WT_2x70_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-170-01-X-DV-A_2x70_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-170-01-X-DV_2x70_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-170-03-X-DV-A-WT_2x70_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-170-03-X-DV-A_2x70_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-170-03-X-DV_2x70_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-170-X-X-DV-BL_2x70_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-170-X-X-DV_2x70_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-170-X-X-DV_2x70_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-180-01-X-DV-A-BL_2x80_P0.8mm_Pol32_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-180-01-X-DV-A-WT_2x80_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-180-01-X-DV-A_2x80_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-180-01-X-DV_2x80_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-180-03-X-DV-A-WT_2x80_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-180-03-X-DV-A_2x80_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-180-03-X-DV_2x80_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-180-X-X-DV-BL_2x80_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-180-X-X-DV_2x80_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-180-X-X-DV_2x80_P0.8mm_Wing_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-190-01-X-DV-A-BL_2x90_P0.8mm_Pol32_Socket_WeldTabs_BoardLocks +Connector_Samtec_HSEC8:Samtec_HSEC8-190-01-X-DV-A-WT_2x90_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-190-01-X-DV-A_2x90_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-190-01-X-DV_2x90_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-190-03-X-DV-A-WT_2x90_P0.8mm_Pol32_Socket_WeldTabs +Connector_Samtec_HSEC8:Samtec_HSEC8-190-03-X-DV-A_2x90_P0.8mm_Pol32_Socket_AlignmentPins +Connector_Samtec_HSEC8:Samtec_HSEC8-190-03-X-DV_2x90_P0.8mm_Pol32_Socket +Connector_Samtec_HSEC8:Samtec_HSEC8-190-X-X-DV-BL_2x90_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-190-X-X-DV_2x90_P0.8mm_Edge +Connector_Samtec_HSEC8:Samtec_HSEC8-190-X-X-DV_2x90_P0.8mm_Wing_Edge +Connector_Samtec_MicroMate:Samtec_T1M-02-X-S-RA_1x02-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-02-X-S-V_1x02-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-02-X-SH-L_1x02-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-02-X-SV-L_1x02-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-03-X-S-RA_1x03-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-03-X-S-V_1x03-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-03-X-SH-L_1x03-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-03-X-SV-L_1x03-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-04-X-S-RA_1x04-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-04-X-S-V_1x04-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-04-X-SH-L_1x04-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-04-X-SV-L_1x04-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-05-X-S-RA_1x05-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-05-X-S-V_1x05-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-05-X-SH-L_1x05-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-05-X-SV-L_1x05-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-06-X-S-RA_1x06-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-06-X-S-V_1x06-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-06-X-SH-L_1x06-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-06-X-SV-L_1x06-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-07-X-S-RA_1x07-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-07-X-S-V_1x07-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-07-X-SH-L_1x07-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-07-X-SV-L_1x07-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-08-X-S-RA_1x08-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-08-X-S-V_1x08-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-08-X-SH-L_1x08-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-08-X-SV-L_1x08-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-09-X-S-RA_1x09-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-09-X-S-V_1x09-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-09-X-SH-L_1x09-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-09-X-SV-L_1x09-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-10-X-S-RA_1x10-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-10-X-S-V_1x10-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-10-X-SH-L_1x10-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-10-X-SV-L_1x10-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-11-X-S-RA_1x11-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-11-X-S-V_1x11-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-11-X-SH-L_1x11-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-11-X-SV-L_1x11-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-12-X-S-RA_1x12-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-12-X-S-V_1x12-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-12-X-SH-L_1x12-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-12-X-SV-L_1x12-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-13-X-S-RA_1x13-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-13-X-S-V_1x13-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-13-X-SH-L_1x13-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-13-X-SV-L_1x13-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-14-X-S-RA_1x14-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-14-X-S-V_1x14-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-14-X-SH-L_1x14-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-14-X-SV-L_1x14-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-15-X-S-RA_1x15-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-15-X-S-V_1x15-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-15-X-SH-L_1x15-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-15-X-SV-L_1x15-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-16-X-S-RA_1x16-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-16-X-S-V_1x16-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-16-X-SH-L_1x16-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-16-X-SV-L_1x16-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-17-X-S-RA_1x17-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-17-X-S-V_1x17-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-17-X-SH-L_1x17-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-17-X-SV-L_1x17-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-18-X-S-RA_1x18-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-18-X-S-V_1x18-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-18-X-SH-L_1x18-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-18-X-SV-L_1x18-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-19-X-S-RA_1x19-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-19-X-S-V_1x19-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-19-X-SH-L_1x19-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-19-X-SV-L_1x19-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroMate:Samtec_T1M-20-X-S-RA_1x20-1MP_P1.0mm_Terminal_Horizontal +Connector_Samtec_MicroMate:Samtec_T1M-20-X-S-V_1x20-1MP_P1.0mm_Terminal_Vertical +Connector_Samtec_MicroMate:Samtec_T1M-20-X-SH-L_1x20-1MP_P1.0mm_Terminal_Horizontal_Latch +Connector_Samtec_MicroMate:Samtec_T1M-20-X-SV-L_1x20-1MP_P1.0mm_Terminal_Vertical_Latch +Connector_Samtec_MicroPower:Samtec_UMPS-02-XX.X-X-V-S-W_1x02-1MP_P2.0mm_Socket_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPS-02-XX.X-X-V-S_1x02_P2.0mm_Socket +Connector_Samtec_MicroPower:Samtec_UMPS-03-XX.X-X-V-S-W_1x03-1MP_P2.0mm_Socket_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPS-03-XX.X-X-V-S_1x03_P2.0mm_Socket +Connector_Samtec_MicroPower:Samtec_UMPS-04-XX.X-X-V-S-W_1x04-1MP_P2.0mm_Socket_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPS-04-XX.X-X-V-S_1x04_P2.0mm_Socket +Connector_Samtec_MicroPower:Samtec_UMPS-05-XX.X-X-V-S-W_1x05-1MP_P2.0mm_Socket_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPS-05-XX.X-X-V-S_1x05_P2.0mm_Socket +Connector_Samtec_MicroPower:Samtec_UMPS-06-XX.X-X-V-S-W_1x06-1MP_P2.0mm_Socket_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPS-06-XX.X-X-V-S_1x06_P2.0mm_Socket +Connector_Samtec_MicroPower:Samtec_UMPS-07-XX.X-X-V-S-W_1x07-1MP_P2.0mm_Socket_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPS-07-XX.X-X-V-S_1x07_P2.0mm_Socket +Connector_Samtec_MicroPower:Samtec_UMPS-08-XX.X-X-V-S-W_1x08-1MP_P2.0mm_Socket_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPS-08-XX.X-X-V-S_1x08_P2.0mm_Socket +Connector_Samtec_MicroPower:Samtec_UMPS-09-XX.X-X-V-S-W_1x09-1MP_P2.0mm_Socket_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPS-09-XX.X-X-V-S_1x09_P2.0mm_Socket +Connector_Samtec_MicroPower:Samtec_UMPS-10-XX.X-X-V-S-W_1x10-1MP_P2.0mm_Socket_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPS-10-XX.X-X-V-S_1x10_P2.0mm_Socket +Connector_Samtec_MicroPower:Samtec_UMPT-02-XX.X-X-V-S-W_1x02-1MP_P2.0mm_Terminal_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPT-02-XX.X-X-V-S_1x02_P2.0mm_Terminal +Connector_Samtec_MicroPower:Samtec_UMPT-03-XX.X-X-V-S-W_1x03-1MP_P2.0mm_Terminal_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPT-03-XX.X-X-V-S_1x03_P2.0mm_Terminal +Connector_Samtec_MicroPower:Samtec_UMPT-04-XX.X-X-V-S-W_1x04-1MP_P2.0mm_Terminal_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPT-04-XX.X-X-V-S_1x04_P2.0mm_Terminal +Connector_Samtec_MicroPower:Samtec_UMPT-05-XX.X-X-V-S-W_1x05-1MP_P2.0mm_Terminal_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPT-05-XX.X-X-V-S_1x05_P2.0mm_Terminal +Connector_Samtec_MicroPower:Samtec_UMPT-06-XX.X-X-V-S-W_1x06-1MP_P2.0mm_Terminal_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPT-06-XX.X-X-V-S_1x06_P2.0mm_Terminal +Connector_Samtec_MicroPower:Samtec_UMPT-07-XX.X-X-V-S-W_1x07-1MP_P2.0mm_Terminal_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPT-07-XX.X-X-V-S_1x07_P2.0mm_Terminal +Connector_Samtec_MicroPower:Samtec_UMPT-08-XX.X-X-V-S-W_1x08-1MP_P2.0mm_Terminal_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPT-08-XX.X-X-V-S_1x08_P2.0mm_Terminal +Connector_Samtec_MicroPower:Samtec_UMPT-09-XX.X-X-V-S-W_1x09-1MP_P2.0mm_Terminal_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPT-09-XX.X-X-V-S_1x09_P2.0mm_Terminal +Connector_Samtec_MicroPower:Samtec_UMPT-10-XX.X-X-V-S-W_1x10-1MP_P2.0mm_Terminal_WeldTab +Connector_Samtec_MicroPower:Samtec_UMPT-10-XX.X-X-V-S_1x10_P2.0mm_Terminal +Connector_SATA_SAS:SAS-mini_TEConnectivity_1888174_Vertical +Connector_SATA_SAS:SATA_Amphenol_10029364-001LF_Horizontal +Connector_Stocko:Stocko_MKS_1651-6-0-202_1x2_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1652-6-0-202_1x2_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1653-6-0-303_1x3_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1654-6-0-404_1x4_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1655-6-0-505_1x5_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1656-6-0-606_1x6_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1657-6-0-707_1x7_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1658-6-0-808_1x8_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1659-6-0-909_1x9_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1660-6-0-1010_1x10_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1661-6-0-1111_1x11_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1662-6-0-1212_1x12_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1663-6-0-1313_1x13_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1664-6-0-1414_1x14_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1665-6-0-1515_1x15_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1666-6-0-1616_1x16_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1667-6-0-1717_1x17_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1668-6-0-1818_1x18_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1669-6-0-1919_1x19_P2.50mm_Vertical +Connector_Stocko:Stocko_MKS_1670-6-0-2020_1x20_P2.50mm_Vertical +Connector_TE-Connectivity:TE_1-826576-3_1x13_P3.96mm_Vertical +Connector_TE-Connectivity:TE_1-826576-5_1x15_P3.96mm_Vertical +Connector_TE-Connectivity:TE_1-826576-6_1x16_P3.96mm_Vertical +Connector_TE-Connectivity:TE_1-826576-7_1x17_P3.96mm_Vertical +Connector_TE-Connectivity:TE_1-826576-8_1x18_P3.96mm_Vertical +Connector_TE-Connectivity:TE_2-826576-0_1x20_P3.96mm_Vertical +Connector_TE-Connectivity:TE_2834006-1_1x01_P4.0mm_Horizontal +Connector_TE-Connectivity:TE_2834006-2_1x02_P4.0mm_Horizontal +Connector_TE-Connectivity:TE_2834006-3_1x03_P4.0mm_Horizontal +Connector_TE-Connectivity:TE_2834006-4_1x04_P4.0mm_Horizontal +Connector_TE-Connectivity:TE_2834006-5_1x05_P4.0mm_Horizontal +Connector_TE-Connectivity:TE_3-826576-6_1x36_P3.96mm_Vertical +Connector_TE-Connectivity:TE_440054-2_1x02_P2.00mm_Vertical +Connector_TE-Connectivity:TE_440055-2_1x02_P2.00mm_Horizontal +Connector_TE-Connectivity:TE_5767171-1_2x19_P0.635mm_Vertical +Connector_TE-Connectivity:TE_826576-2_1x02_P3.96mm_Vertical +Connector_TE-Connectivity:TE_826576-3_1x03_P3.96mm_Vertical +Connector_TE-Connectivity:TE_826576-5_1x05_P3.96mm_Vertical +Connector_TE-Connectivity:TE_826576-6_1x06_P3.96mm_Vertical +Connector_TE-Connectivity:TE_826576-7_1x07_P3.96mm_Vertical +Connector_TE-Connectivity:TE_826576-8_1x08_P3.96mm_Vertical +Connector_TE-Connectivity:TE_826576-9_1x09_P3.96mm_Vertical +Connector_TE-Connectivity:TE_AMPSEAL_1-776087-x_3Rows_23_P0.4mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770182-x_3x03_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770186-x_3x04_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770190-x_3x05_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770621-x_2x06_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770858-x_2x05_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770866-x_1x02_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770870-x_1x03_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770874-x_2x02_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770875-x_2x03_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770966-x_1x02_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770967-x_1x03_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770968-x_2x02_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770969-x_2x03_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770970-x_2x04_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770971-x_2x05_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770972-x_2x06_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770973-x_2x07_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-770974-x_2x08_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794067-x_2x07_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794068-x_2x08_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794069-x_2x09_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794070-x_2x10_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794071-x_2x11_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794072-x_2x12_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794073-x_2x04_P4.14mm_Vertical +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794105-x_2x09_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794106-x_2x10_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794107-x_2x11_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794108-x_2x12_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_1-794374-x_1x01_P4.14mm_Horizontal +Connector_TE-Connectivity:TE_MATE-N-LOK_350211-1_1x04_P5.08mm_Vertical +Connector_TE-Connectivity:TE_Micro-MaTch_1-215079-0_2x05_P1.27mm_Vertical +Connector_TE-Connectivity:TE_Micro-MaTch_1-215079-2_2x06_P1.27mm_Vertical +Connector_TE-Connectivity:TE_Micro-MaTch_1-215079-4_2x07_P1.27mm_Vertical +Connector_TE-Connectivity:TE_Micro-MaTch_1-215079-6_2x08_P1.27mm_Vertical +Connector_TE-Connectivity:TE_Micro-MaTch_1-215079-8_2x09_P1.27mm_Vertical +Connector_TE-Connectivity:TE_Micro-MaTch_2-215079-0_2x10_P1.27mm_Vertical +Connector_TE-Connectivity:TE_Micro-MaTch_215079-4_2x02_P1.27mm_Vertical +Connector_TE-Connectivity:TE_Micro-MaTch_215079-6_2x03_P1.27mm_Vertical +Connector_TE-Connectivity:TE_Micro-MaTch_215079-8_2x04_P1.27mm_Vertical +Connector_TE-Connectivity:TE_T4041037031-000_M8_03_Socket_Straight +Connector_TE-Connectivity:TE_T4041037041-000_M8_04_Socket_Straight +Connector_USB:USB3_A_Molex_48393-001 +Connector_USB:USB3_A_Molex_48406-0001_Horizontal_Stacked +Connector_USB:USB3_A_Plug_Wuerth_692112030100_Horizontal +Connector_USB:USB3_A_Receptacle_Wuerth_692122030100 +Connector_USB:USB3_Micro-B_Connfly_DS1104-01 +Connector_USB:USB_A_CNCTech_1001-011-01101_Horizontal +Connector_USB:USB_A_Connfly_DS1095 +Connector_USB:USB_A_Connfly_DS1098_Horizontal +Connector_USB:USB_A_CUI_UJ2-ADH-TH_Horizontal_Stacked +Connector_USB:USB_A_Kycon_KUSBX-AS1N-B_Horizontal +Connector_USB:USB_A_Molex_105057_Vertical +Connector_USB:USB_A_Molex_48037-2200_Horizontal +Connector_USB:USB_A_Molex_67643_Horizontal +Connector_USB:USB_A_Receptacle_GCT_USB1046 +Connector_USB:USB_A_Receptacle_XKB_U231-091N-4BLRA00-S +Connector_USB:USB_A_Stewart_SS-52100-001_Horizontal +Connector_USB:USB_A_TE_292303-7_Horizontal +Connector_USB:USB_A_Wuerth_614004134726_Horizontal +Connector_USB:USB_A_Wuerth_61400826021_Horizontal_Stacked +Connector_USB:USB_B_Amphenol_MUSB-D511_Vertical_Rugged +Connector_USB:USB_B_Lumberg_2411_02_Horizontal +Connector_USB:USB_B_OST_USB-B1HSxx_Horizontal +Connector_USB:USB_B_TE_5787834_Vertical +Connector_USB:USB_C_Plug_JAE_DX07P024AJ1 +Connector_USB:USB_C_Plug_Molex_105444 +Connector_USB:USB_C_Plug_ShenzhenJingTuoJin_918-118A2021Y40002_Vertical +Connector_USB:USB_C_Receptacle_Amphenol_12401548E4-2A +Connector_USB:USB_C_Receptacle_Amphenol_12401548E4-2A_CircularHoles +Connector_USB:USB_C_Receptacle_Amphenol_12401610E4-2A +Connector_USB:USB_C_Receptacle_Amphenol_12401610E4-2A_CircularHoles +Connector_USB:USB_C_Receptacle_Amphenol_12401948E412A +Connector_USB:USB_C_Receptacle_Amphenol_124019772112A +Connector_USB:USB_C_Receptacle_CNCTech_C-ARA1-AK51X +Connector_USB:USB_C_Receptacle_G-Switch_GT-USB-7010ASV +Connector_USB:USB_C_Receptacle_G-Switch_GT-USB-7025 +Connector_USB:USB_C_Receptacle_G-Switch_GT-USB-7051x +Connector_USB:USB_C_Receptacle_GCT_USB4085 +Connector_USB:USB_C_Receptacle_GCT_USB4105-xx-A_16P_TopMnt_Horizontal +Connector_USB:USB_C_Receptacle_GCT_USB4110 +Connector_USB:USB_C_Receptacle_GCT_USB4115-03-C +Connector_USB:USB_C_Receptacle_GCT_USB4125-xx-x-0190_6P_TopMnt_Horizontal +Connector_USB:USB_C_Receptacle_GCT_USB4125-xx-x_6P_TopMnt_Horizontal +Connector_USB:USB_C_Receptacle_GCT_USB4135-GF-A_6P_TopMnt_Horizontal +Connector_USB:USB_C_Receptacle_HCTL_HC-TYPE-C-16P-01A +Connector_USB:USB_C_Receptacle_HRO_TYPE-C-31-M-12 +Connector_USB:USB_C_Receptacle_HRO_TYPE-C-31-M-17 +Connector_USB:USB_C_Receptacle_JAE_DX07S016JA1R1500 +Connector_USB:USB_C_Receptacle_JAE_DX07S024WJ1R350 +Connector_USB:USB_C_Receptacle_JAE_DX07S024WJ3R400 +Connector_USB:USB_C_Receptacle_Molex_105450-0101 +Connector_USB:USB_C_Receptacle_Palconn_UTC16-G +Connector_USB:USB_C_Receptacle_XKB_U262-16XN-4BVC11 +Connector_USB:USB_Micro-AB_Molex_47590-0001 +Connector_USB:USB_Micro-B_Amphenol_10103594-0001LF_Horizontal +Connector_USB:USB_Micro-B_Amphenol_10104110_Horizontal +Connector_USB:USB_Micro-B_Amphenol_10118193-0001LF_Horizontal +Connector_USB:USB_Micro-B_Amphenol_10118193-0002LF_Horizontal +Connector_USB:USB_Micro-B_Amphenol_10118194-0001LF_Horizontal +Connector_USB:USB_Micro-B_Amphenol_10118194_Horizontal +Connector_USB:USB_Micro-B_GCT_USB3076-30-A +Connector_USB:USB_Micro-B_Molex-105017-0001 +Connector_USB:USB_Micro-B_Molex-105133-0001 +Connector_USB:USB_Micro-B_Molex-105133-0031 +Connector_USB:USB_Micro-B_Molex_47346-0001 +Connector_USB:USB_Micro-B_Technik_TWP-4002D-H3 +Connector_USB:USB_Micro-B_Wuerth_614105150721_Vertical +Connector_USB:USB_Micro-B_Wuerth_614105150721_Vertical_CircularHoles +Connector_USB:USB_Micro-B_Wuerth_629105150521 +Connector_USB:USB_Micro-B_Wuerth_629105150521_CircularHoles +Connector_USB:USB_Micro-B_XKB_U254-051T-4BH83-F1S +Connector_USB:USB_Mini-B_AdamTech_MUSB-B5-S-VT-TSMT-1_SMD_Vertical +Connector_USB:USB_Mini-B_Lumberg_2486_01_Horizontal +Connector_USB:USB_Mini-B_Tensility_54-00023_Vertical +Connector_USB:USB_Mini-B_Tensility_54-00023_Vertical_CircularHoles +Connector_USB:USB_Mini-B_Wuerth_65100516121_Horizontal +Connector_Video:DVI-D_Molex_74320-4004_Horizontal +Connector_Video:DVI-I_Molex_74320-1004_Horizontal +Connector_Video:HDMI_A_Amphenol_10029449-x01xLF_Horizontal +Connector_Video:HDMI_A_Contact_Technology_HDMI-19APL2_Horizontal +Connector_Video:HDMI_A_Kycon_KDMIX-SL1-NS-WS-B15_VerticalRightAngle +Connector_Video:HDMI_A_Molex_208658-1001_Horizontal +Connector_Video:HDMI_Micro-D_Molex_46765-0x01 +Connector_Video:HDMI_Micro-D_Molex_46765-1x01 +Connector_Video:HDMI_Micro-D_Molex_46765-2x0x +Connector_Wago:Wago_734-132_1x02_P3.50mm_Vertical +Connector_Wago:Wago_734-133_1x03_P3.50mm_Vertical +Connector_Wago:Wago_734-134_1x04_P3.50mm_Vertical +Connector_Wago:Wago_734-135_1x05_P3.50mm_Vertical +Connector_Wago:Wago_734-136_1x06_P3.50mm_Vertical +Connector_Wago:Wago_734-137_1x07_P3.50mm_Vertical +Connector_Wago:Wago_734-138_1x08_P3.50mm_Vertical +Connector_Wago:Wago_734-139_1x09_P3.50mm_Vertical +Connector_Wago:Wago_734-140_1x10_P3.50mm_Vertical +Connector_Wago:Wago_734-141_1x11_P3.50mm_Vertical +Connector_Wago:Wago_734-142_1x12_P3.50mm_Vertical +Connector_Wago:Wago_734-143_1x13_P3.50mm_Vertical +Connector_Wago:Wago_734-144_1x14_P3.50mm_Vertical +Connector_Wago:Wago_734-146_1x16_P3.50mm_Vertical +Connector_Wago:Wago_734-148_1x18_P3.50mm_Vertical +Connector_Wago:Wago_734-150_1x20_P3.50mm_Vertical +Connector_Wago:Wago_734-154_1x24_P3.50mm_Vertical +Connector_Wago:Wago_734-162_1x02_P3.50mm_Horizontal +Connector_Wago:Wago_734-163_1x03_P3.50mm_Horizontal +Connector_Wago:Wago_734-164_1x04_P3.50mm_Horizontal +Connector_Wago:Wago_734-165_1x05_P3.50mm_Horizontal +Connector_Wago:Wago_734-166_1x06_P3.50mm_Horizontal +Connector_Wago:Wago_734-167_1x07_P3.50mm_Horizontal +Connector_Wago:Wago_734-168_1x08_P3.50mm_Horizontal +Connector_Wago:Wago_734-169_1x09_P3.50mm_Horizontal +Connector_Wago:Wago_734-170_1x10_P3.50mm_Horizontal +Connector_Wago:Wago_734-171_1x11_P3.50mm_Horizontal +Connector_Wago:Wago_734-172_1x12_P3.50mm_Horizontal +Connector_Wago:Wago_734-173_1x13_P3.50mm_Horizontal +Connector_Wago:Wago_734-174_1x14_P3.50mm_Horizontal +Connector_Wago:Wago_734-176_1x16_P3.50mm_Horizontal +Connector_Wago:Wago_734-178_1x18_P3.50mm_Horizontal +Connector_Wago:Wago_734-180_1x20_P3.50mm_Horizontal +Connector_Wago:Wago_734-184_1x24_P3.50mm_Horizontal +Connector_Wire:SolderWire-0.127sqmm_1x01_D0.48mm_OD1mm +Connector_Wire:SolderWire-0.127sqmm_1x01_D0.48mm_OD1mm_Relief +Connector_Wire:SolderWire-0.127sqmm_1x01_D0.48mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.127sqmm_1x02_P3.7mm_D0.48mm_OD1mm +Connector_Wire:SolderWire-0.127sqmm_1x02_P3.7mm_D0.48mm_OD1mm_Relief +Connector_Wire:SolderWire-0.127sqmm_1x02_P3.7mm_D0.48mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.127sqmm_1x03_P3.7mm_D0.48mm_OD1mm +Connector_Wire:SolderWire-0.127sqmm_1x03_P3.7mm_D0.48mm_OD1mm_Relief +Connector_Wire:SolderWire-0.127sqmm_1x03_P3.7mm_D0.48mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.127sqmm_1x04_P3.7mm_D0.48mm_OD1mm +Connector_Wire:SolderWire-0.127sqmm_1x04_P3.7mm_D0.48mm_OD1mm_Relief +Connector_Wire:SolderWire-0.127sqmm_1x04_P3.7mm_D0.48mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.127sqmm_1x05_P3.7mm_D0.48mm_OD1mm +Connector_Wire:SolderWire-0.127sqmm_1x05_P3.7mm_D0.48mm_OD1mm_Relief +Connector_Wire:SolderWire-0.127sqmm_1x05_P3.7mm_D0.48mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.127sqmm_1x06_P3.7mm_D0.48mm_OD1mm +Connector_Wire:SolderWire-0.127sqmm_1x06_P3.7mm_D0.48mm_OD1mm_Relief +Connector_Wire:SolderWire-0.127sqmm_1x06_P3.7mm_D0.48mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.15sqmm_1x01_D0.5mm_OD1.5mm +Connector_Wire:SolderWire-0.15sqmm_1x01_D0.5mm_OD1.5mm_Relief +Connector_Wire:SolderWire-0.15sqmm_1x01_D0.5mm_OD1.5mm_Relief2x +Connector_Wire:SolderWire-0.15sqmm_1x02_P4mm_D0.5mm_OD1.5mm +Connector_Wire:SolderWire-0.15sqmm_1x02_P4mm_D0.5mm_OD1.5mm_Relief +Connector_Wire:SolderWire-0.15sqmm_1x02_P4mm_D0.5mm_OD1.5mm_Relief2x +Connector_Wire:SolderWire-0.15sqmm_1x03_P4mm_D0.5mm_OD1.5mm +Connector_Wire:SolderWire-0.15sqmm_1x03_P4mm_D0.5mm_OD1.5mm_Relief +Connector_Wire:SolderWire-0.15sqmm_1x03_P4mm_D0.5mm_OD1.5mm_Relief2x +Connector_Wire:SolderWire-0.15sqmm_1x04_P4mm_D0.5mm_OD1.5mm +Connector_Wire:SolderWire-0.15sqmm_1x04_P4mm_D0.5mm_OD1.5mm_Relief +Connector_Wire:SolderWire-0.15sqmm_1x04_P4mm_D0.5mm_OD1.5mm_Relief2x +Connector_Wire:SolderWire-0.15sqmm_1x05_P4mm_D0.5mm_OD1.5mm +Connector_Wire:SolderWire-0.15sqmm_1x05_P4mm_D0.5mm_OD1.5mm_Relief +Connector_Wire:SolderWire-0.15sqmm_1x05_P4mm_D0.5mm_OD1.5mm_Relief2x +Connector_Wire:SolderWire-0.15sqmm_1x06_P4mm_D0.5mm_OD1.5mm +Connector_Wire:SolderWire-0.15sqmm_1x06_P4mm_D0.5mm_OD1.5mm_Relief +Connector_Wire:SolderWire-0.15sqmm_1x06_P4mm_D0.5mm_OD1.5mm_Relief2x +Connector_Wire:SolderWire-0.1sqmm_1x01_D0.4mm_OD1mm +Connector_Wire:SolderWire-0.1sqmm_1x01_D0.4mm_OD1mm_Relief +Connector_Wire:SolderWire-0.1sqmm_1x01_D0.4mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.1sqmm_1x02_P3.6mm_D0.4mm_OD1mm +Connector_Wire:SolderWire-0.1sqmm_1x02_P3.6mm_D0.4mm_OD1mm_Relief +Connector_Wire:SolderWire-0.1sqmm_1x02_P3.6mm_D0.4mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.1sqmm_1x03_P3.6mm_D0.4mm_OD1mm +Connector_Wire:SolderWire-0.1sqmm_1x03_P3.6mm_D0.4mm_OD1mm_Relief +Connector_Wire:SolderWire-0.1sqmm_1x03_P3.6mm_D0.4mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.1sqmm_1x04_P3.6mm_D0.4mm_OD1mm +Connector_Wire:SolderWire-0.1sqmm_1x04_P3.6mm_D0.4mm_OD1mm_Relief +Connector_Wire:SolderWire-0.1sqmm_1x04_P3.6mm_D0.4mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.1sqmm_1x05_P3.6mm_D0.4mm_OD1mm +Connector_Wire:SolderWire-0.1sqmm_1x05_P3.6mm_D0.4mm_OD1mm_Relief +Connector_Wire:SolderWire-0.1sqmm_1x05_P3.6mm_D0.4mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.1sqmm_1x06_P3.6mm_D0.4mm_OD1mm +Connector_Wire:SolderWire-0.1sqmm_1x06_P3.6mm_D0.4mm_OD1mm_Relief +Connector_Wire:SolderWire-0.1sqmm_1x06_P3.6mm_D0.4mm_OD1mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x01_D0.65mm_OD1.7mm +Connector_Wire:SolderWire-0.25sqmm_1x01_D0.65mm_OD1.7mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x01_D0.65mm_OD1.7mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x01_D0.65mm_OD2mm +Connector_Wire:SolderWire-0.25sqmm_1x01_D0.65mm_OD2mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x01_D0.65mm_OD2mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x02_P4.2mm_D0.65mm_OD1.7mm +Connector_Wire:SolderWire-0.25sqmm_1x02_P4.2mm_D0.65mm_OD1.7mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x02_P4.2mm_D0.65mm_OD1.7mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x02_P4.5mm_D0.65mm_OD2mm +Connector_Wire:SolderWire-0.25sqmm_1x02_P4.5mm_D0.65mm_OD2mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x02_P4.5mm_D0.65mm_OD2mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x03_P4.2mm_D0.65mm_OD1.7mm +Connector_Wire:SolderWire-0.25sqmm_1x03_P4.2mm_D0.65mm_OD1.7mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x03_P4.2mm_D0.65mm_OD1.7mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x03_P4.5mm_D0.65mm_OD2mm +Connector_Wire:SolderWire-0.25sqmm_1x03_P4.5mm_D0.65mm_OD2mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x03_P4.5mm_D0.65mm_OD2mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x04_P4.2mm_D0.65mm_OD1.7mm +Connector_Wire:SolderWire-0.25sqmm_1x04_P4.2mm_D0.65mm_OD1.7mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x04_P4.2mm_D0.65mm_OD1.7mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x04_P4.5mm_D0.65mm_OD2mm +Connector_Wire:SolderWire-0.25sqmm_1x04_P4.5mm_D0.65mm_OD2mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x04_P4.5mm_D0.65mm_OD2mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x05_P4.2mm_D0.65mm_OD1.7mm +Connector_Wire:SolderWire-0.25sqmm_1x05_P4.2mm_D0.65mm_OD1.7mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x05_P4.2mm_D0.65mm_OD1.7mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x05_P4.5mm_D0.65mm_OD2mm +Connector_Wire:SolderWire-0.25sqmm_1x05_P4.5mm_D0.65mm_OD2mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x05_P4.5mm_D0.65mm_OD2mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x06_P4.2mm_D0.65mm_OD1.7mm +Connector_Wire:SolderWire-0.25sqmm_1x06_P4.2mm_D0.65mm_OD1.7mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x06_P4.2mm_D0.65mm_OD1.7mm_Relief2x +Connector_Wire:SolderWire-0.25sqmm_1x06_P4.5mm_D0.65mm_OD2mm +Connector_Wire:SolderWire-0.25sqmm_1x06_P4.5mm_D0.65mm_OD2mm_Relief +Connector_Wire:SolderWire-0.25sqmm_1x06_P4.5mm_D0.65mm_OD2mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x01_D0.9mm_OD2.1mm +Connector_Wire:SolderWire-0.5sqmm_1x01_D0.9mm_OD2.1mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x01_D0.9mm_OD2.1mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x01_D0.9mm_OD2.3mm +Connector_Wire:SolderWire-0.5sqmm_1x01_D0.9mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x01_D0.9mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x02_P4.6mm_D0.9mm_OD2.1mm +Connector_Wire:SolderWire-0.5sqmm_1x02_P4.6mm_D0.9mm_OD2.1mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x02_P4.6mm_D0.9mm_OD2.1mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x02_P4.8mm_D0.9mm_OD2.3mm +Connector_Wire:SolderWire-0.5sqmm_1x02_P4.8mm_D0.9mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x02_P4.8mm_D0.9mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x03_P4.6mm_D0.9mm_OD2.1mm +Connector_Wire:SolderWire-0.5sqmm_1x03_P4.6mm_D0.9mm_OD2.1mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x03_P4.6mm_D0.9mm_OD2.1mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x03_P4.8mm_D0.9mm_OD2.3mm +Connector_Wire:SolderWire-0.5sqmm_1x03_P4.8mm_D0.9mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x03_P4.8mm_D0.9mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x04_P4.6mm_D0.9mm_OD2.1mm +Connector_Wire:SolderWire-0.5sqmm_1x04_P4.6mm_D0.9mm_OD2.1mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x04_P4.6mm_D0.9mm_OD2.1mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x04_P4.8mm_D0.9mm_OD2.3mm +Connector_Wire:SolderWire-0.5sqmm_1x04_P4.8mm_D0.9mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x04_P4.8mm_D0.9mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x05_P4.6mm_D0.9mm_OD2.1mm +Connector_Wire:SolderWire-0.5sqmm_1x05_P4.6mm_D0.9mm_OD2.1mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x05_P4.6mm_D0.9mm_OD2.1mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x05_P4.8mm_D0.9mm_OD2.3mm +Connector_Wire:SolderWire-0.5sqmm_1x05_P4.8mm_D0.9mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x05_P4.8mm_D0.9mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x06_P4.6mm_D0.9mm_OD2.1mm +Connector_Wire:SolderWire-0.5sqmm_1x06_P4.6mm_D0.9mm_OD2.1mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x06_P4.6mm_D0.9mm_OD2.1mm_Relief2x +Connector_Wire:SolderWire-0.5sqmm_1x06_P4.8mm_D0.9mm_OD2.3mm +Connector_Wire:SolderWire-0.5sqmm_1x06_P4.8mm_D0.9mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.5sqmm_1x06_P4.8mm_D0.9mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x01_D1.25mm_OD2.3mm +Connector_Wire:SolderWire-0.75sqmm_1x01_D1.25mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x01_D1.25mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x01_D1.25mm_OD3.5mm +Connector_Wire:SolderWire-0.75sqmm_1x01_D1.25mm_OD3.5mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x01_D1.25mm_OD3.5mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x02_P4.8mm_D1.25mm_OD2.3mm +Connector_Wire:SolderWire-0.75sqmm_1x02_P4.8mm_D1.25mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x02_P4.8mm_D1.25mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x02_P7mm_D1.25mm_OD3.5mm +Connector_Wire:SolderWire-0.75sqmm_1x02_P7mm_D1.25mm_OD3.5mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x02_P7mm_D1.25mm_OD3.5mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x03_P4.8mm_D1.25mm_OD2.3mm +Connector_Wire:SolderWire-0.75sqmm_1x03_P4.8mm_D1.25mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x03_P4.8mm_D1.25mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x03_P7mm_D1.25mm_OD3.5mm +Connector_Wire:SolderWire-0.75sqmm_1x03_P7mm_D1.25mm_OD3.5mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x03_P7mm_D1.25mm_OD3.5mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x04_P4.8mm_D1.25mm_OD2.3mm +Connector_Wire:SolderWire-0.75sqmm_1x04_P4.8mm_D1.25mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x04_P4.8mm_D1.25mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x04_P7mm_D1.25mm_OD3.5mm +Connector_Wire:SolderWire-0.75sqmm_1x04_P7mm_D1.25mm_OD3.5mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x04_P7mm_D1.25mm_OD3.5mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x05_P4.8mm_D1.25mm_OD2.3mm +Connector_Wire:SolderWire-0.75sqmm_1x05_P4.8mm_D1.25mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x05_P4.8mm_D1.25mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x05_P7mm_D1.25mm_OD3.5mm +Connector_Wire:SolderWire-0.75sqmm_1x05_P7mm_D1.25mm_OD3.5mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x05_P7mm_D1.25mm_OD3.5mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x06_P4.8mm_D1.25mm_OD2.3mm +Connector_Wire:SolderWire-0.75sqmm_1x06_P4.8mm_D1.25mm_OD2.3mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x06_P4.8mm_D1.25mm_OD2.3mm_Relief2x +Connector_Wire:SolderWire-0.75sqmm_1x06_P7mm_D1.25mm_OD3.5mm +Connector_Wire:SolderWire-0.75sqmm_1x06_P7mm_D1.25mm_OD3.5mm_Relief +Connector_Wire:SolderWire-0.75sqmm_1x06_P7mm_D1.25mm_OD3.5mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x01_D1.7mm_OD3.9mm +Connector_Wire:SolderWire-1.5sqmm_1x01_D1.7mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x01_D1.7mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x01_D1.7mm_OD3mm +Connector_Wire:SolderWire-1.5sqmm_1x01_D1.7mm_OD3mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x01_D1.7mm_OD3mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x02_P6mm_D1.7mm_OD3mm +Connector_Wire:SolderWire-1.5sqmm_1x02_P6mm_D1.7mm_OD3mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x02_P6mm_D1.7mm_OD3mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x02_P7.8mm_D1.7mm_OD3.9mm +Connector_Wire:SolderWire-1.5sqmm_1x02_P7.8mm_D1.7mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x02_P7.8mm_D1.7mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x03_P6mm_D1.7mm_OD3mm +Connector_Wire:SolderWire-1.5sqmm_1x03_P6mm_D1.7mm_OD3mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x03_P6mm_D1.7mm_OD3mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x03_P7.8mm_D1.7mm_OD3.9mm +Connector_Wire:SolderWire-1.5sqmm_1x03_P7.8mm_D1.7mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x03_P7.8mm_D1.7mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x04_P6mm_D1.7mm_OD3mm +Connector_Wire:SolderWire-1.5sqmm_1x04_P6mm_D1.7mm_OD3mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x04_P6mm_D1.7mm_OD3mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x04_P7.8mm_D1.7mm_OD3.9mm +Connector_Wire:SolderWire-1.5sqmm_1x04_P7.8mm_D1.7mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x04_P7.8mm_D1.7mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x05_P6mm_D1.7mm_OD3mm +Connector_Wire:SolderWire-1.5sqmm_1x05_P6mm_D1.7mm_OD3mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x05_P6mm_D1.7mm_OD3mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x05_P7.8mm_D1.7mm_OD3.9mm +Connector_Wire:SolderWire-1.5sqmm_1x05_P7.8mm_D1.7mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x05_P7.8mm_D1.7mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x06_P6mm_D1.7mm_OD3mm +Connector_Wire:SolderWire-1.5sqmm_1x06_P6mm_D1.7mm_OD3mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x06_P6mm_D1.7mm_OD3mm_Relief2x +Connector_Wire:SolderWire-1.5sqmm_1x06_P7.8mm_D1.7mm_OD3.9mm +Connector_Wire:SolderWire-1.5sqmm_1x06_P7.8mm_D1.7mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1.5sqmm_1x06_P7.8mm_D1.7mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x01_D1.4mm_OD2.7mm +Connector_Wire:SolderWire-1sqmm_1x01_D1.4mm_OD2.7mm_Relief +Connector_Wire:SolderWire-1sqmm_1x01_D1.4mm_OD2.7mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x01_D1.4mm_OD3.9mm +Connector_Wire:SolderWire-1sqmm_1x01_D1.4mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1sqmm_1x01_D1.4mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x02_P5.4mm_D1.4mm_OD2.7mm +Connector_Wire:SolderWire-1sqmm_1x02_P5.4mm_D1.4mm_OD2.7mm_Relief +Connector_Wire:SolderWire-1sqmm_1x02_P5.4mm_D1.4mm_OD2.7mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x02_P7.8mm_D1.4mm_OD3.9mm +Connector_Wire:SolderWire-1sqmm_1x02_P7.8mm_D1.4mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1sqmm_1x02_P7.8mm_D1.4mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x03_P5.4mm_D1.4mm_OD2.7mm +Connector_Wire:SolderWire-1sqmm_1x03_P5.4mm_D1.4mm_OD2.7mm_Relief +Connector_Wire:SolderWire-1sqmm_1x03_P5.4mm_D1.4mm_OD2.7mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x03_P7.8mm_D1.4mm_OD3.9mm +Connector_Wire:SolderWire-1sqmm_1x03_P7.8mm_D1.4mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1sqmm_1x03_P7.8mm_D1.4mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x04_P5.4mm_D1.4mm_OD2.7mm +Connector_Wire:SolderWire-1sqmm_1x04_P5.4mm_D1.4mm_OD2.7mm_Relief +Connector_Wire:SolderWire-1sqmm_1x04_P5.4mm_D1.4mm_OD2.7mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x04_P7.8mm_D1.4mm_OD3.9mm +Connector_Wire:SolderWire-1sqmm_1x04_P7.8mm_D1.4mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1sqmm_1x04_P7.8mm_D1.4mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x05_P5.4mm_D1.4mm_OD2.7mm +Connector_Wire:SolderWire-1sqmm_1x05_P5.4mm_D1.4mm_OD2.7mm_Relief +Connector_Wire:SolderWire-1sqmm_1x05_P5.4mm_D1.4mm_OD2.7mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x05_P7.8mm_D1.4mm_OD3.9mm +Connector_Wire:SolderWire-1sqmm_1x05_P7.8mm_D1.4mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1sqmm_1x05_P7.8mm_D1.4mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x06_P5.4mm_D1.4mm_OD2.7mm +Connector_Wire:SolderWire-1sqmm_1x06_P5.4mm_D1.4mm_OD2.7mm_Relief +Connector_Wire:SolderWire-1sqmm_1x06_P5.4mm_D1.4mm_OD2.7mm_Relief2x +Connector_Wire:SolderWire-1sqmm_1x06_P7.8mm_D1.4mm_OD3.9mm +Connector_Wire:SolderWire-1sqmm_1x06_P7.8mm_D1.4mm_OD3.9mm_Relief +Connector_Wire:SolderWire-1sqmm_1x06_P7.8mm_D1.4mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x01_D2.4mm_OD3.6mm +Connector_Wire:SolderWire-2.5sqmm_1x01_D2.4mm_OD3.6mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x01_D2.4mm_OD3.6mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x01_D2.4mm_OD4.4mm +Connector_Wire:SolderWire-2.5sqmm_1x01_D2.4mm_OD4.4mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x01_D2.4mm_OD4.4mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x02_P7.2mm_D2.4mm_OD3.6mm +Connector_Wire:SolderWire-2.5sqmm_1x02_P7.2mm_D2.4mm_OD3.6mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x02_P7.2mm_D2.4mm_OD3.6mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x02_P8.8mm_D2.4mm_OD4.4mm +Connector_Wire:SolderWire-2.5sqmm_1x02_P8.8mm_D2.4mm_OD4.4mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x02_P8.8mm_D2.4mm_OD4.4mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x03_P7.2mm_D2.4mm_OD3.6mm +Connector_Wire:SolderWire-2.5sqmm_1x03_P7.2mm_D2.4mm_OD3.6mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x03_P7.2mm_D2.4mm_OD3.6mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x03_P8.8mm_D2.4mm_OD4.4mm +Connector_Wire:SolderWire-2.5sqmm_1x03_P8.8mm_D2.4mm_OD4.4mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x03_P8.8mm_D2.4mm_OD4.4mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x04_P7.2mm_D2.4mm_OD3.6mm +Connector_Wire:SolderWire-2.5sqmm_1x04_P7.2mm_D2.4mm_OD3.6mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x04_P7.2mm_D2.4mm_OD3.6mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x04_P8.8mm_D2.4mm_OD4.4mm +Connector_Wire:SolderWire-2.5sqmm_1x04_P8.8mm_D2.4mm_OD4.4mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x04_P8.8mm_D2.4mm_OD4.4mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x05_P7.2mm_D2.4mm_OD3.6mm +Connector_Wire:SolderWire-2.5sqmm_1x05_P7.2mm_D2.4mm_OD3.6mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x05_P7.2mm_D2.4mm_OD3.6mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x05_P8.8mm_D2.4mm_OD4.4mm +Connector_Wire:SolderWire-2.5sqmm_1x05_P8.8mm_D2.4mm_OD4.4mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x05_P8.8mm_D2.4mm_OD4.4mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x06_P7.2mm_D2.4mm_OD3.6mm +Connector_Wire:SolderWire-2.5sqmm_1x06_P7.2mm_D2.4mm_OD3.6mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x06_P7.2mm_D2.4mm_OD3.6mm_Relief2x +Connector_Wire:SolderWire-2.5sqmm_1x06_P8.8mm_D2.4mm_OD4.4mm +Connector_Wire:SolderWire-2.5sqmm_1x06_P8.8mm_D2.4mm_OD4.4mm_Relief +Connector_Wire:SolderWire-2.5sqmm_1x06_P8.8mm_D2.4mm_OD4.4mm_Relief2x +Connector_Wire:SolderWire-2sqmm_1x01_D2mm_OD3.9mm +Connector_Wire:SolderWire-2sqmm_1x01_D2mm_OD3.9mm_Relief +Connector_Wire:SolderWire-2sqmm_1x01_D2mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-2sqmm_1x02_P7.8mm_D2mm_OD3.9mm +Connector_Wire:SolderWire-2sqmm_1x02_P7.8mm_D2mm_OD3.9mm_Relief +Connector_Wire:SolderWire-2sqmm_1x02_P7.8mm_D2mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-2sqmm_1x03_P7.8mm_D2mm_OD3.9mm +Connector_Wire:SolderWire-2sqmm_1x03_P7.8mm_D2mm_OD3.9mm_Relief +Connector_Wire:SolderWire-2sqmm_1x03_P7.8mm_D2mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-2sqmm_1x04_P7.8mm_D2mm_OD3.9mm +Connector_Wire:SolderWire-2sqmm_1x04_P7.8mm_D2mm_OD3.9mm_Relief +Connector_Wire:SolderWire-2sqmm_1x04_P7.8mm_D2mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-2sqmm_1x05_P7.8mm_D2mm_OD3.9mm +Connector_Wire:SolderWire-2sqmm_1x05_P7.8mm_D2mm_OD3.9mm_Relief +Connector_Wire:SolderWire-2sqmm_1x05_P7.8mm_D2mm_OD3.9mm_Relief2x +Connector_Wire:SolderWire-2sqmm_1x06_P7.8mm_D2mm_OD3.9mm +Connector_Wire:SolderWire-2sqmm_1x06_P7.8mm_D2mm_OD3.9mm_Relief +Connector_Wire:SolderWire-2sqmm_1x06_P7.8mm_D2mm_OD3.9mm_Relief2x +Connector_Wire:SolderWirePad_1x01_SMD_1x2mm +Connector_Wire:SolderWirePad_1x01_SMD_5x10mm +Connector_Wuerth:Wuerth_WR-PHD_610004243021_SMD_2x02_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610006243021_SMD_2x03_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610008243021_SMD_2x04_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610010243021_SMD_2x05_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610012243021_SMD_2x06_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610016243021_SMD_2x08_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610018243021_SMD_2x09_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610020243021_SMD_2x10_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610022243021_SMD_2x11_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610024243021_SMD_2x12_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610026243021_SMD_2x13_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610032243021_SMD_2x16_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_610034243021_SMD_2x17_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613004216921_Large_2x02_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61300425721_Standard_2x02_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613006216921_Large_2x03_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61300625721_Standard_2x03_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613008216921_Large_2x04_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61300825721_Standard_2x04_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613010216921_Large_2x05_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61301025721_Standard_2x05_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613012216921_Large_2x06_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61301225721_Standard_2x06_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613016216921_Large_2x08_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61301625721_Standard_2x08_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613018216921_Large_2x09_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613020216921_Large_2x10_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61302025721_Standard_2x10_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613022216921_Large_2x11_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613024216921_Large_2x12_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61302425721_Standard_2x12_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613026216921_Large_2x13_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61302625721_Standard_2x13_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613032216921_Large_2x16_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61303225721_Standard_2x16_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_613034216921_Large_2x17_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-PHD_61303425721_Standard_2x17_P2.54mm_Vertical +Connector_Wuerth:Wuerth_WR-WTB_64800211622_1x02_P1.50mm_Vertical +Connector_Wuerth:Wuerth_WR-WTB_64800311622_1x03_P1.50mm_Vertical +Connector_Wuerth:Wuerth_WR-WTB_64800411622_1x04_P1.50mm_Vertical +Connector_Wuerth:Wuerth_WR-WTB_64800511622_1x05_P1.50mm_Vertical +Connector_Wuerth:Wuerth_WR-WTB_64800611622_1x06_P1.50mm_Vertical +Connector_Wuerth:Wuerth_WR-WTB_64800711622_1x07_P1.50mm_Vertical +Connector_Wuerth:Wuerth_WR-WTB_64800811622_1x08_P1.50mm_Vertical +Connector_Wuerth:Wuerth_WR-WTB_64800911622_1x09_P1.50mm_Vertical +Connector_Wuerth:Wuerth_WR-WTB_64801011622_1x10_P1.50mm_Vertical +Converter_ACDC:Converter_ACDC_CUI_PBO-3-Sxx_THT_Vertical +Converter_ACDC:Converter_ACDC_Hahn_HS-400xx_THT +Converter_ACDC:Converter_ACDC_Hi-Link_HLK-10Mxx +Converter_ACDC:Converter_ACDC_Hi-Link_HLK-12MxxA +Converter_ACDC:Converter_ACDC_Hi-Link_HLK-20Mxx +Converter_ACDC:Converter_ACDC_Hi-Link_HLK-2Mxx +Converter_ACDC:Converter_ACDC_Hi-Link_HLK-30Mxx +Converter_ACDC:Converter_ACDC_Hi-Link_HLK-5Mxx +Converter_ACDC:Converter_ACDC_Hi-Link_HLK-PMxx +Converter_ACDC:Converter_ACDC_MeanWell_IRM-02-xx_SMD +Converter_ACDC:Converter_ACDC_MeanWell_IRM-02-xx_THT +Converter_ACDC:Converter_ACDC_MeanWell_IRM-03-xx_SMD +Converter_ACDC:Converter_ACDC_MeanWell_IRM-03-xx_THT +Converter_ACDC:Converter_ACDC_MeanWell_IRM-05-xx_THT +Converter_ACDC:Converter_ACDC_MeanWell_IRM-10-xx_THT +Converter_ACDC:Converter_ACDC_MeanWell_IRM-20-xx_THT +Converter_ACDC:Converter_ACDC_MeanWell_IRM-60-xx_THT +Converter_ACDC:Converter_ACDC_MeanWell_MFM-10-xx_THT +Converter_ACDC:Converter_ACDC_MeanWell_MFM-15-xx_THT +Converter_ACDC:Converter_ACDC_Murata_BAC05SxxDC_THT +Converter_ACDC:Converter_ACDC_RECOM_RAC01-xxSGB_THT +Converter_ACDC:Converter_ACDC_RECOM_RAC04-xxSGx_THT +Converter_ACDC:Converter_ACDC_RECOM_RAC05-xxSK_THT +Converter_ACDC:Converter_ACDC_Recom_RAC20-xxDK_THT +Converter_ACDC:Converter_ACDC_Recom_RAC20-xxSK_THT +Converter_ACDC:Converter_ACDC_TRACO_TMF_051xx_THT +Converter_ACDC:Converter_ACDC_TRACO_TMF_101xx_THT +Converter_ACDC:Converter_ACDC_TRACO_TMF_201xx_THT +Converter_ACDC:Converter_ACDC_TRACO_TMF_301xx_THT +Converter_ACDC:Converter_ACDC_TRACO_TMG-15_THT +Converter_ACDC:Converter_ACDC_TRACO_TMLM-04_THT +Converter_ACDC:Converter_ACDC_TRACO_TMLM-05_THT +Converter_ACDC:Converter_ACDC_TRACO_TMLM-10-20_THT +Converter_ACDC:Converter_ACDC_TRACO_TPP-15-1xx-D_THT +Converter_ACDC:Converter_ACDC_Vigortronix_VTX-214-010-xxx_THT +Converter_ACDC:Converter_ACDC_Vigortronix_VTX-214-015-1xx_THT +Converter_ACDC:Converter_ACDC_ZETTLER_ZPI03Sxx00WC_THT +Converter_DCDC:Converter_DCDC_Artesyn_ATA_SMD +Converter_DCDC:Converter_DCDC_Bothhand_CFUDxxxx_THT +Converter_DCDC:Converter_DCDC_Bothhand_CFUSxxxxEH_THT +Converter_DCDC:Converter_DCDC_Bothhand_CFUSxxxx_THT +Converter_DCDC:Converter_DCDC_Cincon_EC5BExx_Dual_THT +Converter_DCDC:Converter_DCDC_Cincon_EC5BExx_Single_THT +Converter_DCDC:Converter_DCDC_Cincon_EC6Cxx_Dual-Triple_THT +Converter_DCDC:Converter_DCDC_Cincon_EC6Cxx_Single_THT +Converter_DCDC:Converter_DCDC_Cyntec_MUN12AD01-SH +Converter_DCDC:Converter_DCDC_Cyntec_MUN12AD03-SH +Converter_DCDC:Converter_DCDC_MeanWell_NID30_THT +Converter_DCDC:Converter_DCDC_MeanWell_NID60_THT +Converter_DCDC:Converter_DCDC_MeanWell_NSD10_THT +Converter_DCDC:Converter_DCDC_Murata_CRE1xxxxxx3C_THT +Converter_DCDC:Converter_DCDC_Murata_CRE1xxxxxxDC_THT +Converter_DCDC:Converter_DCDC_Murata_CRE1xxxxxxSC_THT +Converter_DCDC:Converter_DCDC_Murata_MEE1SxxxxSC_THT +Converter_DCDC:Converter_DCDC_Murata_MEE3SxxxxSC_THT +Converter_DCDC:Converter_DCDC_muRata_MEJ1DxxxxSC_THT +Converter_DCDC:Converter_DCDC_muRata_MEJ1SxxxxSC_THT +Converter_DCDC:Converter_DCDC_Murata_MGJ2DxxxxxxSC_THT +Converter_DCDC:Converter_DCDC_Murata_MGJ3 +Converter_DCDC:Converter_DCDC_Murata_MYRxP +Converter_DCDC:Converter_DCDC_Murata_NCS1SxxxxSC_THT +Converter_DCDC:Converter_DCDC_Murata_NMAxxxxDC_THT +Converter_DCDC:Converter_DCDC_Murata_NMAxxxxSC_THT +Converter_DCDC:Converter_DCDC_Murata_NXExSxxxxMC_SMD +Converter_DCDC:Converter_DCDC_Murata_OKI-78SR_Horizontal +Converter_DCDC:Converter_DCDC_Murata_OKI-78SR_Vertical +Converter_DCDC:Converter_DCDC_RECOM_R-78B-2.0_THT +Converter_DCDC:Converter_DCDC_RECOM_R-78E-0.5_THT +Converter_DCDC:Converter_DCDC_RECOM_R-78HB-0.5L_THT +Converter_DCDC:Converter_DCDC_RECOM_R-78HB-0.5_THT +Converter_DCDC:Converter_DCDC_RECOM_R-78S-0.1_THT +Converter_DCDC:Converter_DCDC_RECOM_R5xxxDA_THT +Converter_DCDC:Converter_DCDC_RECOM_R5xxxPA_THT +Converter_DCDC:Converter_DCDC_RECOM_RCD-24_THT +Converter_DCDC:Converter_DCDC_RECOM_RPA60-xxxxSFW +Converter_DCDC:Converter_DCDC_RECOM_RPMx.x-x.0 +Converter_DCDC:Converter_DCDC_Silvertel_Ag54xx +Converter_DCDC:Converter_DCDC_Silvertel_Ag5810 +Converter_DCDC:Converter_DCDC_Silvertel_Ag99xxLP_THT +Converter_DCDC:Converter_DCDC_TRACO_TBA1-xxxxE_Dual_THT +Converter_DCDC:Converter_DCDC_TRACO_TBA1-xxxxE_Single_THT +Converter_DCDC:Converter_DCDC_TRACO_TBA2-xxxx_Dual_THT +Converter_DCDC:Converter_DCDC_TRACO_TBA2-xxxx_Single_THT +Converter_DCDC:Converter_DCDC_TRACO_TDN_5-xxxxWISM_SMD +Converter_DCDC:Converter_DCDC_TRACO_TDN_5-xxxxWI_THT +Converter_DCDC:Converter_DCDC_TRACO_TDU1-xxxx_THT +Converter_DCDC:Converter_DCDC_TRACO_TEA1-xxxxE_THT +Converter_DCDC:Converter_DCDC_TRACO_TEA1-xxxxHI_THT +Converter_DCDC:Converter_DCDC_TRACO_TEA1-xxxx_THT +Converter_DCDC:Converter_DCDC_TRACO_TEC3-24xxUI_THT +Converter_DCDC:Converter_DCDC_TRACO_TEL12-xxxx_THT +Converter_DCDC:Converter_DCDC_TRACO_TEN10-110xxWIRH_THT +Converter_DCDC:Converter_DCDC_TRACO_TEN10-xxxx_Dual_THT +Converter_DCDC:Converter_DCDC_TRACO_TEN10-xxxx_Single_THT +Converter_DCDC:Converter_DCDC_TRACO_TEN10-xxxx_THT +Converter_DCDC:Converter_DCDC_TRACO_TEN20-110xxWIRH_THT +Converter_DCDC:Converter_DCDC_TRACO_TEN20-xxxx-N4_THT +Converter_DCDC:Converter_DCDC_TRACO_TEN20-xxxx_THT +Converter_DCDC:Converter_DCDC_TRACO_TEN40-110xxWIRH_THT +Converter_DCDC:Converter_DCDC_TRACO_THB10-xxxx_Dual_THT +Converter_DCDC:Converter_DCDC_TRACO_THB10-xxxx_Single_THT +Converter_DCDC:Converter_DCDC_TRACO_THD_15-xxxxWIN_THT +Converter_DCDC:Converter_DCDC_TRACO_THN30-xxxx_THT +Converter_DCDC:Converter_DCDC_TRACO_THR40-72xxWI_THT +Converter_DCDC:Converter_DCDC_TRACO_TMA-05xxD_12xxD_Dual_THT +Converter_DCDC:Converter_DCDC_TRACO_TMA-05xxS_12xxS_Single_THT +Converter_DCDC:Converter_DCDC_TRACO_TMA-15xxD_24xxD_Dual_THT +Converter_DCDC:Converter_DCDC_TRACO_TMA-15xxS_24xxS_Single_THT +Converter_DCDC:Converter_DCDC_TRACO_TME_03xxS_05xxS_12xxS_Single_THT +Converter_DCDC:Converter_DCDC_TRACO_TME_24xxS_Single_THT +Converter_DCDC:Converter_DCDC_TRACO_TMR-1-xxxx_Dual_THT +Converter_DCDC:Converter_DCDC_TRACO_TMR-1-xxxx_Single_THT +Converter_DCDC:Converter_DCDC_TRACO_TMR-1SM_SMD +Converter_DCDC:Converter_DCDC_TRACO_TMR-2xxxxWI_THT +Converter_DCDC:Converter_DCDC_TRACO_TMR-xxxx_THT +Converter_DCDC:Converter_DCDC_TRACO_TMR4-xxxxWI_THT +Converter_DCDC:Converter_DCDC_TRACO_TMU3-05xx_12xx_THT +Converter_DCDC:Converter_DCDC_TRACO_TMU3-24xx_THT +Converter_DCDC:Converter_DCDC_TRACO_TOS06-05SIL_THT +Converter_DCDC:Converter_DCDC_TRACO_TOS06-12SIL_THT +Converter_DCDC:Converter_DCDC_TRACO_TRA3-xxxx_THT +Converter_DCDC:Converter_DCDC_TRACO_TRI1-xxxx_THT +Converter_DCDC:Converter_DCDC_TRACO_TSR-1_THT +Converter_DCDC:Converter_DCDC_TRACO_TSR0.6-48xxWI_TSR0.6-48xxxWI_THT +Converter_DCDC:Converter_DCDC_TRACO_TSR1-xxxxE_THT +Converter_DCDC:Converter_DCDC_TRACO_TSR2-24xxN_TSR2-24xxxN_THT +Converter_DCDC:Converter_DCDC_TRACO_TSR2-xxxx_THT +Converter_DCDC:Converter_DCDC_XP_POWER-IA48xxD_THT +Converter_DCDC:Converter_DCDC_XP_POWER-IA48xxS_THT +Converter_DCDC:Converter_DCDC_XP_POWER-IAxxxxD_THT +Converter_DCDC:Converter_DCDC_XP_POWER-IAxxxxS_THT +Converter_DCDC:Converter_DCDC_XP_POWER-IHxxxxDH_THT +Converter_DCDC:Converter_DCDC_XP_POWER-IHxxxxD_THT +Converter_DCDC:Converter_DCDC_XP_POWER-IHxxxxSH_THT +Converter_DCDC:Converter_DCDC_XP_POWER-IHxxxxS_THT +Converter_DCDC:Converter_DCDC_XP_POWER-ISU02_SMD +Converter_DCDC:Converter_DCDC_XP_POWER-ITQxxxxS-H_THT +Converter_DCDC:Converter_DCDC_XP_POWER-ITXxxxxSA_THT +Converter_DCDC:Converter_DCDC_XP_POWER-ITxxxxxS_THT +Converter_DCDC:Converter_DCDC_XP_POWER_JTDxxxxxxx_THT +Converter_DCDC:Converter_DCDC_XP_POWER_JTExxxxDxx_THT +Crystal:Crystal_AT310_D3.0mm_L10.0mm_Horizontal +Crystal:Crystal_AT310_D3.0mm_L10.0mm_Horizontal_1EP_style1 +Crystal:Crystal_AT310_D3.0mm_L10.0mm_Horizontal_1EP_style2 +Crystal:Crystal_AT310_D3.0mm_L10.0mm_Vertical +Crystal:Crystal_C26-LF_D2.1mm_L6.5mm_Horizontal +Crystal:Crystal_C26-LF_D2.1mm_L6.5mm_Horizontal_1EP_style1 +Crystal:Crystal_C26-LF_D2.1mm_L6.5mm_Horizontal_1EP_style2 +Crystal:Crystal_C26-LF_D2.1mm_L6.5mm_Vertical +Crystal:Crystal_C38-LF_D3.0mm_L8.0mm_Horizontal +Crystal:Crystal_C38-LF_D3.0mm_L8.0mm_Horizontal_1EP_style1 +Crystal:Crystal_C38-LF_D3.0mm_L8.0mm_Horizontal_1EP_style2 +Crystal:Crystal_C38-LF_D3.0mm_L8.0mm_Vertical +Crystal:Crystal_DS10_D1.0mm_L4.3mm_Horizontal +Crystal:Crystal_DS10_D1.0mm_L4.3mm_Horizontal_1EP_style1 +Crystal:Crystal_DS10_D1.0mm_L4.3mm_Horizontal_1EP_style2 +Crystal:Crystal_DS10_D1.0mm_L4.3mm_Vertical +Crystal:Crystal_DS15_D1.5mm_L5.0mm_Horizontal +Crystal:Crystal_DS15_D1.5mm_L5.0mm_Horizontal_1EP_style1 +Crystal:Crystal_DS15_D1.5mm_L5.0mm_Horizontal_1EP_style2 +Crystal:Crystal_DS15_D1.5mm_L5.0mm_Vertical +Crystal:Crystal_DS26_D2.0mm_L6.0mm_Horizontal +Crystal:Crystal_DS26_D2.0mm_L6.0mm_Horizontal_1EP_style1 +Crystal:Crystal_DS26_D2.0mm_L6.0mm_Horizontal_1EP_style2 +Crystal:Crystal_DS26_D2.0mm_L6.0mm_Vertical +Crystal:Crystal_HC18-U_Horizontal +Crystal:Crystal_HC18-U_Horizontal_1EP_style1 +Crystal:Crystal_HC18-U_Horizontal_1EP_style2 +Crystal:Crystal_HC18-U_Vertical +Crystal:Crystal_HC33-U_Horizontal +Crystal:Crystal_HC33-U_Horizontal_1EP_style1 +Crystal:Crystal_HC33-U_Horizontal_1EP_style2 +Crystal:Crystal_HC33-U_Vertical +Crystal:Crystal_HC35-U +Crystal:Crystal_HC49-4H_Vertical +Crystal:Crystal_HC49-U-3Pin_Vertical +Crystal:Crystal_HC49-U_Horizontal +Crystal:Crystal_HC49-U_Horizontal_1EP_style1 +Crystal:Crystal_HC49-U_Horizontal_1EP_style2 +Crystal:Crystal_HC49-U_Vertical +Crystal:Crystal_HC50_Horizontal +Crystal:Crystal_HC50_Horizontal_1EP_style1 +Crystal:Crystal_HC50_Horizontal_1EP_style2 +Crystal:Crystal_HC50_Vertical +Crystal:Crystal_HC51-U_Vertical +Crystal:Crystal_HC51_Horizontal +Crystal:Crystal_HC51_Horizontal_1EP_style1 +Crystal:Crystal_HC51_Horizontal_1EP_style2 +Crystal:Crystal_HC52-6mm_Horizontal +Crystal:Crystal_HC52-6mm_Horizontal_1EP_style1 +Crystal:Crystal_HC52-6mm_Horizontal_1EP_style2 +Crystal:Crystal_HC52-6mm_Vertical +Crystal:Crystal_HC52-8mm_Horizontal +Crystal:Crystal_HC52-8mm_Horizontal_1EP_style1 +Crystal:Crystal_HC52-8mm_Horizontal_1EP_style2 +Crystal:Crystal_HC52-8mm_Vertical +Crystal:Crystal_HC52-U-3Pin_Vertical +Crystal:Crystal_HC52-U_Horizontal +Crystal:Crystal_HC52-U_Horizontal_1EP_style1 +Crystal:Crystal_HC52-U_Horizontal_1EP_style2 +Crystal:Crystal_HC52-U_Vertical +Crystal:Crystal_Round_D1.0mm_Vertical +Crystal:Crystal_Round_D1.5mm_Vertical +Crystal:Crystal_Round_D2.0mm_Vertical +Crystal:Crystal_Round_D3.0mm_Vertical +Crystal:Crystal_SMD_0603-2Pin_6.0x3.5mm +Crystal:Crystal_SMD_0603-2Pin_6.0x3.5mm_HandSoldering +Crystal:Crystal_SMD_0603-4Pin_6.0x3.5mm +Crystal:Crystal_SMD_0603-4Pin_6.0x3.5mm_HandSoldering +Crystal:Crystal_SMD_1210-4Pin_1.2x1.0mm +Crystal:Crystal_SMD_2012-2Pin_2.0x1.2mm +Crystal:Crystal_SMD_2012-2Pin_2.0x1.2mm_HandSoldering +Crystal:Crystal_SMD_2016-4Pin_2.0x1.6mm +Crystal:Crystal_SMD_2520-4Pin_2.5x2.0mm +Crystal:Crystal_SMD_3215-2Pin_3.2x1.5mm +Crystal:Crystal_SMD_3225-4Pin_3.2x2.5mm +Crystal:Crystal_SMD_3225-4Pin_3.2x2.5mm_HandSoldering +Crystal:Crystal_SMD_5032-2Pin_5.0x3.2mm +Crystal:Crystal_SMD_5032-2Pin_5.0x3.2mm_HandSoldering +Crystal:Crystal_SMD_5032-4Pin_5.0x3.2mm +Crystal:Crystal_SMD_7050-2Pin_7.0x5.0mm +Crystal:Crystal_SMD_7050-2Pin_7.0x5.0mm_HandSoldering +Crystal:Crystal_SMD_7050-4Pin_7.0x5.0mm +Crystal:Crystal_SMD_Abracon_ABM10-4Pin_2.5x2.0mm +Crystal:Crystal_SMD_Abracon_ABM3-2Pin_5.0x3.2mm +Crystal:Crystal_SMD_Abracon_ABM3-2Pin_5.0x3.2mm_HandSoldering +Crystal:Crystal_SMD_Abracon_ABM3B-4Pin_5.0x3.2mm +Crystal:Crystal_SMD_Abracon_ABM3C-4Pin_5.0x3.2mm +Crystal:Crystal_SMD_Abracon_ABM7-2Pin_6.0x3.5mm +Crystal:Crystal_SMD_Abracon_ABM8AIG-4Pin_3.2x2.5mm +Crystal:Crystal_SMD_Abracon_ABM8G-4Pin_3.2x2.5mm +Crystal:Crystal_SMD_Abracon_ABS25-4Pin_8.0x3.8mm +Crystal:Crystal_SMD_ECS_CSM3X-2Pin_7.6x4.1mm +Crystal:Crystal_SMD_EuroQuartz_EQ161-2Pin_3.2x1.5mm +Crystal:Crystal_SMD_EuroQuartz_EQ161-2Pin_3.2x1.5mm_HandSoldering +Crystal:Crystal_SMD_EuroQuartz_MJ-4Pin_5.0x3.2mm +Crystal:Crystal_SMD_EuroQuartz_MJ-4Pin_5.0x3.2mm_HandSoldering +Crystal:Crystal_SMD_EuroQuartz_MQ-4Pin_7.0x5.0mm +Crystal:Crystal_SMD_EuroQuartz_MQ-4Pin_7.0x5.0mm_HandSoldering +Crystal:Crystal_SMD_EuroQuartz_MQ2-2Pin_7.0x5.0mm +Crystal:Crystal_SMD_EuroQuartz_MQ2-2Pin_7.0x5.0mm_HandSoldering +Crystal:Crystal_SMD_EuroQuartz_MT-4Pin_3.2x2.5mm +Crystal:Crystal_SMD_EuroQuartz_MT-4Pin_3.2x2.5mm_HandSoldering +Crystal:Crystal_SMD_EuroQuartz_X22-4Pin_2.5x2.0mm +Crystal:Crystal_SMD_EuroQuartz_X22-4Pin_2.5x2.0mm_HandSoldering +Crystal:Crystal_SMD_FOX_FE-2Pin_7.5x5.0mm +Crystal:Crystal_SMD_FOX_FE-2Pin_7.5x5.0mm_HandSoldering +Crystal:Crystal_SMD_FOX_FQ7050-2Pin_7.0x5.0mm +Crystal:Crystal_SMD_FOX_FQ7050-2Pin_7.0x5.0mm_HandSoldering +Crystal:Crystal_SMD_FOX_FQ7050-4Pin_7.0x5.0mm +Crystal:Crystal_SMD_FrontierElectronics_FM206 +Crystal:Crystal_SMD_G8-2Pin_3.2x1.5mm +Crystal:Crystal_SMD_G8-2Pin_3.2x1.5mm_HandSoldering +Crystal:Crystal_SMD_HC49-SD +Crystal:Crystal_SMD_HC49-SD_HandSoldering +Crystal:Crystal_SMD_MicroCrystal_CC1V-T1A-2Pin_8.0x3.7mm +Crystal:Crystal_SMD_MicroCrystal_CC1V-T1A-2Pin_8.0x3.7mm_HandSoldering +Crystal:Crystal_SMD_MicroCrystal_CC4V-T1A-2Pin_5.0x1.9mm +Crystal:Crystal_SMD_MicroCrystal_CC4V-T1A-2Pin_5.0x1.9mm_HandSoldering +Crystal:Crystal_SMD_MicroCrystal_CC5V-T1A-2Pin_4.1x1.5mm +Crystal:Crystal_SMD_MicroCrystal_CC5V-T1A-2Pin_4.1x1.5mm_HandSoldering +Crystal:Crystal_SMD_MicroCrystal_CC7V-T1A-2Pin_3.2x1.5mm +Crystal:Crystal_SMD_MicroCrystal_CC7V-T1A-2Pin_3.2x1.5mm_HandSoldering +Crystal:Crystal_SMD_MicroCrystal_CC8V-T1A-2Pin_2.0x1.2mm +Crystal:Crystal_SMD_MicroCrystal_CC8V-T1A-2Pin_2.0x1.2mm_HandSoldering +Crystal:Crystal_SMD_MicroCrystal_CM9V-T1A-2Pin_1.6x1.0mm +Crystal:Crystal_SMD_MicroCrystal_CM9V-T1A-2Pin_1.6x1.0mm_HandSoldering +Crystal:Crystal_SMD_MicroCrystal_MS1V-T1K +Crystal:Crystal_SMD_MicroCrystal_MS3V-T1R +Crystal:Crystal_SMD_Qantek_QC5CB-2Pin_5x3.2mm +Crystal:Crystal_SMD_SeikoEpson_FA128-4Pin_2.0x1.6mm +Crystal:Crystal_SMD_SeikoEpson_FA238-4Pin_3.2x2.5mm +Crystal:Crystal_SMD_SeikoEpson_FA238-4Pin_3.2x2.5mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_FA238V-4Pin_3.2x2.5mm +Crystal:Crystal_SMD_SeikoEpson_FA238V-4Pin_3.2x2.5mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_MA406-4Pin_11.7x4.0mm +Crystal:Crystal_SMD_SeikoEpson_MA406-4Pin_11.7x4.0mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_MA505-2Pin_12.7x5.1mm +Crystal:Crystal_SMD_SeikoEpson_MA505-2Pin_12.7x5.1mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_MA506-4Pin_12.7x5.1mm +Crystal:Crystal_SMD_SeikoEpson_MA506-4Pin_12.7x5.1mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_MC146-4Pin_6.7x1.5mm +Crystal:Crystal_SMD_SeikoEpson_MC146-4Pin_6.7x1.5mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_MC156-4Pin_7.1x2.5mm +Crystal:Crystal_SMD_SeikoEpson_MC156-4Pin_7.1x2.5mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_MC306-4Pin_8.0x3.2mm +Crystal:Crystal_SMD_SeikoEpson_MC306-4Pin_8.0x3.2mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_MC405-2Pin_9.6x4.1mm +Crystal:Crystal_SMD_SeikoEpson_MC405-2Pin_9.6x4.1mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_MC406-4Pin_9.6x4.1mm +Crystal:Crystal_SMD_SeikoEpson_MC406-4Pin_9.6x4.1mm_HandSoldering +Crystal:Crystal_SMD_SeikoEpson_TSX3225-4Pin_3.2x2.5mm +Crystal:Crystal_SMD_SeikoEpson_TSX3225-4Pin_3.2x2.5mm_HandSoldering +Crystal:Crystal_SMD_TXC_7A-2Pin_5x3.2mm +Crystal:Crystal_SMD_TXC_7M-4Pin_3.2x2.5mm +Crystal:Crystal_SMD_TXC_7M-4Pin_3.2x2.5mm_HandSoldering +Crystal:Crystal_SMD_TXC_9HT11-2Pin_2.0x1.2mm +Crystal:Crystal_SMD_TXC_9HT11-2Pin_2.0x1.2mm_HandSoldering +Crystal:Crystal_SMD_TXC_AX_8045-2Pin_8.0x4.5mm +Crystal:Resonator-2Pin_W10.0mm_H5.0mm +Crystal:Resonator-2Pin_W6.0mm_H3.0mm +Crystal:Resonator-2Pin_W7.0mm_H2.5mm +Crystal:Resonator-2Pin_W8.0mm_H3.5mm +Crystal:Resonator-3Pin_W10.0mm_H5.0mm +Crystal:Resonator-3Pin_W6.0mm_H3.0mm +Crystal:Resonator-3Pin_W7.0mm_H2.5mm +Crystal:Resonator-3Pin_W8.0mm_H3.5mm +Crystal:Resonator_Murata_CSTLSxxxG-3Pin_W8.0mm_H3.0mm +Crystal:Resonator_Murata_CSTLSxxxX-3Pin_W5.5mm_H3.0mm +Crystal:Resonator_Murata_DSN6-3Pin_W7.0mm_H2.5mm +Crystal:Resonator_Murata_DSS6-3Pin_W7.0mm_H2.5mm +Crystal:Resonator_SMD-3Pin_7.2x3.0mm +Crystal:Resonator_SMD-3Pin_7.2x3.0mm_HandSoldering +Crystal:Resonator_SMD_Murata_CDSCB-2Pin_4.5x2.0mm +Crystal:Resonator_SMD_Murata_CDSCB-2Pin_4.5x2.0mm_HandSoldering +Crystal:Resonator_SMD_Murata_CSTCR_4.5x2x1.15mm +Crystal:Resonator_SMD_Murata_CSTxExxV-3Pin_3.0x1.1mm +Crystal:Resonator_SMD_Murata_CSTxExxV-3Pin_3.0x1.1mm_HandSoldering +Crystal:Resonator_SMD_Murata_SFECV-3Pin_6.9x2.9mm +Crystal:Resonator_SMD_Murata_SFECV-3Pin_6.9x2.9mm_HandSoldering +Crystal:Resonator_SMD_Murata_SFSKA-3Pin_7.9x3.8mm +Crystal:Resonator_SMD_Murata_SFSKA-3Pin_7.9x3.8mm_HandSoldering +Crystal:Resonator_SMD_Murata_TPSKA-3Pin_7.9x3.8mm +Crystal:Resonator_SMD_Murata_TPSKA-3Pin_7.9x3.8mm_HandSoldering +Diode_SMD:Diode_Bridge_Bourns_CD-DF4xxS +Diode_SMD:Diode_Bridge_Diotec_ABS +Diode_SMD:Diode_Bridge_Diotec_MicroDil_3.0x3.0x1.8mm +Diode_SMD:Diode_Bridge_Diotec_SO-DIL-Slim +Diode_SMD:Diode_Bridge_OnSemi_SDIP-4L +Diode_SMD:Diode_Bridge_Vishay_DFS +Diode_SMD:Diode_Bridge_Vishay_DFSFlat +Diode_SMD:Diode_Bridge_Vishay_MBLS +Diode_SMD:D_01005_0402Metric +Diode_SMD:D_01005_0402Metric_Pad0.57x0.30mm_HandSolder +Diode_SMD:D_0201_0603Metric +Diode_SMD:D_0201_0603Metric_Pad0.64x0.40mm_HandSolder +Diode_SMD:D_0402_1005Metric +Diode_SMD:D_0402_1005Metric_Pad0.77x0.64mm_HandSolder +Diode_SMD:D_0603_1608Metric +Diode_SMD:D_0603_1608Metric_Pad1.05x0.95mm_HandSolder +Diode_SMD:D_0805_2012Metric +Diode_SMD:D_0805_2012Metric_Pad1.15x1.40mm_HandSolder +Diode_SMD:D_1206_3216Metric +Diode_SMD:D_1206_3216Metric_Pad1.42x1.75mm_HandSolder +Diode_SMD:D_1210_3225Metric +Diode_SMD:D_1210_3225Metric_Pad1.42x2.65mm_HandSolder +Diode_SMD:D_1812_4532Metric +Diode_SMD:D_1812_4532Metric_Pad1.30x3.40mm_HandSolder +Diode_SMD:D_2010_5025Metric +Diode_SMD:D_2010_5025Metric_Pad1.52x2.65mm_HandSolder +Diode_SMD:D_2114_3652Metric +Diode_SMD:D_2114_3652Metric_Pad1.85x3.75mm_HandSolder +Diode_SMD:D_2512_6332Metric +Diode_SMD:D_2512_6332Metric_Pad1.52x3.35mm_HandSolder +Diode_SMD:D_3220_8050Metric +Diode_SMD:D_3220_8050Metric_Pad2.65x5.15mm_HandSolder +Diode_SMD:D_MELF-RM10_Universal_Handsoldering +Diode_SMD:D_MELF +Diode_SMD:D_MELF_Handsoldering +Diode_SMD:D_MicroMELF +Diode_SMD:D_MicroMELF_Handsoldering +Diode_SMD:D_MicroSMP_AK +Diode_SMD:D_MicroSMP_KA +Diode_SMD:D_MiniMELF +Diode_SMD:D_MiniMELF_Handsoldering +Diode_SMD:D_PowerDI-123 +Diode_SMD:D_PowerDI-5 +Diode_SMD:D_Powermite2_AK +Diode_SMD:D_Powermite2_KA +Diode_SMD:D_Powermite3 +Diode_SMD:D_Powermite_AK +Diode_SMD:D_Powermite_KA +Diode_SMD:D_QFN_3.3x3.3mm_P0.65mm +Diode_SMD:D_SC-80 +Diode_SMD:D_SC-80_HandSoldering +Diode_SMD:D_SMA-SMB_Universal_Handsoldering +Diode_SMD:D_SMA +Diode_SMD:D_SMA_Handsoldering +Diode_SMD:D_SMB-SMC_Universal_Handsoldering +Diode_SMD:D_SMB +Diode_SMD:D_SMB_Handsoldering +Diode_SMD:D_SMB_Modified +Diode_SMD:D_SMC-RM10_Universal_Handsoldering +Diode_SMD:D_SMC +Diode_SMD:D_SMC_Handsoldering +Diode_SMD:D_SMF +Diode_SMD:D_SMP_DO-220AA +Diode_SMD:D_SOD-110 +Diode_SMD:D_SOD-123 +Diode_SMD:D_SOD-123F +Diode_SMD:D_SOD-128 +Diode_SMD:D_SOD-323 +Diode_SMD:D_SOD-323F +Diode_SMD:D_SOD-323_HandSoldering +Diode_SMD:D_SOD-523 +Diode_SMD:D_SOD-882 +Diode_SMD:D_SOD-882D +Diode_SMD:D_SOD-923 +Diode_SMD:D_TUMD2 +Diode_SMD:Infineon_SG-WLL-2-3_0.58x0.28_P0.36mm +Diode_SMD:Littelfuse_PolyZen-LS +Diode_SMD:Nexperia_CFP3_SOD-123W +Diode_SMD:Nexperia_DSN0603-2_0.6x0.3mm_P0.4mm +Diode_SMD:Nexperia_DSN1608-2_1.6x0.8mm +Diode_SMD:OnSemi_751EP_SOIC-4_3.9x4.725mm_P2.54mm +Diode_SMD:ST_D_SMC +Diode_SMD:ST_QFN-2L_1.6x1.0mm +Diode_SMD:Vishay_SMPA +Diode_THT:Diode_Bridge_15.1x15.1x6.3mm_P10.9mm +Diode_THT:Diode_Bridge_15.2x15.2x6.3mm_P10.9mm +Diode_THT:Diode_Bridge_15.7x15.7x6.3mm_P10.8mm +Diode_THT:Diode_Bridge_16.7x16.7x6.3mm_P10.8mm +Diode_THT:Diode_Bridge_19.0x19.0x6.8mm_P12.7mm +Diode_THT:Diode_Bridge_19.0x3.5x10.0mm_P5.0mm +Diode_THT:Diode_Bridge_28.6x28.6x7.3mm_P18.0mm_P11.6mm +Diode_THT:Diode_Bridge_32.0x5.6x17.0mm_P10.0mm_P7.5mm +Diode_THT:Diode_Bridge_Comchip_SCVB-L +Diode_THT:Diode_Bridge_DIGITRON_KBPC_T +Diode_THT:Diode_Bridge_DIP-4_W5.08mm_P2.54mm +Diode_THT:Diode_Bridge_DIP-4_W7.62mm_P5.08mm +Diode_THT:Diode_Bridge_GeneSiC_KBPC_T +Diode_THT:Diode_Bridge_GeneSiC_KBPC_W +Diode_THT:Diode_Bridge_IXYS_GUFP +Diode_THT:Diode_Bridge_Round_D8.9mm +Diode_THT:Diode_Bridge_Round_D9.0mm +Diode_THT:Diode_Bridge_Round_D9.8mm +Diode_THT:Diode_Bridge_Vishay_GBL +Diode_THT:Diode_Bridge_Vishay_GBU +Diode_THT:Diode_Bridge_Vishay_KBL +Diode_THT:Diode_Bridge_Vishay_KBPC1 +Diode_THT:Diode_Bridge_Vishay_KBPC6 +Diode_THT:Diode_Bridge_Vishay_KBPM +Diode_THT:Diode_Bridge_Vishay_KBU +Diode_THT:D_5KPW_P12.70mm_Horizontal +Diode_THT:D_5KPW_P7.62mm_Vertical_AnodeUp +Diode_THT:D_5KPW_P7.62mm_Vertical_KathodeUp +Diode_THT:D_5KP_P10.16mm_Horizontal +Diode_THT:D_5KP_P12.70mm_Horizontal +Diode_THT:D_5KP_P7.62mm_Vertical_AnodeUp +Diode_THT:D_5KP_P7.62mm_Vertical_KathodeUp +Diode_THT:D_5W_P10.16mm_Horizontal +Diode_THT:D_5W_P12.70mm_Horizontal +Diode_THT:D_5W_P5.08mm_Vertical_AnodeUp +Diode_THT:D_5W_P5.08mm_Vertical_KathodeUp +Diode_THT:D_A-405_P10.16mm_Horizontal +Diode_THT:D_A-405_P12.70mm_Horizontal +Diode_THT:D_A-405_P2.54mm_Vertical_AnodeUp +Diode_THT:D_A-405_P2.54mm_Vertical_KathodeUp +Diode_THT:D_A-405_P5.08mm_Vertical_AnodeUp +Diode_THT:D_A-405_P5.08mm_Vertical_KathodeUp +Diode_THT:D_A-405_P7.62mm_Horizontal +Diode_THT:D_DO-15_P10.16mm_Horizontal +Diode_THT:D_DO-15_P12.70mm_Horizontal +Diode_THT:D_DO-15_P15.24mm_Horizontal +Diode_THT:D_DO-15_P2.54mm_Vertical_AnodeUp +Diode_THT:D_DO-15_P2.54mm_Vertical_KathodeUp +Diode_THT:D_DO-15_P3.81mm_Vertical_AnodeUp +Diode_THT:D_DO-15_P3.81mm_Vertical_KathodeUp +Diode_THT:D_DO-15_P5.08mm_Vertical_AnodeUp +Diode_THT:D_DO-15_P5.08mm_Vertical_KathodeUp +Diode_THT:D_DO-201AD_P12.70mm_Horizontal +Diode_THT:D_DO-201AD_P15.24mm_Horizontal +Diode_THT:D_DO-201AD_P3.81mm_Vertical_AnodeUp +Diode_THT:D_DO-201AD_P3.81mm_Vertical_KathodeUp +Diode_THT:D_DO-201AD_P5.08mm_Vertical_AnodeUp +Diode_THT:D_DO-201AD_P5.08mm_Vertical_KathodeUp +Diode_THT:D_DO-201AE_P12.70mm_Horizontal +Diode_THT:D_DO-201AE_P15.24mm_Horizontal +Diode_THT:D_DO-201AE_P3.81mm_Vertical_AnodeUp +Diode_THT:D_DO-201AE_P3.81mm_Vertical_KathodeUp +Diode_THT:D_DO-201AE_P5.08mm_Vertical_AnodeUp +Diode_THT:D_DO-201AE_P5.08mm_Vertical_KathodeUp +Diode_THT:D_DO-201_P12.70mm_Horizontal +Diode_THT:D_DO-201_P15.24mm_Horizontal +Diode_THT:D_DO-201_P3.81mm_Vertical_AnodeUp +Diode_THT:D_DO-201_P3.81mm_Vertical_KathodeUp +Diode_THT:D_DO-201_P5.08mm_Vertical_AnodeUp +Diode_THT:D_DO-201_P5.08mm_Vertical_KathodeUp +Diode_THT:D_DO-247_Horizontal_TabDown +Diode_THT:D_DO-247_Horizontal_TabUp +Diode_THT:D_DO-247_Vertical +Diode_THT:D_DO-27_P12.70mm_Horizontal +Diode_THT:D_DO-27_P15.24mm_Horizontal +Diode_THT:D_DO-27_P5.08mm_Vertical_AnodeUp +Diode_THT:D_DO-27_P5.08mm_Vertical_KathodeUp +Diode_THT:D_DO-34_SOD68_P10.16mm_Horizontal +Diode_THT:D_DO-34_SOD68_P12.70mm_Horizontal +Diode_THT:D_DO-34_SOD68_P2.54mm_Vertical_AnodeUp +Diode_THT:D_DO-34_SOD68_P2.54mm_Vertical_KathodeUp +Diode_THT:D_DO-34_SOD68_P5.08mm_Vertical_AnodeUp +Diode_THT:D_DO-34_SOD68_P5.08mm_Vertical_KathodeUp +Diode_THT:D_DO-34_SOD68_P7.62mm_Horizontal +Diode_THT:D_DO-35_SOD27_P10.16mm_Horizontal +Diode_THT:D_DO-35_SOD27_P12.70mm_Horizontal +Diode_THT:D_DO-35_SOD27_P2.54mm_Vertical_AnodeUp +Diode_THT:D_DO-35_SOD27_P2.54mm_Vertical_KathodeUp +Diode_THT:D_DO-35_SOD27_P3.81mm_Vertical_AnodeUp +Diode_THT:D_DO-35_SOD27_P3.81mm_Vertical_KathodeUp +Diode_THT:D_DO-35_SOD27_P5.08mm_Vertical_AnodeUp +Diode_THT:D_DO-35_SOD27_P5.08mm_Vertical_KathodeUp +Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal +Diode_THT:D_DO-41_SOD81_P10.16mm_Horizontal +Diode_THT:D_DO-41_SOD81_P12.70mm_Horizontal +Diode_THT:D_DO-41_SOD81_P2.54mm_Vertical_AnodeUp +Diode_THT:D_DO-41_SOD81_P2.54mm_Vertical_KathodeUp +Diode_THT:D_DO-41_SOD81_P3.81mm_Vertical_AnodeUp +Diode_THT:D_DO-41_SOD81_P3.81mm_Vertical_KathodeUp +Diode_THT:D_DO-41_SOD81_P5.08mm_Vertical_AnodeUp +Diode_THT:D_DO-41_SOD81_P5.08mm_Vertical_KathodeUp +Diode_THT:D_DO-41_SOD81_P7.62mm_Horizontal +Diode_THT:D_P600_R-6_P12.70mm_Horizontal +Diode_THT:D_P600_R-6_P20.00mm_Horizontal +Diode_THT:D_P600_R-6_P7.62mm_Vertical_AnodeUp +Diode_THT:D_P600_R-6_P7.62mm_Vertical_KathodeUp +Diode_THT:D_T-1_P10.16mm_Horizontal +Diode_THT:D_T-1_P12.70mm_Horizontal +Diode_THT:D_T-1_P2.54mm_Vertical_AnodeUp +Diode_THT:D_T-1_P2.54mm_Vertical_KathodeUp +Diode_THT:D_T-1_P5.08mm_Horizontal +Display:Adafruit_SSD1306 +Display:Adafruit_SSD1306_No_Mounting_Holes +Display:AG12864E +Display:CR2013-MI2120 +Display:EA-eDIP128B-XXX +Display:EA_DOGL128-6 +Display:EA_DOGM128-6 +Display:EA_DOGS104X-A +Display:EA_DOGXL160-7 +Display:EA_DOGXL160-7_Backlight +Display:EA_eDIP160-XXX +Display:EA_eDIP240-XXX +Display:EA_eDIP320X-XXX +Display:EA_eDIPTFT32-XXX +Display:EA_eDIPTFT43-ATC +Display:EA_eDIPTFT43-XXX +Display:EA_eDIPTFT57-XXX +Display:EA_eDIPTFT70-ATC +Display:EA_eDIPTFT70-XXX +Display:EA_T123X-I2C +Display:ER-OLED0.42-1W_Folded +Display:ERM19264 +Display:HDSM-441B_HDSM-443B +Display:HDSM-541B_HDSM-543B +Display:HDSP-4830 +Display:HDSP-4832 +Display:HDSP-4836 +Display:HDSP-4840 +Display:HDSP-4850 +Display:HDSP-48xx +Display:HLCP-J100 +Display:HY1602E +Display:LCD-016N002L +Display:LM16255 +Display:NHD-0420H1Z +Display:NHD-C0220BiZ-FSRGB +Display:NHD-C0220BiZ +Display:NHD-C12832A1Z-FSRGB +Display:OLED-128O064D +Display:RC1602A +Display:WC1602A +Display_7Segment:7SEGMENT-LED__HDSM531_HDSM533_SMD +Display_7Segment:7SegmentLED_LTS6760_LTS6780 +Display_7Segment:AD-121F2 +Display_7Segment:AFF_2x7SEG-DIGIT_10mm +Display_7Segment:CA56-12CGKWA +Display_7Segment:CA56-12EWA +Display_7Segment:CA56-12SEKWA +Display_7Segment:CA56-12SRWA +Display_7Segment:CA56-12SURKWA +Display_7Segment:CA56-12SYKWA +Display_7Segment:CC56-12GWA +Display_7Segment:CC56-12YWA +Display_7Segment:D1X8K +Display_7Segment:DA04-11CGKWA +Display_7Segment:DA04-11SEKWA +Display_7Segment:DA04-11SURKWA +Display_7Segment:DA04-11SYKWA +Display_7Segment:DA56-11CGKWA +Display_7Segment:DA56-11SEKWA +Display_7Segment:DA56-11SURKWA +Display_7Segment:DA56-11SYKWA +Display_7Segment:DE113-XX-XX +Display_7Segment:DE114-RS-20 +Display_7Segment:DE119-XX-XX +Display_7Segment:DE122-XX-XX +Display_7Segment:DE152-XX-XX +Display_7Segment:DE170-XX-XX +Display_7Segment:ELD_426XXXX +Display_7Segment:HDSP-7401 +Display_7Segment:HDSP-7507 +Display_7Segment:HDSP-7801 +Display_7Segment:HDSP-7807 +Display_7Segment:HDSP-A151 +Display_7Segment:HDSP-A401 +Display_7Segment:KCSC02-105 +Display_7Segment:KCSC02-106 +Display_7Segment:KCSC02-107 +Display_7Segment:KCSC02-123 +Display_7Segment:KCSC02-136 +Display_7Segment:LTC-4627Jx +Display_7Segment:MAN3410A +Display_7Segment:MAN3420A +Display_7Segment:MAN3610A +Display_7Segment:MAN3620A +Display_7Segment:MAN3630A +Display_7Segment:MAN3810A +Display_7Segment:MAN3820A +Display_7Segment:MAN71A +Display_7Segment:MAN72A +Display_7Segment:MAN73A +Display_7Segment:SA15-11xxx +Display_7Segment:SBC18-11SURKCGKWA +Display_7Segment:Sx39-1xxxxx +Ferrite_THT:LairdTech_28C0236-0JW-10 +Fiducial:Fiducial_0.5mm_Mask1.5mm +Fiducial:Fiducial_0.5mm_Mask1mm +Fiducial:Fiducial_0.75mm_Mask1.5mm +Fiducial:Fiducial_0.75mm_Mask2.25mm +Fiducial:Fiducial_1.5mm_Mask3mm +Fiducial:Fiducial_1.5mm_Mask4.5mm +Fiducial:Fiducial_1mm_Mask2mm +Fiducial:Fiducial_1mm_Mask3mm +Filter:Filter_1109-5_1.1x0.9mm +Filter:Filter_1411-5_1.4x1.1mm +Filter:Filter_Bourns_SRF0905_6.0x9.2mm +Filter:Filter_FILTERCON_1FPxx +Filter:Filter_KEMET_PZB300_24.0x12.5mm_P10.0mm +Filter:Filter_Mini-Circuits_FV1206-1 +Filter:Filter_Mini-Circuits_FV1206-4 +Filter:Filter_Mini-Circuits_FV1206-5 +Filter:Filter_Mini-Circuits_FV1206-6 +Filter:Filter_Mini-Circuits_FV1206-7 +Filter:Filter_Mini-Circuits_FV1206 +Filter:Filter_Murata_BNX025 +Filter:Filter_Murata_BNX025_ThermalVias +Filter:Filter_Murata_SFECF-6 +Filter:Filter_Murata_SFECF-6_HandSoldering +Filter:Filter_SAW-6_3.8x3.8mm +Filter:Filter_SAW-8_3.8x3.8mm +Filter:Filter_SAW_Epcos_DCC6C_3x3mm +Filter:Filter_Schaffner_FN405 +Filter:Filter_Schaffner_FN406 +Fuse:FuseHolder_Blade_ATO_Littelfuse_FLR_178.6165 +Fuse:Fuseholder_Blade_ATO_Littelfuse_Pudenz_2_Pin +Fuse:Fuseholder_Blade_Mini_Keystone_3568 +Fuse:Fuseholder_Clip-5x20mm_Bel_FC-203-22_Lateral_P17.80x5.00mm_D1.17mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Eaton_1A5601-01_Inline_P20.80x6.76mm_D1.70mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Keystone_3512P_Inline_P23.62x7.27mm_D1.02x2.41x1.02x1.57mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Keystone_3512_Inline_P23.62x7.27mm_D1.02x1.57mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Keystone_3517_Inline_P23.11x6.76mm_D1.70mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Keystone_3518P_Inline_P23.11x6.76mm_D2.44x1.70mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Littelfuse_100_Inline_P20.50x4.60mm_D1.30mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Littelfuse_111_Inline_P20.00x5.00mm_D1.05mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Littelfuse_111_Lateral_P18.80x5.00mm_D1.17mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Littelfuse_445-030_Inline_P20.50x5.20mm_D1.30mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Littelfuse_519_Inline_P20.60x5.00mm_D1.00mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Littelfuse_520_Inline_P20.50x5.80mm_D1.30mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Littelfuse_521_Lateral_P17.00x5.00mm_D1.30mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Schurter_CQM_Inline_P20.60x5.00mm_D1.00mm_Horizontal +Fuse:Fuseholder_Clip-5x20mm_Schurter_OG_Lateral_P15.00x5.00mm_D1.3mm_Horizontal +Fuse:Fuseholder_Clip-6.3x32mm_Littelfuse_102071_Inline_P34.70x7.60mm_D2.00mm_Horizontal +Fuse:Fuseholder_Clip-6.3x32mm_Littelfuse_102_122_Inline_P34.21x7.62mm_D1.98mm_Horizontal +Fuse:Fuseholder_Clip-6.3x32mm_Littelfuse_102_Inline_P34.21x7.62mm_D2.54mm_Horizontal +Fuse:Fuseholder_Clip-6.3x32mm_Littelfuse_122_Inline_P34.21x7.62mm_D2.54mm_Horizontal +Fuse:Fuseholder_Cylinder-5x20mm_Bulgin_FX0456_Vertical_Closed +Fuse:Fuseholder_Cylinder-5x20mm_Bulgin_FX0457_Horizontal_Closed +Fuse:Fuseholder_Cylinder-5x20mm_EATON_H15-V-1_Vertical_Closed +Fuse:Fuseholder_Cylinder-5x20mm_EATON_HBV_Vertical_Closed +Fuse:Fuseholder_Cylinder-5x20mm_EATON_HBW_Vertical_Closed +Fuse:Fuseholder_Cylinder-5x20mm_Schurter_0031_8201_Horizontal_Open +Fuse:Fuseholder_Cylinder-5x20mm_Schurter_FAB_0031-355x_Horizontal_Closed +Fuse:Fuseholder_Cylinder-5x20mm_Schurter_FPG4_Vertical_Closed +Fuse:Fuseholder_Cylinder-5x20mm_Schurter_FUP_0031.2510_Horizontal_Closed +Fuse:Fuseholder_Cylinder-5x20mm_Schurter_OGN-SMD_Horizontal_Open +Fuse:Fuseholder_Cylinder-5x20mm_Stelvio-Kontek_PTF78_Horizontal_Open +Fuse:Fuseholder_Cylinder-5x20mm_Wuerth_696103101002-SMD_Horizontal_Open +Fuse:Fuseholder_Cylinder-6.3x32mm_Schurter_0031-8002_Horizontal_Open +Fuse:Fuseholder_Cylinder-6.3x32mm_Schurter_FUP_0031.2520_Horizontal_Closed +Fuse:Fuseholder_Keystone_3555-2 +Fuse:Fuseholder_Littelfuse_100_series_5x20mm +Fuse:Fuseholder_Littelfuse_100_series_5x25mm +Fuse:Fuseholder_Littelfuse_100_series_5x30mm +Fuse:Fuseholder_Littelfuse_445_030_series_5x20mm +Fuse:Fuseholder_Littelfuse_445_030_series_5x25mm +Fuse:Fuseholder_Littelfuse_445_030_series_5x30mm +Fuse:Fuseholder_Littelfuse_Nano2_154x +Fuse:Fuseholder_Littelfuse_Nano2_157x +Fuse:Fuseholder_TR5_Littelfuse_No560_No460 +Fuse:Fuse_0402_1005Metric +Fuse:Fuse_0402_1005Metric_Pad0.77x0.64mm_HandSolder +Fuse:Fuse_0603_1608Metric +Fuse:Fuse_0603_1608Metric_Pad1.05x0.95mm_HandSolder +Fuse:Fuse_0805_2012Metric +Fuse:Fuse_0805_2012Metric_Pad1.15x1.40mm_HandSolder +Fuse:Fuse_1206_3216Metric +Fuse:Fuse_1206_3216Metric_Pad1.42x1.75mm_HandSolder +Fuse:Fuse_1210_3225Metric +Fuse:Fuse_1210_3225Metric_Pad1.42x2.65mm_HandSolder +Fuse:Fuse_1812_4532Metric +Fuse:Fuse_1812_4532Metric_Pad1.30x3.40mm_HandSolder +Fuse:Fuse_2010_5025Metric +Fuse:Fuse_2010_5025Metric_Pad1.52x2.65mm_HandSolder +Fuse:Fuse_2512_6332Metric +Fuse:Fuse_2512_6332Metric_Pad1.52x3.35mm_HandSolder +Fuse:Fuse_2920_7451Metric +Fuse:Fuse_2920_7451Metric_Pad2.10x5.45mm_HandSolder +Fuse:Fuse_BelFuse_0ZRE0005FF_L8.3mm_W3.8mm +Fuse:Fuse_BelFuse_0ZRE0008FF_L8.3mm_W3.8mm +Fuse:Fuse_BelFuse_0ZRE0012FF_L8.3mm_W3.8mm +Fuse:Fuse_BelFuse_0ZRE0016FF_L9.9mm_W3.8mm +Fuse:Fuse_BelFuse_0ZRE0025FF_L9.6mm_W3.8mm +Fuse:Fuse_BelFuse_0ZRE0033FF_L11.4mm_W3.8mm +Fuse:Fuse_BelFuse_0ZRE0040FF_L11.5mm_W3.8mm +Fuse:Fuse_BelFuse_0ZRE0055FF_L14.0mm_W4.1mm +Fuse:Fuse_BelFuse_0ZRE0075FF_L11.5mm_W4.8mm +Fuse:Fuse_BelFuse_0ZRE0100FF_L18.7mm_W5.1mm +Fuse:Fuse_BelFuse_0ZRE0125FF_L21.2mm_W5.3mm +Fuse:Fuse_BelFuse_0ZRE0150FF_L23.4mm_W5.3mm +Fuse:Fuse_BelFuse_0ZRE0200FF_L24.9mm_W6.1mm +Fuse:Fuse_Blade_ATO_directSolder +Fuse:Fuse_Blade_Mini_directSolder +Fuse:Fuse_Bourns_MF-RG1000 +Fuse:Fuse_Bourns_MF-RG1100 +Fuse:Fuse_Bourns_MF-RG300 +Fuse:Fuse_Bourns_MF-RG400 +Fuse:Fuse_Bourns_MF-RG500 +Fuse:Fuse_Bourns_MF-RG600 +Fuse:Fuse_Bourns_MF-RG650 +Fuse:Fuse_Bourns_MF-RG700 +Fuse:Fuse_Bourns_MF-RG800 +Fuse:Fuse_Bourns_MF-RG900 +Fuse:Fuse_Bourns_MF-RHT050 +Fuse:Fuse_Bourns_MF-RHT070 +Fuse:Fuse_Bourns_MF-RHT100 +Fuse:Fuse_Bourns_MF-RHT1000 +Fuse:Fuse_Bourns_MF-RHT1100 +Fuse:Fuse_Bourns_MF-RHT1300 +Fuse:Fuse_Bourns_MF-RHT200 +Fuse:Fuse_Bourns_MF-RHT300 +Fuse:Fuse_Bourns_MF-RHT400 +Fuse:Fuse_Bourns_MF-RHT500 +Fuse:Fuse_Bourns_MF-RHT550 +Fuse:Fuse_Bourns_MF-RHT600 +Fuse:Fuse_Bourns_MF-RHT650 +Fuse:Fuse_Bourns_MF-RHT700 +Fuse:Fuse_Bourns_MF-RHT750 +Fuse:Fuse_Bourns_MF-RHT800 +Fuse:Fuse_Bourns_MF-RHT900 +Fuse:Fuse_Bourns_MF-SM_7.98x5.44mm +Fuse:Fuse_Bourns_MF-SM_9.5x6.71mm +Fuse:Fuse_Bourns_TBU-CA +Fuse:Fuse_Littelfuse-LVR100 +Fuse:Fuse_Littelfuse-LVR125 +Fuse:Fuse_Littelfuse-LVR200 +Fuse:Fuse_Littelfuse-NANO2-451_453 +Fuse:Fuse_Littelfuse-NANO2-462 +Fuse:Fuse_Littelfuse-NANO2-885 +Fuse:Fuse_Littelfuse_372_D8.50mm +Fuse:Fuse_Littelfuse_395Series +Fuse:Fuse_Schurter_UMT250 +Fuse:Fuse_Schurter_UMZ250 +Fuse:Fuse_SunFuse-6HP +Heatsink:Heatsink_125x35x50mm_3xFixationM3 +Heatsink:Heatsink_35x26mm_1xFixation3mm_Fischer-SK486-35 +Heatsink:Heatsink_38x38mm_SpringFixation +Heatsink:Heatsink_62x40mm_2xFixation3mm +Heatsink:Heatsink_AAVID_573300D00010G_TO-263 +Heatsink:Heatsink_AAVID_576802B03900G +Heatsink:Heatsink_AAVID_590302B03600G +Heatsink:Heatsink_AAVID_TV5G_TO220_Horizontal +Heatsink:Heatsink_Fischer_FK224xx2201_25x8.3mm +Heatsink:Heatsink_Fischer_FK24413D2PAK_26x13mm +Heatsink:Heatsink_Fischer_FK24413DPAK_23x13mm +Heatsink:Heatsink_Fischer_SK104-STC-STIC_35x13mm_2xDrill2.5mm +Heatsink:Heatsink_Fischer_SK104-STCB_35x13mm__2xDrill3.5mm_ScrewM3 +Heatsink:Heatsink_Fischer_SK129-STS_42x25mm_2xDrill2.5mm +Heatsink:Heatsink_SheetType_50x7mm_2Fixations +Heatsink:Heatsink_Stonecold_HS-130_30x12mm_2xFixation2.5mm +Heatsink:Heatsink_Stonecold_HS-132_32x14mm_2xFixation1.5mm +Heatsink:Heatsink_Stonecold_HS-S01_13.21x6.35mm +Heatsink:Heatsink_Stonecold_HS-S02_13.21x9.53mm +Heatsink:Heatsink_Stonecold_HS-S03_13.21x12.7mm +Inductor_SMD:L_01005_0402Metric +Inductor_SMD:L_01005_0402Metric_Pad0.57x0.30mm_HandSolder +Inductor_SMD:L_0201_0603Metric +Inductor_SMD:L_0201_0603Metric_Pad0.64x0.40mm_HandSolder +Inductor_SMD:L_0402_1005Metric +Inductor_SMD:L_0402_1005Metric_Pad0.77x0.64mm_HandSolder +Inductor_SMD:L_0603_1608Metric +Inductor_SMD:L_0603_1608Metric_Pad1.05x0.95mm_HandSolder +Inductor_SMD:L_0805_2012Metric +Inductor_SMD:L_0805_2012Metric_Pad1.05x1.20mm_HandSolder +Inductor_SMD:L_0805_2012Metric_Pad1.15x1.40mm_HandSolder +Inductor_SMD:L_10.4x10.4_H4.8 +Inductor_SMD:L_1008_2520Metric +Inductor_SMD:L_1008_2520Metric_Pad1.43x2.20mm_HandSolder +Inductor_SMD:L_1206_3216Metric +Inductor_SMD:L_1206_3216Metric_Pad1.22x1.90mm_HandSolder +Inductor_SMD:L_1206_3216Metric_Pad1.42x1.75mm_HandSolder +Inductor_SMD:L_1210_3225Metric +Inductor_SMD:L_1210_3225Metric_Pad1.42x2.65mm_HandSolder +Inductor_SMD:L_12x12mm_H4.5mm +Inductor_SMD:L_12x12mm_H6mm +Inductor_SMD:L_12x12mm_H8mm +Inductor_SMD:L_1806_4516Metric +Inductor_SMD:L_1806_4516Metric_Pad1.45x1.90mm_HandSolder +Inductor_SMD:L_1812_4532Metric +Inductor_SMD:L_1812_4532Metric_Pad1.30x3.40mm_HandSolder +Inductor_SMD:L_2010_5025Metric +Inductor_SMD:L_2010_5025Metric_Pad1.52x2.65mm_HandSolder +Inductor_SMD:L_2512_6332Metric +Inductor_SMD:L_2512_6332Metric_Pad1.52x3.35mm_HandSolder +Inductor_SMD:L_6.3x6.3_H3 +Inductor_SMD:L_7.3x7.3_H3.5 +Inductor_SMD:L_7.3x7.3_H4.5 +Inductor_SMD:L_Abracon_ASPI-0425 +Inductor_SMD:L_Abracon_ASPI-0630LR +Inductor_SMD:L_Abracon_ASPI-3012S +Inductor_SMD:L_Abracon_ASPI-4030S +Inductor_SMD:L_Abracon_ASPIAIG-F4020 +Inductor_SMD:L_APV_ANR252010 +Inductor_SMD:L_APV_ANR252012 +Inductor_SMD:L_APV_ANR3010 +Inductor_SMD:L_APV_ANR3012 +Inductor_SMD:L_APV_ANR3015 +Inductor_SMD:L_APV_ANR4010 +Inductor_SMD:L_APV_ANR4012 +Inductor_SMD:L_APV_ANR4018 +Inductor_SMD:L_APV_ANR4020 +Inductor_SMD:L_APV_ANR4026 +Inductor_SMD:L_APV_ANR4030 +Inductor_SMD:L_APV_ANR5012 +Inductor_SMD:L_APV_ANR5020 +Inductor_SMD:L_APV_ANR5040 +Inductor_SMD:L_APV_ANR5045 +Inductor_SMD:L_APV_ANR6020 +Inductor_SMD:L_APV_ANR6028 +Inductor_SMD:L_APV_ANR6045 +Inductor_SMD:L_APV_ANR8040 +Inductor_SMD:L_APV_ANR8065 +Inductor_SMD:L_APV_APH0412 +Inductor_SMD:L_APV_APH0420 +Inductor_SMD:L_APV_APH0518 +Inductor_SMD:L_APV_APH0530 +Inductor_SMD:L_APV_APH0615 +Inductor_SMD:L_APV_APH0618 +Inductor_SMD:L_APV_APH0620 +Inductor_SMD:L_APV_APH0624 +Inductor_SMD:L_APV_APH0630 +Inductor_SMD:L_APV_APH0640 +Inductor_SMD:L_APV_APH0650 +Inductor_SMD:L_APV_APH0840 +Inductor_SMD:L_APV_APH0850 +Inductor_SMD:L_APV_APH1030 +Inductor_SMD:L_APV_APH1040 +Inductor_SMD:L_APV_APH1050 +Inductor_SMD:L_APV_APH1240 +Inductor_SMD:L_APV_APH1250 +Inductor_SMD:L_APV_APH1260 +Inductor_SMD:L_APV_APH1265 +Inductor_SMD:L_APV_APH1770 +Inductor_SMD:L_APV_APH2213 +Inductor_SMD:L_AVX_LMLP07A7 +Inductor_SMD:L_Bourns-SRN1060 +Inductor_SMD:L_Bourns-SRN4018 +Inductor_SMD:L_Bourns-SRN6028 +Inductor_SMD:L_Bourns-SRN8040_8x8.15mm +Inductor_SMD:L_Bourns-SRR1005 +Inductor_SMD:L_Bourns-SRU1028_10.0x10.0mm +Inductor_SMD:L_Bourns-SRU8028_8.0x8.0mm +Inductor_SMD:L_Bourns-SRU8043 +Inductor_SMD:L_Bourns_SDR0604 +Inductor_SMD:L_Bourns_SDR1806 +Inductor_SMD:L_Bourns_SRF1260 +Inductor_SMD:L_Bourns_SRN6045TA +Inductor_SMD:L_Bourns_SRN8040TA +Inductor_SMD:L_Bourns_SRP1038C_10.0x10.0mm +Inductor_SMD:L_Bourns_SRP1050WA +Inductor_SMD:L_Bourns_SRP1245A +Inductor_SMD:L_Bourns_SRP1770TA_16.9x16.9mm +Inductor_SMD:L_Bourns_SRP2313AA +Inductor_SMD:L_Bourns_SRP5030T +Inductor_SMD:L_Bourns_SRP6060FA +Inductor_SMD:L_Bourns_SRP7028A_7.3x6.6mm +Inductor_SMD:L_Bourns_SRR1208_12.7x12.7mm +Inductor_SMD:L_Bourns_SRR1210A +Inductor_SMD:L_Bourns_SRR1260 +Inductor_SMD:L_Bourns_SRU5016_5.2x5.2mm +Inductor_SMD:L_Cenker_CKCS201610 +Inductor_SMD:L_Cenker_CKCS252010 +Inductor_SMD:L_Cenker_CKCS252012 +Inductor_SMD:L_Cenker_CKCS3012 +Inductor_SMD:L_Cenker_CKCS3015 +Inductor_SMD:L_Cenker_CKCS4018 +Inductor_SMD:L_Cenker_CKCS4020 +Inductor_SMD:L_Cenker_CKCS4030 +Inductor_SMD:L_Cenker_CKCS5020 +Inductor_SMD:L_Cenker_CKCS5040 +Inductor_SMD:L_Cenker_CKCS6020 +Inductor_SMD:L_Cenker_CKCS6028 +Inductor_SMD:L_Cenker_CKCS6045 +Inductor_SMD:L_Cenker_CKCS8040 +Inductor_SMD:L_Cenker_CKCS8060 +Inductor_SMD:L_Cenker_CKCS8080 +Inductor_SMD:L_Changjiang_FNR252010S +Inductor_SMD:L_Changjiang_FNR252012S +Inductor_SMD:L_Changjiang_FNR3010S +Inductor_SMD:L_Changjiang_FNR3012S +Inductor_SMD:L_Changjiang_FNR3015S +Inductor_SMD:L_Changjiang_FNR3021S +Inductor_SMD:L_Changjiang_FNR4010S +Inductor_SMD:L_Changjiang_FNR4012S +Inductor_SMD:L_Changjiang_FNR4015S +Inductor_SMD:L_Changjiang_FNR4018S +Inductor_SMD:L_Changjiang_FNR4020S +Inductor_SMD:L_Changjiang_FNR4026S +Inductor_SMD:L_Changjiang_FNR4030S +Inductor_SMD:L_Changjiang_FNR5012S +Inductor_SMD:L_Changjiang_FNR5015S +Inductor_SMD:L_Changjiang_FNR5020S +Inductor_SMD:L_Changjiang_FNR5030S +Inductor_SMD:L_Changjiang_FNR5040S +Inductor_SMD:L_Changjiang_FNR5045S +Inductor_SMD:L_Changjiang_FNR6020S +Inductor_SMD:L_Changjiang_FNR6028S +Inductor_SMD:L_Changjiang_FNR6040S +Inductor_SMD:L_Changjiang_FNR6045S +Inductor_SMD:L_Changjiang_FNR8040S +Inductor_SMD:L_Changjiang_FNR8050S +Inductor_SMD:L_Changjiang_FNR8065S +Inductor_SMD:L_Changjiang_FXL0412 +Inductor_SMD:L_Changjiang_FXL0420 +Inductor_SMD:L_Changjiang_FXL0518 +Inductor_SMD:L_Changjiang_FXL0530 +Inductor_SMD:L_Changjiang_FXL0615 +Inductor_SMD:L_Changjiang_FXL0618 +Inductor_SMD:L_Changjiang_FXL0624 +Inductor_SMD:L_Changjiang_FXL0630 +Inductor_SMD:L_Changjiang_FXL0640 +Inductor_SMD:L_Changjiang_FXL0650 +Inductor_SMD:L_Changjiang_FXL0840 +Inductor_SMD:L_Changjiang_FXL1030 +Inductor_SMD:L_Changjiang_FXL1040 +Inductor_SMD:L_Changjiang_FXL1050 +Inductor_SMD:L_Changjiang_FXL1340 +Inductor_SMD:L_Changjiang_FXL1350 +Inductor_SMD:L_Changjiang_FXL1360 +Inductor_SMD:L_Changjiang_FXL1365 +Inductor_SMD:L_Changjiang_FXL1770 +Inductor_SMD:L_Changjiang_FXL2213 +Inductor_SMD:L_Chilisin_BMRA00040415 +Inductor_SMD:L_Chilisin_BMRA00040420 +Inductor_SMD:L_Chilisin_BMRA00050520 +Inductor_SMD:L_Chilisin_BMRA00050530 +Inductor_SMD:L_Chilisin_BMRB00050512 +Inductor_SMD:L_Chilisin_BMRB00050518-B +Inductor_SMD:L_Chilisin_BMRB00050518 +Inductor_SMD:L_Chilisin_BMRB00060612 +Inductor_SMD:L_Chilisin_BMRB00060618 +Inductor_SMD:L_Chilisin_BMRB00060624 +Inductor_SMD:L_Chilisin_BMRB00060650 +Inductor_SMD:L_Chilisin_BMRF00101040 +Inductor_SMD:L_Chilisin_BMRF00131350 +Inductor_SMD:L_Chilisin_BMRF00131360 +Inductor_SMD:L_Chilisin_BMRF00171770 +Inductor_SMD:L_Chilisin_BMRG00101030 +Inductor_SMD:L_Chilisin_BMRG00131360 +Inductor_SMD:L_Chilisin_BMRx00040412 +Inductor_SMD:L_Chilisin_BMRx00050512-B +Inductor_SMD:L_Chilisin_BMRx00050515 +Inductor_SMD:L_Chilisin_BMRx00060615 +Inductor_SMD:L_Chilisin_BMRx00060630 +Inductor_SMD:L_Coilcraft_1515SQ-47N +Inductor_SMD:L_Coilcraft_1515SQ-68N +Inductor_SMD:L_Coilcraft_1515SQ-82N +Inductor_SMD:L_Coilcraft_2222SQ-111 +Inductor_SMD:L_Coilcraft_2222SQ-131 +Inductor_SMD:L_Coilcraft_2222SQ-161 +Inductor_SMD:L_Coilcraft_2222SQ-181 +Inductor_SMD:L_Coilcraft_2222SQ-221 +Inductor_SMD:L_Coilcraft_2222SQ-271 +Inductor_SMD:L_Coilcraft_2222SQ-301 +Inductor_SMD:L_Coilcraft_2222SQ-90N +Inductor_SMD:L_Coilcraft_2929SQ-331 +Inductor_SMD:L_Coilcraft_2929SQ-361 +Inductor_SMD:L_Coilcraft_2929SQ-391 +Inductor_SMD:L_Coilcraft_2929SQ-431 +Inductor_SMD:L_Coilcraft_2929SQ-501 +Inductor_SMD:L_Coilcraft_LPS3010 +Inductor_SMD:L_Coilcraft_LPS3314 +Inductor_SMD:L_Coilcraft_LPS4018 +Inductor_SMD:L_Coilcraft_LPS4414 +Inductor_SMD:L_Coilcraft_LPS5030 +Inductor_SMD:L_Coilcraft_MOS6020-XXX +Inductor_SMD:L_Coilcraft_MSS1038-XXX +Inductor_SMD:L_Coilcraft_MSS1038T-XXX +Inductor_SMD:L_Coilcraft_MSS1048-XXX +Inductor_SMD:L_Coilcraft_MSS1048T-XXX +Inductor_SMD:L_Coilcraft_MSS1210-XXX +Inductor_SMD:L_Coilcraft_MSS1210H-XXX +Inductor_SMD:L_Coilcraft_MSS1246-XXX +Inductor_SMD:L_Coilcraft_MSS1246H-XXX +Inductor_SMD:L_Coilcraft_MSS1246T-XXX +Inductor_SMD:L_Coilcraft_MSS1260-XXX +Inductor_SMD:L_Coilcraft_MSS1260H-XXX +Inductor_SMD:L_Coilcraft_MSS1260T-XXX +Inductor_SMD:L_Coilcraft_MSS1278-XXX +Inductor_SMD:L_Coilcraft_MSS1278H-XXX +Inductor_SMD:L_Coilcraft_MSS1278T-XXX +Inductor_SMD:L_Coilcraft_MSS1514V-XXX +Inductor_SMD:L_Coilcraft_MSS1583-XXX +Inductor_SMD:L_Coilcraft_MSS1812T-XXX +Inductor_SMD:L_Coilcraft_MSS7348-XXX +Inductor_SMD:L_Coilcraft_XAL1010-XXX +Inductor_SMD:L_Coilcraft_XAL1030-XXX +Inductor_SMD:L_Coilcraft_XAL1060-XXX +Inductor_SMD:L_Coilcraft_XAL1350-XXX +Inductor_SMD:L_Coilcraft_XAL1510-103 +Inductor_SMD:L_Coilcraft_XAL1510-153 +Inductor_SMD:L_Coilcraft_XAL1510-223 +Inductor_SMD:L_Coilcraft_XAL1510-333 +Inductor_SMD:L_Coilcraft_XAL1510-472 +Inductor_SMD:L_Coilcraft_XAL1510-682 +Inductor_SMD:L_Coilcraft_XAL1510-822 +Inductor_SMD:L_Coilcraft_XAL1513-153 +Inductor_SMD:L_Coilcraft_XAL1580-102 +Inductor_SMD:L_Coilcraft_XAL1580-132 +Inductor_SMD:L_Coilcraft_XAL1580-182 +Inductor_SMD:L_Coilcraft_XAL1580-202 +Inductor_SMD:L_Coilcraft_XAL1580-302 +Inductor_SMD:L_Coilcraft_XAL1580-401 +Inductor_SMD:L_Coilcraft_XAL1580-452 +Inductor_SMD:L_Coilcraft_XAL1580-532 +Inductor_SMD:L_Coilcraft_XAL1580-612 +Inductor_SMD:L_Coilcraft_XAL1580-741 +Inductor_SMD:L_Coilcraft_XAL4020-XXX +Inductor_SMD:L_Coilcraft_XAL4030-XXX +Inductor_SMD:L_Coilcraft_XAL4040-XXX +Inductor_SMD:L_Coilcraft_XAL5020-XXX +Inductor_SMD:L_Coilcraft_XAL5030-XXX +Inductor_SMD:L_Coilcraft_XAL5050-XXX +Inductor_SMD:L_Coilcraft_XAL6020-XXX +Inductor_SMD:L_Coilcraft_XAL6030-XXX +Inductor_SMD:L_Coilcraft_XAL6060-XXX +Inductor_SMD:L_Coilcraft_XAL7020-102 +Inductor_SMD:L_Coilcraft_XAL7020-122 +Inductor_SMD:L_Coilcraft_XAL7020-151 +Inductor_SMD:L_Coilcraft_XAL7020-152 +Inductor_SMD:L_Coilcraft_XAL7020-222 +Inductor_SMD:L_Coilcraft_XAL7020-271 +Inductor_SMD:L_Coilcraft_XAL7020-331 +Inductor_SMD:L_Coilcraft_XAL7020-471 +Inductor_SMD:L_Coilcraft_XAL7020-681 +Inductor_SMD:L_Coilcraft_XAL7030-102 +Inductor_SMD:L_Coilcraft_XAL7030-103 +Inductor_SMD:L_Coilcraft_XAL7030-152 +Inductor_SMD:L_Coilcraft_XAL7030-161 +Inductor_SMD:L_Coilcraft_XAL7030-222 +Inductor_SMD:L_Coilcraft_XAL7030-272 +Inductor_SMD:L_Coilcraft_XAL7030-301 +Inductor_SMD:L_Coilcraft_XAL7030-332 +Inductor_SMD:L_Coilcraft_XAL7030-472 +Inductor_SMD:L_Coilcraft_XAL7030-562 +Inductor_SMD:L_Coilcraft_XAL7030-601 +Inductor_SMD:L_Coilcraft_XAL7030-682 +Inductor_SMD:L_Coilcraft_XAL7030-822 +Inductor_SMD:L_Coilcraft_XAL7050-XXX +Inductor_SMD:L_Coilcraft_XAL7070-XXX +Inductor_SMD:L_Coilcraft_XAL8050-223 +Inductor_SMD:L_Coilcraft_XAL8080-XXX +Inductor_SMD:L_Coilcraft_XFL2010 +Inductor_SMD:L_Coilcraft_XxL4020 +Inductor_SMD:L_Coilcraft_XxL4030 +Inductor_SMD:L_Coilcraft_XxL4040 +Inductor_SMD:L_CommonModeChoke_Coilcraft_0603USB +Inductor_SMD:L_CommonModeChoke_Coilcraft_0805USB +Inductor_SMD:L_CommonModeChoke_Coilcraft_1812CAN +Inductor_SMD:L_CommonModeChoke_Murata_DLW5BTMxxxSQ2x_5x5mm +Inductor_SMD:L_CommonModeChoke_TDK_ACM2520-2P +Inductor_SMD:L_CommonModeChoke_TDK_ACM2520-3P +Inductor_SMD:L_CommonModeChoke_TDK_ACM7060 +Inductor_SMD:L_CommonModeChoke_Wuerth_WE-SL5 +Inductor_SMD:L_CommonMode_Delevan_4222 +Inductor_SMD:L_CommonMode_Wuerth_WE-SL2 +Inductor_SMD:L_CommonMode_Wurth_WE-CNSW-1206 +Inductor_SMD:L_Eaton_MCL2012V1 +Inductor_SMD:L_Fastron_PISN +Inductor_SMD:L_Fastron_PISN_Handsoldering +Inductor_SMD:L_Fastron_PISR +Inductor_SMD:L_Fastron_PISR_Handsoldering +Inductor_SMD:L_Ferrocore_DLG-0302 +Inductor_SMD:L_Ferrocore_DLG-0403 +Inductor_SMD:L_Ferrocore_DLG-0504 +Inductor_SMD:L_Ferrocore_DLG-0703 +Inductor_SMD:L_Ferrocore_DLG-0705 +Inductor_SMD:L_Ferrocore_DLG-1004 +Inductor_SMD:L_Ferrocore_DLG-1005 +Inductor_SMD:L_KOHERelec_MDA5030 +Inductor_SMD:L_KOHERelec_MDA7030 +Inductor_SMD:L_Murata_DEM35xxC +Inductor_SMD:L_Murata_DFE201610P +Inductor_SMD:L_Murata_LQH2MCNxxxx02_2.0x1.6mm +Inductor_SMD:L_Murata_LQH55DN_5.7x5.0mm +Inductor_SMD:L_Neosid_Air-Coil_SML_1turn_HDM0131A +Inductor_SMD:L_Neosid_Air-Coil_SML_2turn_HAM0231A +Inductor_SMD:L_Neosid_Air-Coil_SML_2turn_HDM0231A +Inductor_SMD:L_Neosid_Air-Coil_SML_3turn_HAM0331A +Inductor_SMD:L_Neosid_Air-Coil_SML_3turn_HDM0331A +Inductor_SMD:L_Neosid_Air-Coil_SML_4turn_HAM0431A +Inductor_SMD:L_Neosid_Air-Coil_SML_4turn_HDM0431A +Inductor_SMD:L_Neosid_Air-Coil_SML_5turn_HAM0531A +Inductor_SMD:L_Neosid_Air-Coil_SML_5turn_HDM0531A +Inductor_SMD:L_Neosid_Air-Coil_SML_6-10turn_HAM0631A-HAM1031A +Inductor_SMD:L_Neosid_Air-Coil_SML_6-10turn_HDM0431A-HDM1031A +Inductor_SMD:L_Neosid_Air-Coil_SML_6turn_HAM0631A +Inductor_SMD:L_Neosid_MicroCoil_Ms36-L +Inductor_SMD:L_Neosid_Ms42 +Inductor_SMD:L_Neosid_Ms50 +Inductor_SMD:L_Neosid_Ms50T +Inductor_SMD:L_Neosid_Ms85 +Inductor_SMD:L_Neosid_Ms85T +Inductor_SMD:L_Neosid_Ms95 +Inductor_SMD:L_Neosid_Ms95a +Inductor_SMD:L_Neosid_Ms95T +Inductor_SMD:L_Neosid_SM-NE127 +Inductor_SMD:L_Neosid_SM-NE127_HandSoldering +Inductor_SMD:L_Neosid_SM-NE150 +Inductor_SMD:L_Neosid_SM-NE95H +Inductor_SMD:L_Neosid_SM-PIC0512H +Inductor_SMD:L_Neosid_SM-PIC0602H +Inductor_SMD:L_Neosid_SM-PIC0612H +Inductor_SMD:L_Neosid_SM-PIC1004H +Inductor_SMD:L_Neosid_SMS-ME3010 +Inductor_SMD:L_Neosid_SMS-ME3015 +Inductor_SMD:L_Neosid_SMs42 +Inductor_SMD:L_Neosid_SMs50 +Inductor_SMD:L_Neosid_SMs85 +Inductor_SMD:L_Neosid_SMs95_SMs95p +Inductor_SMD:L_Pulse_P059x +Inductor_SMD:L_Pulse_PA4320 +Inductor_SMD:L_Pulse_PA4332 +Inductor_SMD:L_Pulse_PA4340 +Inductor_SMD:L_Pulse_PA4341 +Inductor_SMD:L_Pulse_PA4344 +Inductor_SMD:L_Pulse_PA4349 +Inductor_SMD:L_Pulse_PA5402 +Inductor_SMD:L_Sagami_CER1242B +Inductor_SMD:L_Sagami_CER1257B +Inductor_SMD:L_Sagami_CER1277B +Inductor_SMD:L_Sagami_CWR1242C +Inductor_SMD:L_Sagami_CWR1257C +Inductor_SMD:L_Sagami_CWR1277C +Inductor_SMD:L_SigTra_SC3316F +Inductor_SMD:L_SOREDE_SNR.1050_10x10x5mm +Inductor_SMD:L_Sumida_CDMC6D28_7.25x6.5mm +Inductor_SMD:L_Sumida_CR75 +Inductor_SMD:L_Sunlord_MWSA0402S +Inductor_SMD:L_Sunlord_MWSA0412S +Inductor_SMD:L_Sunlord_MWSA0503S +Inductor_SMD:L_Sunlord_MWSA0518S +Inductor_SMD:L_Sunlord_MWSA0602S +Inductor_SMD:L_Sunlord_MWSA0603S +Inductor_SMD:L_Sunlord_MWSA0604S +Inductor_SMD:L_Sunlord_MWSA0605S +Inductor_SMD:L_Sunlord_MWSA0615S +Inductor_SMD:L_Sunlord_MWSA0618S +Inductor_SMD:L_Sunlord_MWSA0624S +Inductor_SMD:L_Sunlord_MWSA0804S +Inductor_SMD:L_Sunlord_MWSA1003S +Inductor_SMD:L_Sunlord_MWSA1004S +Inductor_SMD:L_Sunlord_MWSA1005S +Inductor_SMD:L_Sunlord_MWSA1204S-100 +Inductor_SMD:L_Sunlord_MWSA1204S-150 +Inductor_SMD:L_Sunlord_MWSA1204S-1R0 +Inductor_SMD:L_Sunlord_MWSA1204S-1R5 +Inductor_SMD:L_Sunlord_MWSA1204S-220 +Inductor_SMD:L_Sunlord_MWSA1204S-2R2 +Inductor_SMD:L_Sunlord_MWSA1204S-3R3 +Inductor_SMD:L_Sunlord_MWSA1204S-4R7 +Inductor_SMD:L_Sunlord_MWSA1204S-6R8 +Inductor_SMD:L_Sunlord_MWSA1204S-R22 +Inductor_SMD:L_Sunlord_MWSA1204S-R47 +Inductor_SMD:L_Sunlord_MWSA1204S-R68 +Inductor_SMD:L_Sunlord_MWSA1204S-R82 +Inductor_SMD:L_Sunlord_MWSA1205S-100 +Inductor_SMD:L_Sunlord_MWSA1205S-150 +Inductor_SMD:L_Sunlord_MWSA1205S-1R0 +Inductor_SMD:L_Sunlord_MWSA1205S-1R5 +Inductor_SMD:L_Sunlord_MWSA1205S-220 +Inductor_SMD:L_Sunlord_MWSA1205S-2R2 +Inductor_SMD:L_Sunlord_MWSA1205S-330 +Inductor_SMD:L_Sunlord_MWSA1205S-3R3 +Inductor_SMD:L_Sunlord_MWSA1205S-470 +Inductor_SMD:L_Sunlord_MWSA1205S-4R7 +Inductor_SMD:L_Sunlord_MWSA1205S-6R8 +Inductor_SMD:L_Sunlord_MWSA1205S-R22 +Inductor_SMD:L_Sunlord_MWSA1205S-R36 +Inductor_SMD:L_Sunlord_MWSA1205S-R50 +Inductor_SMD:L_Sunlord_MWSA1205S-R68 +Inductor_SMD:L_Sunlord_MWSA1205S-R82 +Inductor_SMD:L_Sunlord_MWSA1206S-100 +Inductor_SMD:L_Sunlord_MWSA1206S-101 +Inductor_SMD:L_Sunlord_MWSA1206S-120 +Inductor_SMD:L_Sunlord_MWSA1206S-121 +Inductor_SMD:L_Sunlord_MWSA1206S-150 +Inductor_SMD:L_Sunlord_MWSA1206S-151 +Inductor_SMD:L_Sunlord_MWSA1206S-180 +Inductor_SMD:L_Sunlord_MWSA1206S-1R5 +Inductor_SMD:L_Sunlord_MWSA1206S-220 +Inductor_SMD:L_Sunlord_MWSA1206S-270 +Inductor_SMD:L_Sunlord_MWSA1206S-2R2 +Inductor_SMD:L_Sunlord_MWSA1206S-330 +Inductor_SMD:L_Sunlord_MWSA1206S-3R3 +Inductor_SMD:L_Sunlord_MWSA1206S-470 +Inductor_SMD:L_Sunlord_MWSA1206S-4R7 +Inductor_SMD:L_Sunlord_MWSA1206S-5R6 +Inductor_SMD:L_Sunlord_MWSA1206S-680 +Inductor_SMD:L_Sunlord_MWSA1206S-6R8 +Inductor_SMD:L_Sunlord_MWSA1206S-8R2 +Inductor_SMD:L_Sunlord_MWSA1206S-R68 +Inductor_SMD:L_Sunlord_MWSA1265S +Inductor_SMD:L_Sunlord_MWSA1707S +Inductor_SMD:L_Sunlord_MWSA2213S +Inductor_SMD:L_Sunlord_SWPA252010S +Inductor_SMD:L_Sunlord_SWPA252012S +Inductor_SMD:L_Sunlord_SWPA3010S +Inductor_SMD:L_Sunlord_SWPA3012S +Inductor_SMD:L_Sunlord_SWPA3015S +Inductor_SMD:L_Sunlord_SWPA4010S +Inductor_SMD:L_Sunlord_SWPA4012S +Inductor_SMD:L_Sunlord_SWPA4018S +Inductor_SMD:L_Sunlord_SWPA4020S +Inductor_SMD:L_Sunlord_SWPA4026S +Inductor_SMD:L_Sunlord_SWPA4030S +Inductor_SMD:L_Sunlord_SWPA5012S +Inductor_SMD:L_Sunlord_SWPA5020S +Inductor_SMD:L_Sunlord_SWPA5040S +Inductor_SMD:L_Sunlord_SWPA6020S +Inductor_SMD:L_Sunlord_SWPA6028S +Inductor_SMD:L_Sunlord_SWPA6040S +Inductor_SMD:L_Sunlord_SWPA6045S +Inductor_SMD:L_Sunlord_SWPA8040S +Inductor_SMD:L_Sunlord_SWRB1204S +Inductor_SMD:L_Sunlord_SWRB1205S +Inductor_SMD:L_Sunlord_SWRB1207S +Inductor_SMD:L_SXN_SMDRI124 +Inductor_SMD:L_SXN_SMDRI125 +Inductor_SMD:L_SXN_SMDRI127 +Inductor_SMD:L_SXN_SMDRI62 +Inductor_SMD:L_SXN_SMDRI64 +Inductor_SMD:L_SXN_SMDRI73 +Inductor_SMD:L_SXN_SMDRI74 +Inductor_SMD:L_TaiTech_TMPC1265_13.5x12.5mm +Inductor_SMD:L_Taiyo-Yuden_BK_Array_1206_3216Metric +Inductor_SMD:L_Taiyo-Yuden_MD-1616 +Inductor_SMD:L_Taiyo-Yuden_MD-2020 +Inductor_SMD:L_Taiyo-Yuden_MD-3030 +Inductor_SMD:L_Taiyo-Yuden_MD-4040 +Inductor_SMD:L_Taiyo-Yuden_MD-5050 +Inductor_SMD:L_Taiyo-Yuden_NR-10050_9.8x10.0mm +Inductor_SMD:L_Taiyo-Yuden_NR-10050_9.8x10.0mm_HandSoldering +Inductor_SMD:L_Taiyo-Yuden_NR-20xx +Inductor_SMD:L_Taiyo-Yuden_NR-20xx_HandSoldering +Inductor_SMD:L_Taiyo-Yuden_NR-24xx +Inductor_SMD:L_Taiyo-Yuden_NR-24xx_HandSoldering +Inductor_SMD:L_Taiyo-Yuden_NR-30xx +Inductor_SMD:L_Taiyo-Yuden_NR-30xx_HandSoldering +Inductor_SMD:L_Taiyo-Yuden_NR-40xx +Inductor_SMD:L_Taiyo-Yuden_NR-40xx_HandSoldering +Inductor_SMD:L_Taiyo-Yuden_NR-50xx +Inductor_SMD:L_Taiyo-Yuden_NR-50xx_HandSoldering +Inductor_SMD:L_Taiyo-Yuden_NR-60xx +Inductor_SMD:L_Taiyo-Yuden_NR-60xx_HandSoldering +Inductor_SMD:L_Taiyo-Yuden_NR-80xx +Inductor_SMD:L_Taiyo-Yuden_NR-80xx_HandSoldering +Inductor_SMD:L_TDK_MLZ1608 +Inductor_SMD:L_TDK_MLZ2012_h0.85mm +Inductor_SMD:L_TDK_MLZ2012_h1.25mm +Inductor_SMD:L_TDK_NLV25_2.5x2.0mm +Inductor_SMD:L_TDK_NLV32_3.2x2.5mm +Inductor_SMD:L_TDK_SLF10145 +Inductor_SMD:L_TDK_SLF10165 +Inductor_SMD:L_TDK_SLF12555 +Inductor_SMD:L_TDK_SLF12565 +Inductor_SMD:L_TDK_SLF12575 +Inductor_SMD:L_TDK_SLF6025 +Inductor_SMD:L_TDK_SLF6028 +Inductor_SMD:L_TDK_SLF6045 +Inductor_SMD:L_TDK_SLF7032 +Inductor_SMD:L_TDK_SLF7045 +Inductor_SMD:L_TDK_SLF7055 +Inductor_SMD:L_TDK_VLF10040 +Inductor_SMD:L_TDK_VLP8040 +Inductor_SMD:L_TDK_VLS6045EX_VLS6045AF +Inductor_SMD:L_TracoPower_TCK-047_5.2x5.8mm +Inductor_SMD:L_TracoPower_TCK-141 +Inductor_SMD:L_Vishay_IFSC-1515AH_4x4x1.8mm +Inductor_SMD:L_Vishay_IHLP-1212 +Inductor_SMD:L_Vishay_IHLP-1616 +Inductor_SMD:L_Vishay_IHLP-2020 +Inductor_SMD:L_Vishay_IHLP-2525 +Inductor_SMD:L_Vishay_IHLP-4040 +Inductor_SMD:L_Vishay_IHLP-5050 +Inductor_SMD:L_Vishay_IHLP-6767 +Inductor_SMD:L_Vishay_IHSM-3825 +Inductor_SMD:L_Vishay_IHSM-4825 +Inductor_SMD:L_Vishay_IHSM-5832 +Inductor_SMD:L_Vishay_IHSM-7832 +Inductor_SMD:L_Walsin_WLFM201209x +Inductor_SMD:L_Walsin_WLFM201609x +Inductor_SMD:L_Walsin_WLFM252009x +Inductor_SMD:L_Wuerth_HCF-2013 +Inductor_SMD:L_Wuerth_HCF-2815 +Inductor_SMD:L_Wuerth_HCF-2818 +Inductor_SMD:L_Wuerth_HCI-1030 +Inductor_SMD:L_Wuerth_HCI-1040 +Inductor_SMD:L_Wuerth_HCI-1050 +Inductor_SMD:L_Wuerth_HCI-1335 +Inductor_SMD:L_Wuerth_HCI-1350 +Inductor_SMD:L_Wuerth_HCI-1365 +Inductor_SMD:L_Wuerth_HCI-1890 +Inductor_SMD:L_Wuerth_HCI-2212 +Inductor_SMD:L_Wuerth_HCI-5040 +Inductor_SMD:L_Wuerth_HCI-7030 +Inductor_SMD:L_Wuerth_HCI-7040 +Inductor_SMD:L_Wuerth_HCI-7050 +Inductor_SMD:L_Wuerth_HCM-1050 +Inductor_SMD:L_Wuerth_HCM-1052 +Inductor_SMD:L_Wuerth_HCM-1070 +Inductor_SMD:L_Wuerth_HCM-1078 +Inductor_SMD:L_Wuerth_HCM-1190 +Inductor_SMD:L_Wuerth_HCM-1240 +Inductor_SMD:L_Wuerth_HCM-1350 +Inductor_SMD:L_Wuerth_HCM-1390 +Inductor_SMD:L_Wuerth_HCM-7050 +Inductor_SMD:L_Wuerth_HCM-7070 +Inductor_SMD:L_Wuerth_MAPI-1610 +Inductor_SMD:L_Wuerth_MAPI-2010 +Inductor_SMD:L_Wuerth_MAPI-2506 +Inductor_SMD:L_Wuerth_MAPI-2508 +Inductor_SMD:L_Wuerth_MAPI-2510 +Inductor_SMD:L_Wuerth_MAPI-2512 +Inductor_SMD:L_Wuerth_MAPI-3010 +Inductor_SMD:L_Wuerth_MAPI-3012 +Inductor_SMD:L_Wuerth_MAPI-3015 +Inductor_SMD:L_Wuerth_MAPI-3020 +Inductor_SMD:L_Wuerth_MAPI-4020 +Inductor_SMD:L_Wuerth_MAPI-4030 +Inductor_SMD:L_Wuerth_WE-DD-Typ-L-Typ-XL-Typ-XXL +Inductor_SMD:L_Wuerth_WE-DD-Typ-M-Typ-S +Inductor_SMD:L_Wuerth_WE-GF-1210 +Inductor_SMD:L_Wuerth_WE-PD-Typ-7345 +Inductor_SMD:L_Wuerth_WE-PD-Typ-LS +Inductor_SMD:L_Wuerth_WE-PD-Typ-LS_Handsoldering +Inductor_SMD:L_Wuerth_WE-PD-Typ-M-Typ-S +Inductor_SMD:L_Wuerth_WE-PD-Typ-M-Typ-S_Handsoldering +Inductor_SMD:L_Wuerth_WE-PD2-Typ-L +Inductor_SMD:L_Wuerth_WE-PD2-Typ-MS +Inductor_SMD:L_Wuerth_WE-PD2-Typ-XL +Inductor_SMD:L_Wuerth_WE-PD4-Typ-X +Inductor_SMD:L_Wuerth_WE-PDF +Inductor_SMD:L_Wuerth_WE-PDF_Handsoldering +Inductor_SMD:L_Wuerth_WE-TPC-3816 +Inductor_SMD:L_Wuerth_WE-XHMI-8080 +Inductor_SMD:L_Wurth_WE-CAIR-5910 +Inductor_SMD_Wurth:L_Wurth_WE-LQSH-2010 +Inductor_SMD_Wurth:L_Wurth_WE-LQSH-2512 +Inductor_SMD_Wurth:L_Wurth_WE-LQSH-3012 +Inductor_SMD_Wurth:L_Wurth_WE-LQSH-4020 +Inductor_THT:Choke_EPCOS_B82722A +Inductor_THT:Choke_Schaffner_RN102-04-14.0x14.0mm +Inductor_THT:Choke_Schaffner_RN112-04-17.7x17.1mm +Inductor_THT:Choke_Schaffner_RN114-04-22.5x21.5mm +Inductor_THT:Choke_Schaffner_RN116-04-22.5x21.5mm +Inductor_THT:Choke_Schaffner_RN122-04-28.0x27.0mm +Inductor_THT:Choke_Schaffner_RN142-04-33.1x32.5mm +Inductor_THT:Choke_Schaffner_RN143-04-33.1x32.5mm +Inductor_THT:Choke_Schaffner_RN152-04-43.0x41.8mm +Inductor_THT:Choke_Schaffner_RN202-04-8.8x18.2mm +Inductor_THT:Choke_Schaffner_RN204-04-9.0x14.0mm +Inductor_THT:Choke_Schaffner_RN212-04-12.5x18.0mm +Inductor_THT:Choke_Schaffner_RN214-04-15.5x23.0mm +Inductor_THT:Choke_Schaffner_RN216-04-15.5x23.0mm +Inductor_THT:Choke_Schaffner_RN218-04-12.5x18.0mm +Inductor_THT:Choke_Schaffner_RN222-04-18.0x31.0mm +Inductor_THT:Choke_Schaffner_RN232-04-18.0x31.0mm +Inductor_THT:Choke_Schaffner_RN242-04-18.0x31.0mm +Inductor_THT:L_Axial_L11.0mm_D4.5mm_P15.24mm_Horizontal_Fastron_MECC +Inductor_THT:L_Axial_L11.0mm_D4.5mm_P5.08mm_Vertical_Fastron_MECC +Inductor_THT:L_Axial_L11.0mm_D4.5mm_P7.62mm_Vertical_Fastron_MECC +Inductor_THT:L_Axial_L12.0mm_D5.0mm_P15.24mm_Horizontal_Fastron_MISC +Inductor_THT:L_Axial_L12.0mm_D5.0mm_P5.08mm_Vertical_Fastron_MISC +Inductor_THT:L_Axial_L12.0mm_D5.0mm_P7.62mm_Vertical_Fastron_MISC +Inductor_THT:L_Axial_L12.8mm_D5.8mm_P20.32mm_Horizontal_Fastron_HBCC +Inductor_THT:L_Axial_L12.8mm_D5.8mm_P25.40mm_Horizontal_Fastron_HBCC +Inductor_THT:L_Axial_L12.8mm_D5.8mm_P5.08mm_Vertical_Fastron_HBCC +Inductor_THT:L_Axial_L12.8mm_D5.8mm_P7.62mm_Vertical_Fastron_HBCC +Inductor_THT:L_Axial_L13.0mm_D4.5mm_P15.24mm_Horizontal_Fastron_HCCC +Inductor_THT:L_Axial_L13.0mm_D4.5mm_P5.08mm_Vertical_Fastron_HCCC +Inductor_THT:L_Axial_L13.0mm_D4.5mm_P7.62mm_Vertical_Fastron_HCCC +Inductor_THT:L_Axial_L14.0mm_D4.5mm_P15.24mm_Horizontal_Fastron_LACC +Inductor_THT:L_Axial_L14.0mm_D4.5mm_P5.08mm_Vertical_Fastron_LACC +Inductor_THT:L_Axial_L14.0mm_D4.5mm_P7.62mm_Vertical_Fastron_LACC +Inductor_THT:L_Axial_L14.5mm_D5.8mm_P20.32mm_Horizontal_Fastron_HBCC +Inductor_THT:L_Axial_L14.5mm_D5.8mm_P25.40mm_Horizontal_Fastron_HBCC +Inductor_THT:L_Axial_L14.5mm_D5.8mm_P5.08mm_Vertical_Fastron_HBCC +Inductor_THT:L_Axial_L14.5mm_D5.8mm_P7.62mm_Vertical_Fastron_HBCC +Inductor_THT:L_Axial_L16.0mm_D6.3mm_P20.32mm_Horizontal_Fastron_VHBCC +Inductor_THT:L_Axial_L16.0mm_D6.3mm_P25.40mm_Horizontal_Fastron_VHBCC +Inductor_THT:L_Axial_L16.0mm_D6.3mm_P5.08mm_Vertical_Fastron_VHBCC +Inductor_THT:L_Axial_L16.0mm_D6.3mm_P7.62mm_Vertical_Fastron_VHBCC +Inductor_THT:L_Axial_L16.0mm_D7.5mm_P20.32mm_Horizontal_Fastron_XHBCC +Inductor_THT:L_Axial_L16.0mm_D7.5mm_P25.40mm_Horizontal_Fastron_XHBCC +Inductor_THT:L_Axial_L16.0mm_D7.5mm_P5.08mm_Vertical_Fastron_XHBCC +Inductor_THT:L_Axial_L16.0mm_D7.5mm_P7.62mm_Vertical_Fastron_XHBCC +Inductor_THT:L_Axial_L16.0mm_D9.5mm_P20.32mm_Horizontal_Vishay_IM-10-37 +Inductor_THT:L_Axial_L16.0mm_D9.5mm_P5.08mm_Vertical_Vishay_IM-10-37 +Inductor_THT:L_Axial_L17.5mm_D12.0mm_P20.32mm_Horizontal_Vishay_IM-10-46 +Inductor_THT:L_Axial_L17.5mm_D12.0mm_P7.62mm_Vertical_Vishay_IM-10-46 +Inductor_THT:L_Axial_L20.0mm_D8.0mm_P25.40mm_Horizontal +Inductor_THT:L_Axial_L20.0mm_D8.0mm_P5.08mm_Vertical +Inductor_THT:L_Axial_L20.0mm_D8.0mm_P7.62mm_Vertical +Inductor_THT:L_Axial_L20.3mm_D12.1mm_P28.50mm_Horizontal_Vishay_IHA-101 +Inductor_THT:L_Axial_L20.3mm_D12.1mm_P7.62mm_Vertical_Vishay_IHA-101 +Inductor_THT:L_Axial_L20.3mm_D12.7mm_P25.40mm_Horizontal_Vishay_IHA-201 +Inductor_THT:L_Axial_L20.3mm_D12.7mm_P7.62mm_Vertical_Vishay_IHA-201 +Inductor_THT:L_Axial_L23.4mm_D12.7mm_P32.00mm_Horizontal_Vishay_IHA-203 +Inductor_THT:L_Axial_L23.4mm_D12.7mm_P7.62mm_Vertical_Vishay_IHA-203 +Inductor_THT:L_Axial_L24.0mm_D7.1mm_P30.48mm_Horizontal_Vishay_IM-10-28 +Inductor_THT:L_Axial_L24.0mm_D7.1mm_P5.08mm_Vertical_Vishay_IM-10-28 +Inductor_THT:L_Axial_L24.0mm_D7.5mm_P27.94mm_Horizontal_Fastron_MESC +Inductor_THT:L_Axial_L24.0mm_D7.5mm_P5.08mm_Vertical_Fastron_MESC +Inductor_THT:L_Axial_L24.0mm_D7.5mm_P7.62mm_Vertical_Fastron_MESC +Inductor_THT:L_Axial_L26.0mm_D10.0mm_P30.48mm_Horizontal_Fastron_77A +Inductor_THT:L_Axial_L26.0mm_D10.0mm_P5.08mm_Vertical_Fastron_77A +Inductor_THT:L_Axial_L26.0mm_D10.0mm_P7.62mm_Vertical_Fastron_77A +Inductor_THT:L_Axial_L26.0mm_D11.0mm_P30.48mm_Horizontal_Fastron_77A +Inductor_THT:L_Axial_L26.0mm_D11.0mm_P5.08mm_Vertical_Fastron_77A +Inductor_THT:L_Axial_L26.0mm_D11.0mm_P7.62mm_Vertical_Fastron_77A +Inductor_THT:L_Axial_L26.0mm_D9.0mm_P30.48mm_Horizontal_Fastron_77A +Inductor_THT:L_Axial_L26.0mm_D9.0mm_P5.08mm_Vertical_Fastron_77A +Inductor_THT:L_Axial_L26.0mm_D9.0mm_P7.62mm_Vertical_Fastron_77A +Inductor_THT:L_Axial_L26.7mm_D12.1mm_P35.00mm_Horizontal_Vishay_IHA-103 +Inductor_THT:L_Axial_L26.7mm_D12.1mm_P7.62mm_Vertical_Vishay_IHA-103 +Inductor_THT:L_Axial_L26.7mm_D14.0mm_P35.00mm_Horizontal_Vishay_IHA-104 +Inductor_THT:L_Axial_L26.7mm_D14.0mm_P7.62mm_Vertical_Vishay_IHA-104 +Inductor_THT:L_Axial_L29.9mm_D14.0mm_P38.00mm_Horizontal_Vishay_IHA-105 +Inductor_THT:L_Axial_L29.9mm_D14.0mm_P7.62mm_Vertical_Vishay_IHA-105 +Inductor_THT:L_Axial_L30.0mm_D8.0mm_P35.56mm_Horizontal_Fastron_77A +Inductor_THT:L_Axial_L30.0mm_D8.0mm_P5.08mm_Vertical_Fastron_77A +Inductor_THT:L_Axial_L30.0mm_D8.0mm_P7.62mm_Vertical_Fastron_77A +Inductor_THT:L_Axial_L5.0mm_D3.6mm_P10.00mm_Horizontal_Murata_BL01RN1A2A2 +Inductor_THT:L_Axial_L5.3mm_D2.2mm_P10.16mm_Horizontal_Vishay_IM-1 +Inductor_THT:L_Axial_L5.3mm_D2.2mm_P2.54mm_Vertical_Vishay_IM-1 +Inductor_THT:L_Axial_L5.3mm_D2.2mm_P7.62mm_Horizontal_Vishay_IM-1 +Inductor_THT:L_Axial_L6.6mm_D2.7mm_P10.16mm_Horizontal_Vishay_IM-2 +Inductor_THT:L_Axial_L6.6mm_D2.7mm_P2.54mm_Vertical_Vishay_IM-2 +Inductor_THT:L_Axial_L7.0mm_D3.3mm_P10.16mm_Horizontal_Fastron_MICC +Inductor_THT:L_Axial_L7.0mm_D3.3mm_P12.70mm_Horizontal_Fastron_MICC +Inductor_THT:L_Axial_L7.0mm_D3.3mm_P2.54mm_Vertical_Fastron_MICC +Inductor_THT:L_Axial_L7.0mm_D3.3mm_P5.08mm_Vertical_Fastron_MICC +Inductor_THT:L_Axial_L9.5mm_D4.0mm_P12.70mm_Horizontal_Fastron_SMCC +Inductor_THT:L_Axial_L9.5mm_D4.0mm_P15.24mm_Horizontal_Fastron_SMCC +Inductor_THT:L_Axial_L9.5mm_D4.0mm_P2.54mm_Vertical_Fastron_SMCC +Inductor_THT:L_Axial_L9.5mm_D4.0mm_P5.08mm_Vertical_Fastron_SMCC +Inductor_THT:L_CommonMode_PulseElectronics_PH9455x105NL_1 +Inductor_THT:L_CommonMode_PulseElectronics_PH9455x155NL_1 +Inductor_THT:L_CommonMode_PulseElectronics_PH9455x205NL_1 +Inductor_THT:L_CommonMode_PulseElectronics_PH9455x405NL_1 +Inductor_THT:L_CommonMode_PulseElectronics_PH9455x705NL_1 +Inductor_THT:L_CommonMode_PulseElectronics_PH9455xxx6NL_2 +Inductor_THT:L_CommonMode_TDK_B82746S4143A040 +Inductor_THT:L_CommonMode_TDK_B82746S6702A040 +Inductor_THT:L_CommonMode_TDK_B82747E6163A040 +Inductor_THT:L_CommonMode_TDK_B82747E6203A040 +Inductor_THT:L_CommonMode_TDK_B82747E6253A040 +Inductor_THT:L_CommonMode_TDK_B82747E6353A040 +Inductor_THT:L_CommonMode_TDK_B82767S4123N030 +Inductor_THT:L_CommonMode_TDK_B82767S4193N030 +Inductor_THT:L_CommonMode_TDK_B82767S4263N030 +Inductor_THT:L_CommonMode_Toroid_Vertical_L19.3mm_W10.8mm_Px6.35mm_Py15.24mm_Bourns_8100 +Inductor_THT:L_CommonMode_Toroid_Vertical_L21.0mm_W10.0mm_Px5.08mm_Py12.70mm_Murata_5100 +Inductor_THT:L_CommonMode_Toroid_Vertical_L24.0mm_W16.3mm_Px10.16mm_Py20.32mm_Murata_5200 +Inductor_THT:L_CommonMode_Toroid_Vertical_L30.5mm_W15.2mm_Px10.16mm_Py20.32mm_Bourns_8100 +Inductor_THT:L_CommonMode_Toroid_Vertical_L34.3mm_W20.3mm_Px15.24mm_Py22.86mm_Bourns_8100 +Inductor_THT:L_CommonMode_Toroid_Vertical_L36.8mm_W20.3mm_Px15.24mm_Py22.86mm_Bourns_8100 +Inductor_THT:L_CommonMode_Toroid_Vertical_L38.1mm_W20.3mm_Px15.24mm_Py22.86mm_Bourns_8100 +Inductor_THT:L_CommonMode_Toroid_Vertical_L39.4mm_W20.3mm_Px15.24mm_Py22.86mm_Bourns_8100 +Inductor_THT:L_CommonMode_Toroid_Vertical_L41.9mm_W20.3mm_Px15.24mm_Py22.86mm_Bourns_8100 +Inductor_THT:L_CommonMode_Toroid_Vertical_L43.2mm_W22.9mm_Px17.78mm_Py30.48mm_Bourns_8100 +Inductor_THT:L_CommonMode_VAC_T60405-S6123-X140 +Inductor_THT:L_CommonMode_VAC_T60405-S6123-X240 +Inductor_THT:L_CommonMode_VAC_T60405-S6123-X402 +Inductor_THT:L_CommonMode_Wuerth_WE-CMB-L +Inductor_THT:L_CommonMode_Wuerth_WE-CMB-M +Inductor_THT:L_CommonMode_Wuerth_WE-CMB-S +Inductor_THT:L_CommonMode_Wuerth_WE-CMB-XL +Inductor_THT:L_CommonMode_Wuerth_WE-CMB-XS +Inductor_THT:L_CommonMode_Wuerth_WE-CMB-XXL +Inductor_THT:L_Mount_Lodestone_VTM120 +Inductor_THT:L_Mount_Lodestone_VTM160 +Inductor_THT:L_Mount_Lodestone_VTM254 +Inductor_THT:L_Mount_Lodestone_VTM280 +Inductor_THT:L_Mount_Lodestone_VTM950-6 +Inductor_THT:L_Radial_D10.0mm_P5.00mm_Fastron_07M +Inductor_THT:L_Radial_D10.0mm_P5.00mm_Fastron_07P +Inductor_THT:L_Radial_D10.0mm_P5.00mm_Neosid_SD12k_style3 +Inductor_THT:L_Radial_D10.0mm_P5.00mm_Neosid_SD12_style3 +Inductor_THT:L_Radial_D10.5mm_P4.00x5.00mm_Murata_1200RS +Inductor_THT:L_Radial_D10.5mm_P5.00mm_Abacron_AISR-01 +Inductor_THT:L_Radial_D12.0mm_P10.00mm_Neosid_SD12k_style1 +Inductor_THT:L_Radial_D12.0mm_P10.00mm_Neosid_SD12_style1 +Inductor_THT:L_Radial_D12.0mm_P5.00mm_Fastron_11P +Inductor_THT:L_Radial_D12.0mm_P5.00mm_Neosid_SD12k_style2 +Inductor_THT:L_Radial_D12.0mm_P5.00mm_Neosid_SD12_style2 +Inductor_THT:L_Radial_D12.0mm_P6.00mm_Murata_1900R +Inductor_THT:L_Radial_D12.5mm_P7.00mm_Fastron_09HCP +Inductor_THT:L_Radial_D12.5mm_P9.00mm_Fastron_09HCP +Inductor_THT:L_Radial_D13.5mm_P7.00mm_Fastron_09HCP +Inductor_THT:L_Radial_D14.2mm_P10.00mm_Neosid_SD14 +Inductor_THT:L_Radial_D16.0mm_P10.00mm_Panasonic_15E-L +Inductor_THT:L_Radial_D16.8mm_P11.43mm_Vishay_IHB-1 +Inductor_THT:L_Radial_D16.8mm_P12.07mm_Vishay_IHB-1 +Inductor_THT:L_Radial_D16.8mm_P12.70mm_Vishay_IHB-1 +Inductor_THT:L_Radial_D18.0mm_P10.00mm +Inductor_THT:L_Radial_D21.0mm_P14.61mm_Vishay_IHB-2 +Inductor_THT:L_Radial_D21.0mm_P15.00mm_Vishay_IHB-2 +Inductor_THT:L_Radial_D21.0mm_P15.24mm_Vishay_IHB-2 +Inductor_THT:L_Radial_D21.0mm_P15.75mm_Vishay_IHB-2 +Inductor_THT:L_Radial_D21.0mm_P19.00mm +Inductor_THT:L_Radial_D24.0mm_P24.00mm +Inductor_THT:L_Radial_D24.4mm_P22.90mm_Murata_1400series +Inductor_THT:L_Radial_D24.4mm_P23.10mm_Murata_1400series +Inductor_THT:L_Radial_D24.4mm_P23.40mm_Murata_1400series +Inductor_THT:L_Radial_D24.4mm_P23.70mm_Murata_1400series +Inductor_THT:L_Radial_D24.4mm_P23.90mm_Murata_1400series +Inductor_THT:L_Radial_D27.9mm_P18.29mm_Vishay_IHB-3 +Inductor_THT:L_Radial_D27.9mm_P19.05mm_Vishay_IHB-3 +Inductor_THT:L_Radial_D27.9mm_P20.07mm_Vishay_IHB-3 +Inductor_THT:L_Radial_D28.0mm_P29.20mm +Inductor_THT:L_Radial_D29.8mm_P28.30mm_Murata_1400series +Inductor_THT:L_Radial_D29.8mm_P28.50mm_Murata_1400series +Inductor_THT:L_Radial_D29.8mm_P28.80mm_Murata_1400series +Inductor_THT:L_Radial_D29.8mm_P29.00mm_Murata_1400series +Inductor_THT:L_Radial_D29.8mm_P29.30mm_Murata_1400series +Inductor_THT:L_Radial_D40.6mm_P26.16mm_Vishay_IHB-5 +Inductor_THT:L_Radial_D40.6mm_P27.18mm_Vishay_IHB-4 +Inductor_THT:L_Radial_D40.6mm_P27.94mm_Vishay_IHB-4 +Inductor_THT:L_Radial_D40.6mm_P27.94mm_Vishay_IHB-5 +Inductor_THT:L_Radial_D40.6mm_P28.70mm_Vishay_IHB-5 +Inductor_THT:L_Radial_D50.8mm_P33.27mm_Vishay_IHB-6 +Inductor_THT:L_Radial_D50.8mm_P34.29mm_Vishay_IHB-6 +Inductor_THT:L_Radial_D50.8mm_P35.81mm_Vishay_IHB-6 +Inductor_THT:L_Radial_D50.8mm_P36.32mm_Vishay_IHB-6 +Inductor_THT:L_Radial_D50.8mm_P38.86mm_Vishay_IHB-6 +Inductor_THT:L_Radial_D6.0mm_P4.00mm +Inductor_THT:L_Radial_D7.0mm_P3.00mm +Inductor_THT:L_Radial_D7.2mm_P3.00mm_Murata_1700 +Inductor_THT:L_Radial_D7.5mm_P3.50mm_Fastron_07P +Inductor_THT:L_Radial_D7.5mm_P5.00mm_Fastron_07P +Inductor_THT:L_Radial_D7.8mm_P5.00mm_Fastron_07HCP +Inductor_THT:L_Radial_D8.7mm_P5.00mm_Fastron_07HCP +Inductor_THT:L_Radial_D9.5mm_P5.00mm_Fastron_07HVP +Inductor_THT:L_Radial_L10.2mm_W10.2mm_Px7.62mm_Py7.62mm_Pulse_LP-30 +Inductor_THT:L_Radial_L11.5mm_W11.5mm_Px6.00mm_Py6.00mm_Neosid_NE-CPB-11EN_Drill1.3mm +Inductor_THT:L_Radial_L11.5mm_W11.5mm_Px6.00mm_Py6.00mm_Neosid_NE-CPB-11EN_Drill1.5mm +Inductor_THT:L_Radial_L11.5mm_W11.5mm_Px6.00mm_Py6.00mm_Neosid_NE-CPB-11EN_Drill1.7mm +Inductor_THT:L_Radial_L11.5mm_W11.5mm_Px6.00mm_Py6.00mm_Neosid_NE-CPB-11EN_Drill1.8mm +Inductor_THT:L_Radial_L12.6mm_W12.6mm_Px9.52mm_Py9.52mm_Pulse_LP-37 +Inductor_THT:L_Radial_L16.1mm_W16.1mm_Px7.62mm_Py12.70mm_Pulse_LP-44 +Inductor_THT:L_Radial_L7.5mm_W4.6mm_P5.00mm_Neosid_SD75 +Inductor_THT:L_Radial_L8.0mm_W8.0mm_P5.00mm_Neosid_NE-CPB-07E +Inductor_THT:L_Radial_L8.0mm_W8.0mm_P5.00mm_Neosid_SD8 +Inductor_THT:L_Radial_L9.1mm_W9.1mm_Px6.35mm_Py6.35mm_Pulse_LP-25 +Inductor_THT:L_SELF1408 +Inductor_THT:L_SELF1418 +Inductor_THT:L_Toroid_Horizontal_D11.2mm_P17.00mm_Diameter12-5mm_Amidon-T44 +Inductor_THT:L_Toroid_Horizontal_D12.7mm_P20.00mm_Diameter14-5mm_Amidon-T50 +Inductor_THT:L_Toroid_Horizontal_D16.8mm_P14.70mm_Vishay_TJ3 +Inductor_THT:L_Toroid_Horizontal_D16.8mm_P14.70mm_Vishay_TJ3_BigPads +Inductor_THT:L_Toroid_Horizontal_D17.3mm_P15.24mm_Bourns_2000 +Inductor_THT:L_Toroid_Horizontal_D21.8mm_P19.10mm_Bourns_2100 +Inductor_THT:L_Toroid_Horizontal_D21.8mm_P19.60mm_Bourns_2100 +Inductor_THT:L_Toroid_Horizontal_D22.4mm_P19.80mm_Vishay_TJ4 +Inductor_THT:L_Toroid_Horizontal_D24.1mm_P21.80mm_Bourns_2200 +Inductor_THT:L_Toroid_Horizontal_D24.1mm_P23.10mm_Bourns_2200 +Inductor_THT:L_Toroid_Horizontal_D25.4mm_P22.90mm_Vishay_TJ5 +Inductor_THT:L_Toroid_Horizontal_D25.4mm_P22.90mm_Vishay_TJ5_BigPads +Inductor_THT:L_Toroid_Horizontal_D26.0mm_P5.08mm +Inductor_THT:L_Toroid_Horizontal_D28.0mm_P25.10mm_Bourns_2200 +Inductor_THT:L_Toroid_Horizontal_D28.0mm_P26.67mm_Bourns_2200 +Inductor_THT:L_Toroid_Horizontal_D3.2mm_P6.40mm_Diameter3-5mm_Amidon-T12 +Inductor_THT:L_Toroid_Horizontal_D32.5mm_P28.90mm_Bourns_2300 +Inductor_THT:L_Toroid_Horizontal_D32.5mm_P30.00mm_Bourns_2300 +Inductor_THT:L_Toroid_Horizontal_D35.1mm_P31.00mm_Vishay_TJ6 +Inductor_THT:L_Toroid_Horizontal_D4.1mm_P8.00mm_Diameter4-5mm_Amidon-T16 +Inductor_THT:L_Toroid_Horizontal_D40.0mm_P48.26mm +Inductor_THT:L_Toroid_Horizontal_D41.9mm_P37.60mm_Vishay_TJ7 +Inductor_THT:L_Toroid_Horizontal_D49.3mm_P44.60mm_Vishay_TJ8 +Inductor_THT:L_Toroid_Horizontal_D5.1mm_P9.00mm_Diameter6-5mm_Amidon-T20 +Inductor_THT:L_Toroid_Horizontal_D6.5mm_P10.00mm_Diameter7-5mm_Amidon-T25 +Inductor_THT:L_Toroid_Horizontal_D69.1mm_P63.20mm_Vishay_TJ9 +Inductor_THT:L_Toroid_Horizontal_D7.8mm_P13.00mm_Diameter9-5mm_Amidon-T30 +Inductor_THT:L_Toroid_Horizontal_D9.5mm_P15.00mm_Diameter10-5mm_Amidon-T37 +Inductor_THT:L_Toroid_Vertical_L10.0mm_W5.0mm_P5.08mm +Inductor_THT:L_Toroid_Vertical_L13.0mm_W6.5mm_P5.60mm +Inductor_THT:L_Toroid_Vertical_L14.0mm_W5.6mm_P5.30mm_Bourns_5700 +Inductor_THT:L_Toroid_Vertical_L14.0mm_W6.3mm_P4.57mm_Pulse_A +Inductor_THT:L_Toroid_Vertical_L14.7mm_W8.6mm_P5.58mm_Pulse_KM-1 +Inductor_THT:L_Toroid_Vertical_L16.0mm_W8.0mm_P7.62mm +Inductor_THT:L_Toroid_Vertical_L16.3mm_W7.1mm_P7.11mm_Pulse_H +Inductor_THT:L_Toroid_Vertical_L16.4mm_W7.6mm_P6.60mm_Vishay_TJ3 +Inductor_THT:L_Toroid_Vertical_L16.5mm_W11.4mm_P7.62mm_Pulse_KM-2 +Inductor_THT:L_Toroid_Vertical_L16.8mm_W9.2mm_P7.10mm_Vishay_TJ3 +Inductor_THT:L_Toroid_Vertical_L16.8mm_W9.2mm_P7.10mm_Vishay_TJ3_BigPads +Inductor_THT:L_Toroid_Vertical_L17.8mm_W8.1mm_P7.62mm_Bourns_5700 +Inductor_THT:L_Toroid_Vertical_L17.8mm_W9.7mm_P7.11mm_Pulse_B +Inductor_THT:L_Toroid_Vertical_L19.1mm_W8.1mm_P7.10mm_Bourns_5700 +Inductor_THT:L_Toroid_Vertical_L21.6mm_W11.4mm_P7.62mm_Pulse_KM-3 +Inductor_THT:L_Toroid_Vertical_L21.6mm_W8.4mm_P8.38mm_Pulse_G +Inductor_THT:L_Toroid_Vertical_L21.6mm_W9.1mm_P8.40mm_Bourns_5700 +Inductor_THT:L_Toroid_Vertical_L21.6mm_W9.5mm_P7.11mm_Pulse_C +Inductor_THT:L_Toroid_Vertical_L22.4mm_W10.2mm_P7.90mm_Vishay_TJ4 +Inductor_THT:L_Toroid_Vertical_L24.6mm_W15.5mm_P11.44mm_Pulse_KM-4 +Inductor_THT:L_Toroid_Vertical_L25.4mm_W14.7mm_P12.20mm_Vishay_TJ5 +Inductor_THT:L_Toroid_Vertical_L25.4mm_W14.7mm_P12.20mm_Vishay_TJ5_BigPads +Inductor_THT:L_Toroid_Vertical_L26.7mm_W14.0mm_P10.16mm_Pulse_D +Inductor_THT:L_Toroid_Vertical_L28.6mm_W14.3mm_P11.43mm_Bourns_5700 +Inductor_THT:L_Toroid_Vertical_L31.8mm_W15.9mm_P13.50mm_Bourns_5700 +Inductor_THT:L_Toroid_Vertical_L33.0mm_W17.8mm_P12.70mm_Pulse_KM-5 +Inductor_THT:L_Toroid_Vertical_L35.1mm_W21.1mm_P18.50mm_Vishay_TJ6 +Inductor_THT:L_Toroid_Vertical_L35.6mm_W17.8mm_P12.70mm_Pulse_E +Inductor_THT:L_Toroid_Vertical_L41.9mm_W17.8mm_P12.70mm_Pulse_F +Inductor_THT:L_Toroid_Vertical_L41.9mm_W19.1mm_P15.80mm_Vishay_TJ7 +Inductor_THT:L_Toroid_Vertical_L46.0mm_W19.1mm_P21.80mm_Bourns_5700 +Inductor_THT:L_Toroid_Vertical_L48.8mm_W25.4mm_P20.80mm_Vishay_TJ8 +Inductor_THT:L_Toroid_Vertical_L54.0mm_W23.8mm_P20.10mm_Bourns_5700 +Inductor_THT:L_Toroid_Vertical_L67.6mm_W36.1mm_P31.80mm_Vishay_TJ9 +Inductor_THT_Wurth:L_Wurth_WE-HCFT-2012_LeadDiameter1.2mm +Inductor_THT_Wurth:L_Wurth_WE-HCFT-2012_LeadDiameter1.5mm +Inductor_THT_Wurth:L_Wurth_WE-HCFT-2504 +Inductor_THT_Wurth:L_Wurth_WE-HCFT-3521 +Inductor_THT_Wurth:L_Wurth_WE-HCFT-3533_LeadDiameter1.8mm +Inductor_THT_Wurth:L_Wurth_WE-HCFT-3533_LeadDiameter2.0mm +Inductor_THT_Wurth:L_Wurth_WE-HCFT-3540_LeadDiameter0.8mm +Inductor_THT_Wurth:L_Wurth_WE-HCFT-3540_LeadDiameter1.3mm +Inductor_THT_Wurth:L_Wurth_WE-HCFT-3540_LeadDiameter1.5mm +Inductor_THT_Wurth:L_Wurth_WE-HCFT-3540_LeadDiameter2.0mm +Jumper:SolderJumper-2_P1.3mm_Bridged2Bar_Pad1.0x1.5mm +Jumper:SolderJumper-2_P1.3mm_Bridged2Bar_RoundedPad1.0x1.5mm +Jumper:SolderJumper-2_P1.3mm_Bridged_Pad1.0x1.5mm +Jumper:SolderJumper-2_P1.3mm_Bridged_RoundedPad1.0x1.5mm +Jumper:SolderJumper-2_P1.3mm_Open_Pad1.0x1.5mm +Jumper:SolderJumper-2_P1.3mm_Open_RoundedPad1.0x1.5mm +Jumper:SolderJumper-2_P1.3mm_Open_TrianglePad1.0x1.5mm +Jumper:SolderJumper-3_P1.3mm_Bridged12_Pad1.0x1.5mm +Jumper:SolderJumper-3_P1.3mm_Bridged12_Pad1.0x1.5mm_NumberLabels +Jumper:SolderJumper-3_P1.3mm_Bridged12_RoundedPad1.0x1.5mm +Jumper:SolderJumper-3_P1.3mm_Bridged12_RoundedPad1.0x1.5mm_NumberLabels +Jumper:SolderJumper-3_P1.3mm_Bridged2Bar12_Pad1.0x1.5mm +Jumper:SolderJumper-3_P1.3mm_Bridged2Bar12_Pad1.0x1.5mm_NumberLabels +Jumper:SolderJumper-3_P1.3mm_Bridged2Bar12_RoundedPad1.0x1.5mm +Jumper:SolderJumper-3_P1.3mm_Bridged2Bar12_RoundedPad1.0x1.5mm_NumberLabels +Jumper:SolderJumper-3_P1.3mm_Open_Pad1.0x1.5mm +Jumper:SolderJumper-3_P1.3mm_Open_Pad1.0x1.5mm_NumberLabels +Jumper:SolderJumper-3_P1.3mm_Open_RoundedPad1.0x1.5mm +Jumper:SolderJumper-3_P1.3mm_Open_RoundedPad1.0x1.5mm_NumberLabels +Jumper:SolderJumper-3_P2.0mm_Open_TrianglePad1.0x1.5mm +Jumper:SolderJumper-3_P2.0mm_Open_TrianglePad1.0x1.5mm_NumberLabels +LED_SMD:LED-APA102-2020 +LED_SMD:LED-L1T2_LUMILEDS +LED_SMD:LED_0201_0603Metric +LED_SMD:LED_0201_0603Metric_Pad0.64x0.40mm_HandSolder +LED_SMD:LED_0402_1005Metric +LED_SMD:LED_0402_1005Metric_Pad0.77x0.64mm_HandSolder +LED_SMD:LED_0603_1608Metric +LED_SMD:LED_0603_1608Metric_Pad1.05x0.95mm_HandSolder +LED_SMD:LED_0805_2012Metric +LED_SMD:LED_0805_2012Metric_Pad1.15x1.40mm_HandSolder +LED_SMD:LED_1206_3216Metric +LED_SMD:LED_1206_3216Metric_Pad1.42x1.75mm_HandSolder +LED_SMD:LED_1206_3216Metric_ReverseMount_Hole1.8x2.4mm +LED_SMD:LED_1210_3225Metric +LED_SMD:LED_1210_3225Metric_Pad1.42x2.65mm_HandSolder +LED_SMD:LED_1812_4532Metric +LED_SMD:LED_1812_4532Metric_Pad1.30x3.40mm_HandSolder +LED_SMD:LED_1W_3W_R8 +LED_SMD:LED_2010_5025Metric +LED_SMD:LED_2010_5025Metric_Pad1.52x2.65mm_HandSolder +LED_SMD:LED_2512_6332Metric +LED_SMD:LED_2512_6332Metric_Pad1.52x3.35mm_HandSolder +LED_SMD:LED_ASMB-KTF0-0A306 +LED_SMD:LED_Avago_PLCC4_3.2x2.8mm_CW +LED_SMD:LED_Avago_PLCC6_3x2.8mm +LED_SMD:LED_Cree-PLCC4_2x2mm_CW +LED_SMD:LED_Cree-PLCC4_3.2x2.8mm_CCW +LED_SMD:LED_Cree-PLCC4_5x5mm_CW +LED_SMD:LED_Cree-PLCC6_4.7x1.5mm +LED_SMD:LED_Cree-XB +LED_SMD:LED_Cree-XH +LED_SMD:LED_Cree-XHP35 +LED_SMD:LED_Cree-XHP50_12V +LED_SMD:LED_Cree-XHP50_6V +LED_SMD:LED_Cree-XHP70_12V +LED_SMD:LED_Cree-XHP70_6V +LED_SMD:LED_Cree-XP-G +LED_SMD:LED_Cree-XP +LED_SMD:LED_Cree-XQ +LED_SMD:LED_Cree-XQ_HandSoldering +LED_SMD:LED_CSP_Samsung_LH181B_2.36x2.36mm +LED_SMD:LED_Dialight_591 +LED_SMD:LED_Everlight-SMD3528_3.5x2.8mm_67-21ST +LED_SMD:LED_Inolux_IN-P55TATRGB_PLCC6_5.0x5.5mm_P1.8mm +LED_SMD:LED_Inolux_IN-PI554FCH_PLCC4_5.0x5.0mm_P3.2mm +LED_SMD:LED_Kingbright_AAA3528ESGCT +LED_SMD:LED_Kingbright_APA1606_1.6x0.6mm_Horizontal +LED_SMD:LED_Kingbright_APDA3020VBCD +LED_SMD:LED_Kingbright_APFA3010_3x1.5mm_Horizontal +LED_SMD:LED_Kingbright_APHBM2012_2x1.25mm +LED_SMD:LED_Kingbright_KPA-3010_3x2x1mm +LED_SMD:LED_Kingbright_KPBD-3224 +LED_SMD:LED_LiteOn_LTST-C19HE1WT +LED_SMD:LED_LiteOn_LTST-C235KGKRKT +LED_SMD:LED_LiteOn_LTST-C295K_1.6x0.8mm +LED_SMD:LED_LiteOn_LTST-E563C_PLCC4_5.0x5.0mm_P3.2mm +LED_SMD:LED_LiteOn_LTST-E563C_PLCC4_5.0x5.0mm_P3.2mm_HandSoldering +LED_SMD:LED_LiteOn_LTST-S326 +LED_SMD:LED_Lumex_SML-LX0303SIUPGUSB +LED_SMD:LED_Lumex_SML-LX0404SIUPGUSB +LED_SMD:LED_Luminus_MP-3030-1100_3.0x3.0mm +LED_SMD:LED_miniPLCC_2315 +LED_SMD:LED_miniPLCC_2315_Handsoldering +LED_SMD:LED_OPSCO_SK6812_PLCC4_5.0x5.0mm_P3.1mm +LED_SMD:LED_Osram_Lx_P47F_D2mm_ReverseMount +LED_SMD:LED_PLCC-2_3.4x3.0mm_AK +LED_SMD:LED_PLCC-2_3.4x3.0mm_KA +LED_SMD:LED_PLCC-2_3x2mm_AK +LED_SMD:LED_PLCC-2_3x2mm_KA +LED_SMD:LED_PLCC_2835 +LED_SMD:LED_PLCC_2835_Handsoldering +LED_SMD:LED_RGB_1210 +LED_SMD:LED_RGB_5050-6 +LED_SMD:LED_RGB_Cree-PLCC-6_6x5mm_P2.1mm +LED_SMD:LED_RGB_Everlight_EASV3015RGBA0_Horizontal +LED_SMD:LED_RGB_Getian_GT-P6PRGB4303 +LED_SMD:LED_RGB_Lumex_SML-LXT0805SIUGUBW +LED_SMD:LED_RGB_PLCC-6 +LED_SMD:LED_RGB_Wuerth-PLCC4_3.2x2.8mm_150141M173100 +LED_SMD:LED_RGB_Wuerth_150080M153000 +LED_SMD:LED_ROHM_SMLVN6 +LED_SMD:LED_SK6805_PLCC4_2.4x2.7mm_P1.3mm +LED_SMD:LED_SK6812MINI_PLCC4_3.5x3.5mm_P1.75mm +LED_SMD:LED_SK6812_EC15_1.5x1.5mm +LED_SMD:LED_SK6812_PLCC4_5.0x5.0mm_P3.2mm +LED_SMD:LED_WS2812B-2020_PLCC4_2.0x2.0mm +LED_SMD:LED_WS2812B-Mini_PLCC4_3.5x3.5mm +LED_SMD:LED_WS2812B_PLCC4_5.0x5.0mm_P3.2mm +LED_SMD:LED_WS2812_PLCC6_5.0x5.0mm_P1.6mm +LED_SMD:LED_Wurth_150044M155260 +LED_SMD:LED_Yuji_5730 +LED_THT:LED_BL-FL7680RGB +LED_THT:LED_D1.8mm_W1.8mm_H2.4mm_Horizontal_O1.27mm_Z1.6mm +LED_THT:LED_D1.8mm_W1.8mm_H2.4mm_Horizontal_O1.27mm_Z4.9mm +LED_THT:LED_D1.8mm_W1.8mm_H2.4mm_Horizontal_O1.27mm_Z8.2mm +LED_THT:LED_D1.8mm_W1.8mm_H2.4mm_Horizontal_O3.81mm_Z1.6mm +LED_THT:LED_D1.8mm_W1.8mm_H2.4mm_Horizontal_O3.81mm_Z4.9mm +LED_THT:LED_D1.8mm_W1.8mm_H2.4mm_Horizontal_O3.81mm_Z8.2mm +LED_THT:LED_D1.8mm_W1.8mm_H2.4mm_Horizontal_O6.35mm_Z1.6mm +LED_THT:LED_D1.8mm_W1.8mm_H2.4mm_Horizontal_O6.35mm_Z4.9mm +LED_THT:LED_D1.8mm_W1.8mm_H2.4mm_Horizontal_O6.35mm_Z8.2mm +LED_THT:LED_D1.8mm_W3.3mm_H2.4mm +LED_THT:LED_D10.0mm-3 +LED_THT:LED_D10.0mm +LED_THT:LED_D2.0mm_W4.0mm_H2.8mm_FlatTop +LED_THT:LED_D2.0mm_W4.8mm_H2.5mm_FlatTop +LED_THT:LED_D20.0mm +LED_THT:LED_D3.0mm-3 +LED_THT:LED_D3.0mm +LED_THT:LED_D3.0mm_Clear +LED_THT:LED_D3.0mm_FlatTop +LED_THT:LED_D3.0mm_Horizontal_O1.27mm_Z10.0mm +LED_THT:LED_D3.0mm_Horizontal_O1.27mm_Z2.0mm +LED_THT:LED_D3.0mm_Horizontal_O1.27mm_Z2.0mm_Clear +LED_THT:LED_D3.0mm_Horizontal_O1.27mm_Z2.0mm_IRBlack +LED_THT:LED_D3.0mm_Horizontal_O1.27mm_Z2.0mm_IRGrey +LED_THT:LED_D3.0mm_Horizontal_O1.27mm_Z6.0mm +LED_THT:LED_D3.0mm_Horizontal_O3.81mm_Z10.0mm +LED_THT:LED_D3.0mm_Horizontal_O3.81mm_Z2.0mm +LED_THT:LED_D3.0mm_Horizontal_O3.81mm_Z6.0mm +LED_THT:LED_D3.0mm_Horizontal_O6.35mm_Z10.0mm +LED_THT:LED_D3.0mm_Horizontal_O6.35mm_Z2.0mm +LED_THT:LED_D3.0mm_Horizontal_O6.35mm_Z6.0mm +LED_THT:LED_D3.0mm_IRBlack +LED_THT:LED_D3.0mm_IRGrey +LED_THT:LED_D4.0mm +LED_THT:LED_D5.0mm-3 +LED_THT:LED_D5.0mm-3_Horizontal_O3.81mm_Z3.0mm +LED_THT:LED_D5.0mm-4_RGB +LED_THT:LED_D5.0mm-4_RGB_Staggered_Pins +LED_THT:LED_D5.0mm-4_RGB_Wide_Pins +LED_THT:LED_D5.0mm +LED_THT:LED_D5.0mm_Clear +LED_THT:LED_D5.0mm_FlatTop +LED_THT:LED_D5.0mm_Horizontal_O1.27mm_Z15.0mm +LED_THT:LED_D5.0mm_Horizontal_O1.27mm_Z3.0mm +LED_THT:LED_D5.0mm_Horizontal_O1.27mm_Z3.0mm_Clear +LED_THT:LED_D5.0mm_Horizontal_O1.27mm_Z3.0mm_IRBlack +LED_THT:LED_D5.0mm_Horizontal_O1.27mm_Z3.0mm_IRGrey +LED_THT:LED_D5.0mm_Horizontal_O1.27mm_Z9.0mm +LED_THT:LED_D5.0mm_Horizontal_O3.81mm_Z15.0mm +LED_THT:LED_D5.0mm_Horizontal_O3.81mm_Z3.0mm +LED_THT:LED_D5.0mm_Horizontal_O3.81mm_Z9.0mm +LED_THT:LED_D5.0mm_Horizontal_O6.35mm_Z15.0mm +LED_THT:LED_D5.0mm_Horizontal_O6.35mm_Z3.0mm +LED_THT:LED_D5.0mm_Horizontal_O6.35mm_Z9.0mm +LED_THT:LED_D5.0mm_IRBlack +LED_THT:LED_D5.0mm_IRGrey +LED_THT:LED_D8.0mm-3 +LED_THT:LED_D8.0mm +LED_THT:LED_Oval_W5.2mm_H3.8mm +LED_THT:LED_Rectangular_W3.0mm_H2.0mm +LED_THT:LED_Rectangular_W3.9mm_H1.8mm +LED_THT:LED_Rectangular_W3.9mm_H1.9mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm-3Pins +LED_THT:LED_Rectangular_W5.0mm_H2.0mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm_Horizontal_O1.27mm_Z1.0mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm_Horizontal_O1.27mm_Z3.0mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm_Horizontal_O1.27mm_Z5.0mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm_Horizontal_O3.81mm_Z1.0mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm_Horizontal_O3.81mm_Z3.0mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm_Horizontal_O3.81mm_Z5.0mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm_Horizontal_O6.35mm_Z1.0mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm_Horizontal_O6.35mm_Z3.0mm +LED_THT:LED_Rectangular_W5.0mm_H2.0mm_Horizontal_O6.35mm_Z5.0mm +LED_THT:LED_Rectangular_W5.0mm_H5.0mm +LED_THT:LED_Rectangular_W7.62mm_H4.55mm_P5.08mm_R3 +LED_THT:LED_SideEmitter_Rectangular_W4.5mm_H1.6mm +LED_THT:LED_VCCLite_5381H1_6.35x6.35mm +LED_THT:LED_VCCLite_5381H3_6.35x6.35mm +LED_THT:LED_VCCLite_5381H5_6.35x6.35mm +LED_THT:LED_VCCLite_5381H7_6.35x6.35mm +Module:A20_OLINUXINO_LIME2 +Module:Adafruit_Feather +Module:Adafruit_Feather_32u4_FONA +Module:Adafruit_Feather_32u4_FONA_WithMountingHoles +Module:Adafruit_Feather_32u4_RFM +Module:Adafruit_Feather_32u4_RFM_WithMountingHoles +Module:Adafruit_Feather_M0_RFM +Module:Adafruit_Feather_M0_RFM_WithMountingHoles +Module:Adafruit_Feather_M0_Wifi +Module:Adafruit_Feather_M0_Wifi_WithMountingHoles +Module:Adafruit_Feather_WICED +Module:Adafruit_Feather_WICED_WithMountingHoles +Module:Adafruit_Feather_WithMountingHoles +Module:Adafruit_HUZZAH_ESP8266_breakout +Module:Adafruit_HUZZAH_ESP8266_breakout_WithMountingHoles +Module:Arduino_Nano +Module:Arduino_Nano_WithMountingHoles +Module:Arduino_UNO_R2 +Module:Arduino_UNO_R2_WithMountingHoles +Module:Arduino_UNO_R3 +Module:Arduino_UNO_R3_WithMountingHoles +Module:BeagleBoard_PocketBeagle +Module:Carambola2 +Module:Electrosmith_Daisy_Seed +Module:Flipper_Zero_Angled +Module:Flipper_Zero_Straight +Module:Google_Coral_SMT_TPU_Module +Module:Maple_Mini +Module:Olimex_MOD-WIFI-ESP8266-DEV +Module:Onion_Omega2+ +Module:Onion_Omega2S +Module:Pololu_Breakout-16_15.2x20.3mm +Module:RaspberryPi_Pico_Common_SMD +Module:RaspberryPi_Pico_Common_THT +Module:RaspberryPi_Pico_Common_Unspecified +Module:RaspberryPi_Pico_SMD +Module:RaspberryPi_Pico_SMD_HandSolder +Module:RaspberryPi_Pico_W_SMD +Module:RaspberryPi_Pico_W_SMD_HandSolder +Module:Raspberry_Pi_Zero_Socketed_THT_FaceDown_MountingHoles +Module:Sipeed-M1 +Module:Sipeed-M1W +Module:ST_Morpho_Connector_144_STLink +Module:ST_Morpho_Connector_144_STLink_MountingHoles +Module:Texas_EUK_R-PDSS-T7_THT +Module:Texas_EUS_R-PDSS-T5_THT +Module:Texas_EUW_R-PDSS-T7_THT +Motors:Vybronics_VZ30C1T8219732L +MountingEquipment:DINRailAdapter_3xM3_PhoenixContact_1201578 +MountingHole:MountingHole_2.1mm +MountingHole:MountingHole_2.2mm_M2 +MountingHole:MountingHole_2.2mm_M2_DIN965 +MountingHole:MountingHole_2.2mm_M2_DIN965_Pad +MountingHole:MountingHole_2.2mm_M2_DIN965_Pad_TopBottom +MountingHole:MountingHole_2.2mm_M2_DIN965_Pad_TopOnly +MountingHole:MountingHole_2.2mm_M2_ISO14580 +MountingHole:MountingHole_2.2mm_M2_ISO14580_Pad +MountingHole:MountingHole_2.2mm_M2_ISO14580_Pad_TopBottom +MountingHole:MountingHole_2.2mm_M2_ISO14580_Pad_TopOnly +MountingHole:MountingHole_2.2mm_M2_ISO7380 +MountingHole:MountingHole_2.2mm_M2_ISO7380_Pad +MountingHole:MountingHole_2.2mm_M2_ISO7380_Pad_TopBottom +MountingHole:MountingHole_2.2mm_M2_ISO7380_Pad_TopOnly +MountingHole:MountingHole_2.2mm_M2_Pad +MountingHole:MountingHole_2.2mm_M2_Pad_TopBottom +MountingHole:MountingHole_2.2mm_M2_Pad_TopOnly +MountingHole:MountingHole_2.2mm_M2_Pad_Via +MountingHole:MountingHole_2.5mm +MountingHole:MountingHole_2.5mm_Pad +MountingHole:MountingHole_2.5mm_Pad_TopBottom +MountingHole:MountingHole_2.5mm_Pad_TopOnly +MountingHole:MountingHole_2.5mm_Pad_Via +MountingHole:MountingHole_2.7mm +MountingHole:MountingHole_2.7mm_M2.5 +MountingHole:MountingHole_2.7mm_M2.5_DIN965 +MountingHole:MountingHole_2.7mm_M2.5_DIN965_Pad +MountingHole:MountingHole_2.7mm_M2.5_DIN965_Pad_TopBottom +MountingHole:MountingHole_2.7mm_M2.5_DIN965_Pad_TopOnly +MountingHole:MountingHole_2.7mm_M2.5_ISO14580 +MountingHole:MountingHole_2.7mm_M2.5_ISO14580_Pad +MountingHole:MountingHole_2.7mm_M2.5_ISO14580_Pad_TopBottom +MountingHole:MountingHole_2.7mm_M2.5_ISO14580_Pad_TopOnly +MountingHole:MountingHole_2.7mm_M2.5_ISO7380 +MountingHole:MountingHole_2.7mm_M2.5_ISO7380_Pad +MountingHole:MountingHole_2.7mm_M2.5_ISO7380_Pad_TopBottom +MountingHole:MountingHole_2.7mm_M2.5_ISO7380_Pad_TopOnly +MountingHole:MountingHole_2.7mm_M2.5_Pad +MountingHole:MountingHole_2.7mm_M2.5_Pad_TopBottom +MountingHole:MountingHole_2.7mm_M2.5_Pad_TopOnly +MountingHole:MountingHole_2.7mm_M2.5_Pad_Via +MountingHole:MountingHole_2.7mm_Pad +MountingHole:MountingHole_2.7mm_Pad_TopBottom +MountingHole:MountingHole_2.7mm_Pad_TopOnly +MountingHole:MountingHole_2.7mm_Pad_Via +MountingHole:MountingHole_2mm +MountingHole:MountingHole_3.2mm_M3 +MountingHole:MountingHole_3.2mm_M3_DIN965 +MountingHole:MountingHole_3.2mm_M3_DIN965_Pad +MountingHole:MountingHole_3.2mm_M3_DIN965_Pad_TopBottom +MountingHole:MountingHole_3.2mm_M3_DIN965_Pad_TopOnly +MountingHole:MountingHole_3.2mm_M3_ISO14580 +MountingHole:MountingHole_3.2mm_M3_ISO14580_Pad +MountingHole:MountingHole_3.2mm_M3_ISO14580_Pad_TopBottom +MountingHole:MountingHole_3.2mm_M3_ISO14580_Pad_TopOnly +MountingHole:MountingHole_3.2mm_M3_ISO7380 +MountingHole:MountingHole_3.2mm_M3_ISO7380_Pad +MountingHole:MountingHole_3.2mm_M3_ISO7380_Pad_TopBottom +MountingHole:MountingHole_3.2mm_M3_ISO7380_Pad_TopOnly +MountingHole:MountingHole_3.2mm_M3_Pad +MountingHole:MountingHole_3.2mm_M3_Pad_TopBottom +MountingHole:MountingHole_3.2mm_M3_Pad_TopOnly +MountingHole:MountingHole_3.2mm_M3_Pad_Via +MountingHole:MountingHole_3.5mm +MountingHole:MountingHole_3.5mm_Pad +MountingHole:MountingHole_3.5mm_Pad_TopBottom +MountingHole:MountingHole_3.5mm_Pad_TopOnly +MountingHole:MountingHole_3.5mm_Pad_Via +MountingHole:MountingHole_3.7mm +MountingHole:MountingHole_3.7mm_Pad +MountingHole:MountingHole_3.7mm_Pad_TopBottom +MountingHole:MountingHole_3.7mm_Pad_TopOnly +MountingHole:MountingHole_3.7mm_Pad_Via +MountingHole:MountingHole_3mm +MountingHole:MountingHole_3mm_Pad +MountingHole:MountingHole_3mm_Pad_TopBottom +MountingHole:MountingHole_3mm_Pad_TopOnly +MountingHole:MountingHole_3mm_Pad_Via +MountingHole:MountingHole_4.3mm_M4 +MountingHole:MountingHole_4.3mm_M4_DIN965 +MountingHole:MountingHole_4.3mm_M4_DIN965_Pad +MountingHole:MountingHole_4.3mm_M4_DIN965_Pad_TopBottom +MountingHole:MountingHole_4.3mm_M4_DIN965_Pad_TopOnly +MountingHole:MountingHole_4.3mm_M4_ISO14580 +MountingHole:MountingHole_4.3mm_M4_ISO14580_Pad +MountingHole:MountingHole_4.3mm_M4_ISO14580_Pad_TopBottom +MountingHole:MountingHole_4.3mm_M4_ISO14580_Pad_TopOnly +MountingHole:MountingHole_4.3mm_M4_ISO7380 +MountingHole:MountingHole_4.3mm_M4_ISO7380_Pad +MountingHole:MountingHole_4.3mm_M4_ISO7380_Pad_TopBottom +MountingHole:MountingHole_4.3mm_M4_ISO7380_Pad_TopOnly +MountingHole:MountingHole_4.3mm_M4_Pad +MountingHole:MountingHole_4.3mm_M4_Pad_TopBottom +MountingHole:MountingHole_4.3mm_M4_Pad_TopOnly +MountingHole:MountingHole_4.3mm_M4_Pad_Via +MountingHole:MountingHole_4.3x6.2mm_M4_Pad +MountingHole:MountingHole_4.3x6.2mm_M4_Pad_Via +MountingHole:MountingHole_4.5mm +MountingHole:MountingHole_4.5mm_Pad +MountingHole:MountingHole_4.5mm_Pad_TopBottom +MountingHole:MountingHole_4.5mm_Pad_TopOnly +MountingHole:MountingHole_4.5mm_Pad_Via +MountingHole:MountingHole_4mm +MountingHole:MountingHole_4mm_Pad +MountingHole:MountingHole_4mm_Pad_TopBottom +MountingHole:MountingHole_4mm_Pad_TopOnly +MountingHole:MountingHole_4mm_Pad_Via +MountingHole:MountingHole_5.3mm_M5 +MountingHole:MountingHole_5.3mm_M5_DIN965 +MountingHole:MountingHole_5.3mm_M5_DIN965_Pad +MountingHole:MountingHole_5.3mm_M5_DIN965_Pad_TopBottom +MountingHole:MountingHole_5.3mm_M5_DIN965_Pad_TopOnly +MountingHole:MountingHole_5.3mm_M5_ISO14580 +MountingHole:MountingHole_5.3mm_M5_ISO14580_Pad +MountingHole:MountingHole_5.3mm_M5_ISO14580_Pad_TopBottom +MountingHole:MountingHole_5.3mm_M5_ISO14580_Pad_TopOnly +MountingHole:MountingHole_5.3mm_M5_ISO7380 +MountingHole:MountingHole_5.3mm_M5_ISO7380_Pad +MountingHole:MountingHole_5.3mm_M5_ISO7380_Pad_TopBottom +MountingHole:MountingHole_5.3mm_M5_ISO7380_Pad_TopOnly +MountingHole:MountingHole_5.3mm_M5_Pad +MountingHole:MountingHole_5.3mm_M5_Pad_TopBottom +MountingHole:MountingHole_5.3mm_M5_Pad_TopOnly +MountingHole:MountingHole_5.3mm_M5_Pad_Via +MountingHole:MountingHole_5.5mm +MountingHole:MountingHole_5.5mm_Pad +MountingHole:MountingHole_5.5mm_Pad_TopBottom +MountingHole:MountingHole_5.5mm_Pad_TopOnly +MountingHole:MountingHole_5.5mm_Pad_Via +MountingHole:MountingHole_5mm +MountingHole:MountingHole_5mm_Pad +MountingHole:MountingHole_5mm_Pad_TopBottom +MountingHole:MountingHole_5mm_Pad_TopOnly +MountingHole:MountingHole_5mm_Pad_Via +MountingHole:MountingHole_6.4mm_M6 +MountingHole:MountingHole_6.4mm_M6_DIN965 +MountingHole:MountingHole_6.4mm_M6_DIN965_Pad +MountingHole:MountingHole_6.4mm_M6_DIN965_Pad_TopBottom +MountingHole:MountingHole_6.4mm_M6_DIN965_Pad_TopOnly +MountingHole:MountingHole_6.4mm_M6_ISO14580 +MountingHole:MountingHole_6.4mm_M6_ISO14580_Pad +MountingHole:MountingHole_6.4mm_M6_ISO14580_Pad_TopBottom +MountingHole:MountingHole_6.4mm_M6_ISO14580_Pad_TopOnly +MountingHole:MountingHole_6.4mm_M6_ISO7380 +MountingHole:MountingHole_6.4mm_M6_ISO7380_Pad +MountingHole:MountingHole_6.4mm_M6_ISO7380_Pad_TopBottom +MountingHole:MountingHole_6.4mm_M6_ISO7380_Pad_TopOnly +MountingHole:MountingHole_6.4mm_M6_Pad +MountingHole:MountingHole_6.4mm_M6_Pad_TopBottom +MountingHole:MountingHole_6.4mm_M6_Pad_TopOnly +MountingHole:MountingHole_6.4mm_M6_Pad_Via +MountingHole:MountingHole_6.5mm +MountingHole:MountingHole_6.5mm_Pad +MountingHole:MountingHole_6.5mm_Pad_TopBottom +MountingHole:MountingHole_6.5mm_Pad_TopOnly +MountingHole:MountingHole_6.5mm_Pad_Via +MountingHole:MountingHole_6mm +MountingHole:MountingHole_6mm_Pad +MountingHole:MountingHole_6mm_Pad_TopBottom +MountingHole:MountingHole_6mm_Pad_TopOnly +MountingHole:MountingHole_6mm_Pad_Via +MountingHole:MountingHole_8.4mm_M8 +MountingHole:MountingHole_8.4mm_M8_Pad +MountingHole:MountingHole_8.4mm_M8_Pad_TopBottom +MountingHole:MountingHole_8.4mm_M8_Pad_TopOnly +MountingHole:MountingHole_8.4mm_M8_Pad_Via +MountingHole:ToolingHole_1.152mm +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H10mm_9771100360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H11mm_9771110360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H12mm_9771120360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H13mm_9771130360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H14mm_9771140360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H15mm_9771150360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H5mm_9771050360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H6mm_9771060360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H7mm_9771070360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H8mm_9771080360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSE-ExternalM3_H9mm_9771090360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H10mm_9774100482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H1mm_9774010482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H2mm_9774020482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H3mm_9774030482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H4mm_9774040482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H5mm_9774050482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H6mm_9774060482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H7mm_9774070482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H8mm_9774080482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-4.5mm_H9mm_9774090482 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H1.5mm_9774015633 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H1mm_9774010633 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H2.5mm_9774025633 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H2.5mm_ThreadDepth1.5mm_97730256332 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H2.5mm_ThreadDepth1.5mm_NoNPTH_97730256330 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H2mm_9774020633 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H3.5mm_ThreadDepth2mm_97730356332 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H3.5mm_ThreadDepth2mm_97730356334 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H3.5mm_ThreadDepth2mm_NoNPTH_97730356330 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H3mm_9774030633 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H3mm_ThreadDepth1.8mm_97730306332 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H3mm_ThreadDepth1.8mm_NoNPTH_97730306330 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H4.5mm_ThreadDepth2mm_97730456332 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H4.5mm_ThreadDepth2mm_97730456334 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H4.5mm_ThreadDepth2mm_NoNPTH_97730456330 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H4mm_ThreadDepth2mm_97730406332 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H4mm_ThreadDepth2mm_97730406334 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H4mm_ThreadDepth2mm_NoNPTH_97730406330 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H5mm_ThreadDepth2mm_97730506332 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H5mm_ThreadDepth2mm_97730506334 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H5mm_ThreadDepth2mm_NoNPTH_97730506330 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H6mm_ThreadDepth2mm_97730606332 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H6mm_ThreadDepth2mm_97730606334 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M1.6_H6mm_ThreadDepth2mm_NoNPTH_97730606330 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H1.5mm_9774015243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H1mm_9774010243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H2.5mm_9774025243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H2mm_9774020243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H3.5mm_9774035243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H3mm_9774030243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H4.5mm_9774045243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H4mm_9774040243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H5mm_9774050243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H6mm_9774060243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H7mm_9774070243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M2_H8mm_9774080243 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H1.5mm_9774015360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H10mm_9774100360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H11mm_9774110360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H12mm_9774120360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H13mm_9774130360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H14mm_9774140360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H15mm_9774150360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H1mm_9774010360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H2.5mm_9774025360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H2mm_9774020360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H3mm_9774030360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H4mm_9774040360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H5mm_9774050360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H6mm_9774060360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H7mm_9774070360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H8mm_9774080360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSI-M3_H9mm_9774090360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H10.6mm_ReverseMount_9775106960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H11.6mm_ReverseMount_9775116960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H2.6mm_ReverseMount_9775026960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H3.1mm_ReverseMount_9775031960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H3.6mm_ReverseMount_9775036960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H4.1mm_ReverseMount_9775041960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H4.6mm_ReverseMount_9775046960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H5.1mm_ReverseMount_9775051960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H5.6mm_ReverseMount_9775056960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H6.6mm_ReverseMount_9775066960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H7.6mm_ReverseMount_9775076960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H8.6mm_ReverseMount_9775086960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-3.2mm_H9.6mm_ReverseMount_9775096960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H10.6mm_ReverseMount_9775106360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H11.6mm_ReverseMount_9775116360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H2.6mm_ReverseMount_9775026360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H3.1mm_ReverseMount_9775031360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H3.6mm_ReverseMount_9775036360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H4.1mm_ReverseMount_9775041360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H4.6mm_ReverseMount_9775046360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H5.1mm_ReverseMount_9775051360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H5.6mm_ReverseMount_9775056360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H6.6mm_ReverseMount_9775066360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H7.6mm_ReverseMount_9775076360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H8.6mm_ReverseMount_9775086360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSR-M3_H9.6mm_ReverseMount_9775096360 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H10mm_SnapRivet_9776100960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H2.5mm_SnapRivet_9776025960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H2mm_SnapRivet_9776020960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H3mm_SnapRivet_9776030960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H4mm_SnapRivet_9776040960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H5mm_SnapRivet_9776050960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H6mm_SnapRivet_9776060960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H7mm_SnapRivet_9776070960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H8mm_SnapRivet_9776080960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMSSR-3.3mm_H9mm_SnapRivet_9776090960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H1.5mm_9774015943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H1mm_9774010943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H2.5mm_9774025943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H2mm_9774020943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H3.5mm_9774035943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H3mm_9774030943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H4.5mm_9774045943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H4mm_9774040943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H5mm_9774050943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H6mm_9774060943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H7mm_9774070943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.25mm_H8mm_9774080943 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H1.5mm_9774015951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H10mm_9774100951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H1mm_9774010951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H2.5mm_9774025951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H2mm_9774020951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H3mm_9774030951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H4mm_9774040951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H5.5mm_9774055951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H5mm_9774050951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H6.5mm_9774065951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H6mm_9774060951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H7mm_9774070951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H8mm_9774080951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-2.7mm_H9mm_9774090951 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H1.5mm_9774015960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H10mm_9774100960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H11mm_9774110960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H12mm_9774120960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H13mm_9774130960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H14mm_9774140960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H15mm_9774150960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H1mm_9774010960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H2.5mm_9774025960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H2mm_9774020960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H3mm_9774030960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H4mm_9774040960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H5mm_9774050960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H6mm_9774060960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H7mm_9774070960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H8mm_9774080960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-3.3mm_H9mm_9774090960 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H10mm_9774100982 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H1mm_9774010982 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H2mm_9774020982 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H3mm_9774030982 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H4mm_9774040982 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H5mm_9774050982 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H6mm_9774060982 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H7mm_9774070982 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H8mm_9774080982 +Mounting_Wuerth:Mounting_Wuerth_WA-SMST-4.5mm_H9mm_9774090982 +Mounting_Wuerth:Mounting_Wuerth_WP-SMRA-D3.3mm_L7mm_7466300_Horizontal +Mounting_Wuerth:Mounting_Wuerth_WP-SMRA-M3_L7mm_7466303_Horizontal +NetTie:NetTie-2_SMD_Pad0.5mm +NetTie:NetTie-2_SMD_Pad2.0mm +NetTie:NetTie-2_THT_Pad0.3mm +NetTie:NetTie-2_THT_Pad1.0mm +NetTie:NetTie-3_SMD_Pad0.5mm +NetTie:NetTie-3_SMD_Pad2.0mm +NetTie:NetTie-3_THT_Pad0.3mm +NetTie:NetTie-3_THT_Pad1.0mm +NetTie:NetTie-4_SMD_Pad0.5mm +NetTie:NetTie-4_SMD_Pad2.0mm +NetTie:NetTie-4_THT_Pad0.3mm +NetTie:NetTie-4_THT_Pad1.0mm +OptoDevice:ADNS-9800 +OptoDevice:AGILENT_HFBR-152x +OptoDevice:AGILENT_HFBR-252x +OptoDevice:AMS_TSL2550_SMD +OptoDevice:AMS_TSL25911FN +OptoDevice:Broadcom_AFBR-16xxZ_Horizontal +OptoDevice:Broadcom_AFBR-16xxZ_Tilted +OptoDevice:Broadcom_AFBR-16xxZ_Vertical +OptoDevice:Broadcom_APDS-9160-003 +OptoDevice:Broadcom_APDS-9301 +OptoDevice:Broadcom_DFN-6_2x2mm_P0.65mm +OptoDevice:Broadcom_LGA-8_2x2mm_P0.53mm +OptoDevice:Broadcom_LGA-8_2x2mm_P0.5mm +OptoDevice:Everlight_IRM-H6xxT +OptoDevice:Everlight_ITR1201SR10AR +OptoDevice:Everlight_ITR8307 +OptoDevice:Everlight_ITR8307F43 +OptoDevice:Everlight_ITR8307_Reverse +OptoDevice:Everlight_ITR9608-F +OptoDevice:Finder_34.81 +OptoDevice:Hamamatsu_C12880 +OptoDevice:Hamamatsu_S13360-30CS +OptoDevice:Kingbright_KPS-3227 +OptoDevice:Kingbright_KPS-5130 +OptoDevice:Kingbright_KRC011_Horizontal +OptoDevice:Kingbright_KRC011_Vertical +OptoDevice:Kodenshi_LG206D +OptoDevice:Kodenshi_LG206L +OptoDevice:Kodenshi_SG105 +OptoDevice:Kodenshi_SG105F +OptoDevice:Kodenshi_SG105_Reverse +OptoDevice:LaserDiode_TO18-D5.6-3 +OptoDevice:LaserDiode_TO3.3-D3.3-3 +OptoDevice:LaserDiode_TO38ICut-3 +OptoDevice:LaserDiode_TO5-D9-3 +OptoDevice:LaserDiode_TO56-3 +OptoDevice:Lightpipe_Bivar_RLP1-400-650 +OptoDevice:Lightpipe_Bivar_SLP3-150-100-F +OptoDevice:Lightpipe_Bivar_SLP3-150-100-R +OptoDevice:Lightpipe_Bivar_SLP3-150-150-F +OptoDevice:Lightpipe_Bivar_SLP3-150-150-R +OptoDevice:Lightpipe_Bivar_SLP3-150-200-R +OptoDevice:Lightpipe_Bivar_SLP3-150-250-F +OptoDevice:Lightpipe_Bivar_SLP3-150-250-R +OptoDevice:Lightpipe_Bivar_SLP3-150-300-F +OptoDevice:Lightpipe_Bivar_SLP3-150-300-R +OptoDevice:Lightpipe_Bivar_SLP3-150-450-R +OptoDevice:Lightpipe_Dialight_515-1064F +OptoDevice:Lightpipe_LPF-C012303S +OptoDevice:Lightpipe_LPF-C013301S +OptoDevice:Lightpipe_Mentor_1275.x00x +OptoDevice:Lightpipe_Mentor_1276.1004 +OptoDevice:Lightpipe_Mentor_1276.2004 +OptoDevice:Lite-On_LTR-303ALS-01 +OptoDevice:Luna_NSL-32 +OptoDevice:Maxim_OLGA-14_3.3x5.6mm_P0.8mm +OptoDevice:OnSemi_CASE100AQ +OptoDevice:OnSemi_CASE100CY +OptoDevice:ONSemi_QSE15x +OptoDevice:Osram_BP104-SMD +OptoDevice:Osram_BPW34S-SMD +OptoDevice:Osram_BPW82 +OptoDevice:Osram_DIL2_4.3x4.65mm_P5.08mm +OptoDevice:Osram_LPT80A +OptoDevice:Osram_SFH205 +OptoDevice:Osram_SFH2201 +OptoDevice:Osram_SFH225 +OptoDevice:Osram_SFH2430 +OptoDevice:Osram_SFH2440 +OptoDevice:Osram_SFH3710 +OptoDevice:Osram_SFH9x0x +OptoDevice:Osram_SMD-SmartDIL +OptoDevice:Panasonic_APV-AQY_SSOP-4_4.45x2.65mm_P1.27mm +OptoDevice:PerkinElmer_VTL5C +OptoDevice:PerkinElmer_VTL5Cx2 +OptoDevice:Renesas_DFN-6_1.5x1.6mm_P0.5mm +OptoDevice:Rohm_RPR-0720 +OptoDevice:R_LDR_10x8.5mm_P7.6mm_Vertical +OptoDevice:R_LDR_11x9.4mm_P8.2mm_Vertical +OptoDevice:R_LDR_12x10.8mm_P9.0mm_Vertical +OptoDevice:R_LDR_4.9x4.2mm_P2.54mm_Vertical +OptoDevice:R_LDR_5.0x4.1mm_P3mm_Vertical +OptoDevice:R_LDR_5.1x4.3mm_P3.4mm_Vertical +OptoDevice:R_LDR_5.2x5.2mm_P3.5mm_Horizontal +OptoDevice:R_LDR_7x6mm_P5.1mm_Vertical +OptoDevice:R_LDR_D13.8mm_P9.0mm_Vertical +OptoDevice:R_LDR_D20mm_P17.5mm_Vertical +OptoDevice:R_LDR_D6.4mm_P3.4mm_Vertical +OptoDevice:Sharp_GP2S700HCP +OptoDevice:Sharp_GP2Y0A41SK0F +OptoDevice:Sharp_IS471F +OptoDevice:Sharp_IS485 +OptoDevice:Siemens_SFH900 +OptoDevice:ST_VL53L0X +OptoDevice:Toshiba_TORX170_TORX173_TORX193_TORX194 +OptoDevice:Toshiba_TOTX170_TOTX173_TOTX193_TOTX194 +OptoDevice:Vishay_CAST-3Pin +OptoDevice:Vishay_CNY70 +OptoDevice:Vishay_MINICAST-3Pin +OptoDevice:Vishay_MINIMOLD-3Pin +OptoDevice:Vishay_MOLD-3Pin +OptoDevice:Vishay_TCRT5000 +Oscillator:Oscillator_DIP-14 +Oscillator:Oscillator_DIP-14_LargePads +Oscillator:Oscillator_DIP-8 +Oscillator:Oscillator_DIP-8_LargePads +Oscillator:Oscillator_OCXO_Morion_MV267 +Oscillator:Oscillator_OCXO_Morion_MV317 +Oscillator:Oscillator_SeikoEpson_SG-8002DB +Oscillator:Oscillator_SeikoEpson_SG-8002DC +Oscillator:Oscillator_SMD_Abracon_ABLNO +Oscillator:Oscillator_SMD_Abracon_ASCO-4Pin_1.6x1.2mm +Oscillator:Oscillator_SMD_Abracon_ASDMB-4Pin_2.5x2.0mm +Oscillator:Oscillator_SMD_Abracon_ASE-4Pin_3.2x2.5mm +Oscillator:Oscillator_SMD_Abracon_ASE-4Pin_3.2x2.5mm_HandSoldering +Oscillator:Oscillator_SMD_Abracon_ASV-4Pin_7.0x5.1mm +Oscillator:Oscillator_SMD_Abracon_ASV-4Pin_7.0x5.1mm_HandSoldering +Oscillator:Oscillator_SMD_Diodes_FN-4Pin_7.0x5.0mm +Oscillator:Oscillator_SMD_ECS_2520MV-xxx-xx-4Pin_2.5x2.0mm +Oscillator:Oscillator_SMD_EuroQuartz_XO32-4Pin_3.2x2.5mm +Oscillator:Oscillator_SMD_EuroQuartz_XO32-4Pin_3.2x2.5mm_HandSoldering +Oscillator:Oscillator_SMD_EuroQuartz_XO53-4Pin_5.0x3.2mm +Oscillator:Oscillator_SMD_EuroQuartz_XO53-4Pin_5.0x3.2mm_HandSoldering +Oscillator:Oscillator_SMD_EuroQuartz_XO91-4Pin_7.0x5.0mm +Oscillator:Oscillator_SMD_EuroQuartz_XO91-4Pin_7.0x5.0mm_HandSoldering +Oscillator:Oscillator_SMD_Fordahl_DFAS1-6Pin_14.8x9.1mm +Oscillator:Oscillator_SMD_Fordahl_DFAS11-4Pin_7.0x5.0mm +Oscillator:Oscillator_SMD_Fordahl_DFAS11-4Pin_7.0x5.0mm_HandSoldering +Oscillator:Oscillator_SMD_Fordahl_DFAS15-4Pin_5.0x3.2mm +Oscillator:Oscillator_SMD_Fordahl_DFAS15-4Pin_5.0x3.2mm_HandSoldering +Oscillator:Oscillator_SMD_Fordahl_DFAS2-4Pin_7.3x5.1mm +Oscillator:Oscillator_SMD_Fordahl_DFAS2-4Pin_7.3x5.1mm_HandSoldering +Oscillator:Oscillator_SMD_Fordahl_DFAS3-4Pin_9.1x7.2mm +Oscillator:Oscillator_SMD_Fordahl_DFAS3-4Pin_9.1x7.2mm_HandSoldering +Oscillator:Oscillator_SMD_Fordahl_DFAS7-4Pin_19.9x12.9mm +Oscillator:Oscillator_SMD_Fordahl_DFAS7-4Pin_19.9x12.9mm_HandSoldering +Oscillator:Oscillator_SMD_Fox_FT5H_5.0x3.2mm +Oscillator:Oscillator_SMD_IDT_JS6-6_5.0x3.2mm_P1.27mm +Oscillator:Oscillator_SMD_IDT_JU6-6_7.0x5.0mm_P2.54mm +Oscillator:Oscillator_SMD_IQD_IQXO70-4Pin_7.5x5.0mm +Oscillator:Oscillator_SMD_IQD_IQXO70-4Pin_7.5x5.0mm_HandSoldering +Oscillator:Oscillator_SMD_Kyocera_2520-6Pin_2.5x2.0mm +Oscillator:Oscillator_SMD_Kyocera_KC2520Z-4Pin_2.5x2.0mm +Oscillator:Oscillator_SMD_OCXO_ConnorWinfield_OH300 +Oscillator:Oscillator_SMD_SeikoEpson_SG210-4Pin_2.5x2.0mm +Oscillator:Oscillator_SMD_SeikoEpson_SG210-4Pin_2.5x2.0mm_HandSoldering +Oscillator:Oscillator_SMD_SeikoEpson_SG3030CM +Oscillator:Oscillator_SMD_SeikoEpson_SG8002CA-4Pin_7.0x5.0mm +Oscillator:Oscillator_SMD_SeikoEpson_SG8002CA-4Pin_7.0x5.0mm_HandSoldering +Oscillator:Oscillator_SMD_SeikoEpson_SG8002CE-4Pin_3.2x2.5mm +Oscillator:Oscillator_SMD_SeikoEpson_SG8002CE-4Pin_3.2x2.5mm_HandSoldering +Oscillator:Oscillator_SMD_SeikoEpson_SG8002JA-4Pin_14.0x8.7mm +Oscillator:Oscillator_SMD_SeikoEpson_SG8002JA-4Pin_14.0x8.7mm_HandSoldering +Oscillator:Oscillator_SMD_SeikoEpson_SG8002JC-4Pin_10.5x5.0mm +Oscillator:Oscillator_SMD_SeikoEpson_SG8002JC-4Pin_10.5x5.0mm_HandSoldering +Oscillator:Oscillator_SMD_SeikoEpson_SG8002LB-4Pin_5.0x3.2mm +Oscillator:Oscillator_SMD_SeikoEpson_SG8002LB-4Pin_5.0x3.2mm_HandSoldering +Oscillator:Oscillator_SMD_SeikoEpson_TG2520SMN-xxx-xxxxxx-4Pin_2.5x2.0mm +Oscillator:Oscillator_SMD_SI570_SI571_HandSoldering +Oscillator:Oscillator_SMD_SI570_SI571_Standard +Oscillator:Oscillator_SMD_Silicon_Labs_LGA-6_2.5x3.2mm_P1.25mm +Oscillator:Oscillator_SMD_SiTime_PQFD-6L_3.2x2.5mm +Oscillator:Oscillator_SMD_SiTime_SiT9121-6Pin_3.2x2.5mm +Oscillator:Oscillator_SMD_SiT_PQFN-4Pin_2.0x1.6mm +Oscillator:Oscillator_SMD_SiT_PQFN-4Pin_2.5x2.0mm +Oscillator:Oscillator_SMD_SiT_PQFN-4Pin_3.2x2.5mm +Oscillator:Oscillator_SMD_SiT_PQFN-4Pin_5.0x3.2mm +Oscillator:Oscillator_SMD_SiT_PQFN-4Pin_7.0x5.0mm +Oscillator:Oscillator_SMD_TCXO_G158 +Oscillator:Oscillator_SMD_TXC_7C-4Pin_5.0x3.2mm +Oscillator:Oscillator_SMD_TXC_7C-4Pin_5.0x3.2mm_HandSoldering +Package_BGA:Alliance_TFBGA-36_6x8mm_Layout6x8_P0.75mm +Package_BGA:Alliance_TFBGA-54_8x8mm_Layout9x9_P0.8mm +Package_BGA:Analog_BGA-165_11.9x16mm_Layout11x15_P1.0mm +Package_BGA:Analog_BGA-209_9.5x16mm_Layout11x19_P0.8mm +Package_BGA:Analog_BGA-28_4x6.25mm_Layout4x7_P0.8mm +Package_BGA:Analog_BGA-49_6.25x6.25mm_Layout7x7_P0.8mm +Package_BGA:Analog_BGA-77_9x15mm_Layout7x11_P1.27mm +Package_BGA:BGA-100_11.0x11.0mm_Layout10x10_P1.0mm_Ball0.5mm_Pad0.4mm_NSMD +Package_BGA:BGA-100_6.0x6.0mm_Layout11x11_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD +Package_BGA:BGA-1023_33.0x33.0mm_Layout32x32_P1.0mm +Package_BGA:BGA-1156_35.0x35.0mm_Layout34x34_P1.0mm +Package_BGA:BGA-121_9.0x9.0mm_Layout11x11_P0.8mm_Ball0.4mm_Pad0.35mm_NSMD +Package_BGA:BGA-1295_37.5x37.5mm_Layout36x36_P1.0mm +Package_BGA:BGA-132_12x18mm_Layout11x17_P1.0mm +Package_BGA:BGA-144_13.0x13.0mm_Layout12x12_P1.0mm +Package_BGA:BGA-144_7.0x7.0mm_Layout13x13_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD +Package_BGA:BGA-152_14x18mm_Layout13x17_P0.5mm +Package_BGA:BGA-153_8.0x8.0mm_Layout15x15_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD +Package_BGA:BGA-169_11.0x11.0mm_Layout13x13_P0.8mm_Ball0.5mm_Pad0.4mm_NSMD +Package_BGA:BGA-16_1.92x1.92mm_Layout4x4_P0.5mm +Package_BGA:BGA-196_15x15mm_Layout14x14_P1.0mm +Package_BGA:BGA-200_10x14.5mm_Layout12x22_P0.8x0.65mm +Package_BGA:BGA-256_11.0x11.0mm_Layout20x20_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD +Package_BGA:BGA-256_14.0x14.0mm_Layout16x16_P0.8mm_Ball0.45mm_Pad0.32mm_NSMD +Package_BGA:BGA-256_17.0x17.0mm_Layout16x16_P1.0mm_Ball0.5mm_Pad0.4mm_NSMD +Package_BGA:BGA-25_6.35x6.35mm_Layout5x5_P1.27mm +Package_BGA:BGA-324_15.0x15.0mm_Layout18x18_P0.8mm_Ball0.5mm_Pad0.4mm_NSMD +Package_BGA:BGA-324_15x15mm_Layout18x18_P0.8mm +Package_BGA:BGA-324_19.0x19.0mm_Layout18x18_P1.0mm_Ball0.5mm_Pad0.4mm_NSMD +Package_BGA:BGA-352_35.0x35.0mm_Layout26x26_P1.27mm +Package_BGA:BGA-36_3.396x3.466mm_Layout6x6_P0.4mm_Ball0.25mm_Pad0.2mm_NSMD +Package_BGA:BGA-400_21.0x21.0mm_Layout20x20_P1.0mm +Package_BGA:BGA-484_23.0x23.0mm_Layout22x22_P1.0mm +Package_BGA:BGA-48_8.0x9.0mm_Layout6x8_P0.8mm +Package_BGA:BGA-529_19x19mm_Layout23x23_P0.8mm +Package_BGA:BGA-624_21x21mm_Layout25x25_P0.8mm +Package_BGA:BGA-625_21.0x21.0mm_Layout25x25_P0.8mm +Package_BGA:BGA-64_9.0x9.0mm_Layout10x10_P0.8mm +Package_BGA:BGA-672_27.0x27.0mm_Layout26x26_P1.0mm_Ball0.6mm_Pad0.5mm_NSMD +Package_BGA:BGA-676_27.0x27.0mm_Layout26x26_P1.0mm_Ball0.6mm_Pad0.5mm_NSMD +Package_BGA:BGA-68_5.0x5.0mm_Layout9x9_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD +Package_BGA:BGA-81_4.496x4.377mm_Layout9x9_P0.4mm_Ball0.25mm_Pad0.2mm_NSMD +Package_BGA:BGA-90_8.0x13.0mm_Layout2x3x15_P0.8mm +Package_BGA:BGA-96_9.0x13.0mm_Layout2x3x16_P0.8mm +Package_BGA:BGA-9_1.6x1.6mm_Layout3x3_P0.5mm +Package_BGA:EPC_BGA-4_0.9x0.9mm_Layout2x2_P0.45mm +Package_BGA:FB-BGA-484_23.0x23.0mm_Layout22x22_P1.0mm +Package_BGA:FBGA-78_7.5x11mm_Layout2x3x13_P0.8mm +Package_BGA:Fujitsu_WLP-15_2.28x3.092mm_Layout3x5_P0.4mm +Package_BGA:Infineon_LFBGA-292_17x17mm_Layout20x20_P0.8mm +Package_BGA:Infineon_TFBGA-48_6x10mm_Layout6x8_P0.75mm +Package_BGA:Lattice_caBGA-381_17x17mm_Layout20x20_P0.8mm +Package_BGA:Lattice_caBGA-381_17x17mm_Layout20x20_P0.8mm_SMD +Package_BGA:Lattice_caBGA-756_27x27mm_Layout32x32_P0.8mm +Package_BGA:Lattice_iCE40_csBGA-132_8x8mm_Layout14x14_P0.5mm +Package_BGA:LFBGA-100_10x10mm_Layout10x10_P0.8mm +Package_BGA:LFBGA-144_10x10mm_Layout12x12_P0.8mm +Package_BGA:LFBGA-153_11.5x13mm_Layout14x14_P0.5mm +Package_BGA:LFBGA-169_12x16mm_Layout14x28_P0.5mm +Package_BGA:LFBGA-169_12x18mm_Layout14x28_P0.5mm +Package_BGA:LFBGA-169_14x18mm_Layout14x28_P0.5mm +Package_BGA:LFBGA-289_14x14mm_Layout17x17_P0.8mm +Package_BGA:LFBGA-400_16x16mm_Layout20x20_P0.8mm +Package_BGA:LFBGA-484_18x18mm_Layout22x22_P0.8mm +Package_BGA:Linear_BGA-133_15.0x15.0mm_Layout12x12_P1.27mm +Package_BGA:MAPBGA-272_9x9mm_Layout17x17_P0.5mm +Package_BGA:MAPBGA-289_14x14mm_Layout17x17_P0.8mm +Package_BGA:Maxim_WLP-12 +Package_BGA:Maxim_WLP-12_2.008x1.608mm_Layout4x3_P0.4mm +Package_BGA:Maxim_WLP-9_1.595x1.415_Layout3x3_P0.4mm_Ball0.27mm_Pad0.25mm_NSMD +Package_BGA:Microchip_TFBGA-196_11x11mm_Layout14x14_P0.75mm_SMD +Package_BGA:Micron_FBGA-78_7.5x10.6mm_Layout9x13_P0.8mm +Package_BGA:Micron_FBGA-78_8x10.5mm_Layout9x13_P0.8mm +Package_BGA:Micron_FBGA-78_9x10.5mm_Layout9x13_P0.8mm +Package_BGA:Micron_FBGA-96_7.5x13.5mm_Layout9x16_P0.8mm +Package_BGA:Micron_FBGA-96_8x14mm_Layout9x16_P0.8mm +Package_BGA:Micron_FBGA-96_9x14mm_Layout9x16_P0.8mm +Package_BGA:NXP_VFBGA-42_2.6x3mm_Layout6x7_P0.4mm +Package_BGA:ST_LFBGA-354_16x16mm_Layout19x19_P0.8mm +Package_BGA:ST_LFBGA-448_18x18mm_Layout22x22_P0.8mm +Package_BGA:ST_TFBGA-169_7x7mm_Layout13x13_P0.5mm +Package_BGA:ST_TFBGA-225_13x13mm_Layout15x15_P0.8mm +Package_BGA:ST_TFBGA-257_10x10mm_Layout19x19_P0.5mmP0.65mm +Package_BGA:ST_TFBGA-320_11x11mm_Layout21x21_P0.5mm +Package_BGA:ST_TFBGA-361_12x12mm_Layout23x23_P0.5mmP0.65mm +Package_BGA:ST_UFBGA-121_6x6mm_Layout11x11_P0.5mm +Package_BGA:ST_UFBGA-129_7x7mm_Layout13x13_P0.5mm +Package_BGA:ST_UFBGA-59_5x5mm_Layout8x8_P0.5mm +Package_BGA:ST_UFBGA-73_5x5mm_Layout9x9_P0.5mm +Package_BGA:ST_UFBGA-81_5x5mm_Layout9x9_P0.5mm +Package_BGA:ST_uTFBGA-36_3.6x3.6mm_Layout6x6_P0.5mm +Package_BGA:Texas_BGA-289_15x15mm_Layout17x17_P0.8mm +Package_BGA:Texas_DSBGA-10_1.36x1.86mm_Layout3x4_P0.5mm +Package_BGA:Texas_DSBGA-12_1.36x1.86mm_Layout3x4_P0.5mm +Package_BGA:Texas_DSBGA-16_2.39x2.39mm_Layout4x4_P0.5mm +Package_BGA:Texas_DSBGA-28_1.9x3mm_Layout4x7_P0.4mm +Package_BGA:Texas_DSBGA-49_3.33x3.488mm_Layout7x7_P0.4mm +Package_BGA:Texas_DSBGA-5_0.822x1.116mm_Layout2x1x2_P0.4mm +Package_BGA:Texas_DSBGA-5_0.8875x1.3875mm_Layout2x3_P0.5mm +Package_BGA:Texas_DSBGA-5_1.5855x1.6365mm_Layout3x2_P0.5mm +Package_BGA:Texas_DSBGA-64_3.415x3.535mm_Layout8x8_P0.4mm +Package_BGA:Texas_DSBGA-6_0.704x1.054mm_Layout2x3_P0.35mm +Package_BGA:Texas_DSBGA-6_0.757x1.01mm_Layout2x3_P0.35mm +Package_BGA:Texas_DSBGA-6_0.855x1.255mm_Layout2x3_P0.4mm_LevelB +Package_BGA:Texas_DSBGA-6_0.855x1.255mm_Layout2x3_P0.4mm_LevelC +Package_BGA:Texas_DSBGA-6_0.95x1.488mm_Layout2x3_P0.4mm +Package_BGA:Texas_DSBGA-6_0.9x1.4mm_Layout2x3_P0.5mm +Package_BGA:Texas_DSBGA-8_0.705x1.468mm_Layout2x4_P0.4mm +Package_BGA:Texas_DSBGA-8_0.9x1.9mm_Layout2x4_P0.5mm +Package_BGA:Texas_DSBGA-8_1.43x1.41mm_Layout3x3_P0.5mm +Package_BGA:Texas_DSBGA-8_1.5195x1.5195mm_Layout3x3_P0.5mm +Package_BGA:Texas_DSBGA-9_1.4715x1.4715mm_Layout3x3_P0.5mm +Package_BGA:Texas_DSBGA-9_1.62x1.58mm_Layout3x3_P0.5mm +Package_BGA:Texas_MicroStar_Junior_BGA-113_7x7mm_Layout12x12_P0.5mm +Package_BGA:Texas_MicroStar_Junior_BGA-12_2.0x2.5mm_Layout4x3_P0.5mm +Package_BGA:Texas_MicroStar_Junior_BGA-80_5.0x5.0mm_Layout9x9_P0.5mm +Package_BGA:Texas_PicoStar_BGA-4_0.758x0.758mm_Layout2x2_P0.4mm +Package_BGA:Texas_YFP0020_DSBGA-20_1.588x1.988mm_Layout4x5_P0.4mm +Package_BGA:TFBGA-100_5.5x5.5mm_Layout10x10_P0.5mm +Package_BGA:TFBGA-100_8x8mm_Layout10x10_P0.8mm +Package_BGA:TFBGA-100_9.0x9.0mm_Layout10x10_P0.8mm +Package_BGA:TFBGA-121_10x10mm_Layout11x11_P0.8mm +Package_BGA:TFBGA-169_9x9mm_Layout13x13_P0.65mm +Package_BGA:TFBGA-216_13x13mm_Layout15x15_P0.8mm +Package_BGA:TFBGA-225_10x10mm_Layout15x15_P0.65mm +Package_BGA:TFBGA-256_13x13mm_Layout16x16_P0.8mm +Package_BGA:TFBGA-265_14x14mm_Layout17x17_P0.8mm +Package_BGA:TFBGA-289_9x9mm_Layout17x17_P0.5mm +Package_BGA:TFBGA-324_12x12mm_Layout18x18_P0.65mm +Package_BGA:TFBGA-361_13x13mm_Layout19x19_P0.65mm +Package_BGA:TFBGA-48_6x10mm_Layout6x8_P0.75mm +Package_BGA:TFBGA-49_3x3mm_Layout7x7_P0.4mm +Package_BGA:TFBGA-576_16x16mm_Layout24x24_P0.65mm +Package_BGA:TFBGA-644_19x19mm_Layout28x28_P0.65mm +Package_BGA:TFBGA-64_5x5mm_Layout8x8_P0.5mm +Package_BGA:TFBGA-81_5x5mm_Layout9x9_P0.5mm +Package_BGA:UCBGA-36_2.5x2.5mm_Layout6x6_P0.4mm +Package_BGA:UCBGA-49_3x3mm_Layout7x7_P0.4mm +Package_BGA:UCBGA-81_4x4mm_Layout9x9_P0.4mm +Package_BGA:UFBGA-100_7x7mm_Layout12x12_P0.5mm +Package_BGA:UFBGA-132_7x7mm_Layout12x12_P0.5mm +Package_BGA:UFBGA-132_7x7mm_P0.5mm +Package_BGA:UFBGA-144_10x10mm_Layout12x12_P0.8mm +Package_BGA:UFBGA-144_7x7mm_Layout12x12_P0.5mm +Package_BGA:UFBGA-15_3.0x3.0mm_Layout4x4_P0.65mm +Package_BGA:UFBGA-169_7x7mm_Layout13x13_P0.5mm +Package_BGA:UFBGA-201_10x10mm_Layout15x15_P0.65mm +Package_BGA:UFBGA-32_4.0x4.0mm_Layout6x6_P0.5mm +Package_BGA:UFBGA-64_5x5mm_Layout8x8_P0.5mm +Package_BGA:VFBGA-100_7.0x7.0mm_Layout10x10_P0.65mm +Package_BGA:VFBGA-49_5.0x5.0mm_Layout7x7_P0.65mm +Package_BGA:VFBGA-86_6x6mm_Layout10x10_P0.55mm +Package_BGA:WLP-4_0.728x0.728mm_Layout2x2_P0.35mm +Package_BGA:WLP-4_0.83x0.83mm_P0.4mm +Package_BGA:WLP-4_0.86x0.86mm_P0.4mm +Package_BGA:WLP-9_1.468x1.448mm_Layout3x3_P0.4mm +Package_BGA:XBGA-121_10x10mm_Layout11x11_P0.8mm +Package_BGA:XFBGA-121_8x8mm_Layout11x11_P0.65mm +Package_BGA:XFBGA-36_3.5x3.5mm_Layout6x6_P0.5mm +Package_BGA:XFBGA-64_5.0x5.0mm_Layout8x8_P0.5mm +Package_BGA:Xilinx_CLG225 +Package_BGA:Xilinx_CLG400 +Package_BGA:Xilinx_CLG484_CLG485 +Package_BGA:Xilinx_CPG236 +Package_BGA:Xilinx_CPG238 +Package_BGA:Xilinx_CPGA196 +Package_BGA:Xilinx_CSG324 +Package_BGA:Xilinx_CSG325 +Package_BGA:Xilinx_CSGA225 +Package_BGA:Xilinx_CSGA324 +Package_BGA:Xilinx_FBG484 +Package_BGA:Xilinx_FBG676 +Package_BGA:Xilinx_FBG900 +Package_BGA:Xilinx_FFG1156 +Package_BGA:Xilinx_FFG1157_FFG1158 +Package_BGA:Xilinx_FFG1761 +Package_BGA:Xilinx_FFG1926_FFG1927_FFG1928_FFG1930 +Package_BGA:Xilinx_FFG676 +Package_BGA:Xilinx_FFG900_FFG901 +Package_BGA:Xilinx_FFV1761 +Package_BGA:Xilinx_FGG484 +Package_BGA:Xilinx_FGG676 +Package_BGA:Xilinx_FGGA484 +Package_BGA:Xilinx_FGGA676 +Package_BGA:Xilinx_FHG1761 +Package_BGA:Xilinx_FLG1925_FLG1926_FLG1928_FLG1930 +Package_BGA:Xilinx_FTG256 +Package_BGA:Xilinx_FTGB196 +Package_BGA:Xilinx_RB484 +Package_BGA:Xilinx_RB676 +Package_BGA:Xilinx_RF1156 +Package_BGA:Xilinx_RF1157_RF1158 +Package_BGA:Xilinx_RF1761 +Package_BGA:Xilinx_RF1930 +Package_BGA:Xilinx_RF676 +Package_BGA:Xilinx_RF900 +Package_BGA:Xilinx_RFG676 +Package_BGA:Xilinx_RS484 +Package_BGA:Xilinx_SBG484 +Package_BGA:Xilinx_SBG485 +Package_CSP:Analog_LFCSP-16-1EP_4x4mm_P0.65mm_EP2.1x2.1mm +Package_CSP:Analog_LFCSP-16-1EP_4x4mm_P0.65mm_EP2.1x2.1mm_ThermalVias +Package_CSP:Analog_LFCSP-16-1EP_4x4mm_P0.65mm_EP2.35x2.35mm +Package_CSP:Analog_LFCSP-16-1EP_4x4mm_P0.65mm_EP2.35x2.35mm_ThermalVias +Package_CSP:Analog_LFCSP-8-1EP_3x3mm_P0.5mm_EP1.53x1.85mm +Package_CSP:Analog_LFCSP-UQ-10_1.3x1.6mm_P0.4mm +Package_CSP:Anpec_WLCSP-20_1.76x2.03mm_Layout4x5_P0.4mm +Package_CSP:Dialog_WLCSP-34_4.54x1.66mm_Layout17x4_P0.25x0.34mm +Package_CSP:DiodesInc_GEA20_WLCSP-20_1.7x2.1mm_Layout4x5_P0.4mm +Package_CSP:Efinix_WLCSP-64_3.5353x3.3753mm_Layout8x8_P0.4mm +Package_CSP:Efinix_WLCSP-80_4.4567x3.5569mm_Layout10x8_P0.4mm +Package_CSP:LFCSP-10_2x2mm_P0.5mm +Package_CSP:LFCSP-16-1EP_3x3mm_P0.5mm_EP1.3x1.3mm +Package_CSP:LFCSP-16-1EP_3x3mm_P0.5mm_EP1.3x1.3mm_ThermalVias +Package_CSP:LFCSP-16-1EP_3x3mm_P0.5mm_EP1.5x1.5mm +Package_CSP:LFCSP-16-1EP_3x3mm_P0.5mm_EP1.6x1.6mm +Package_CSP:LFCSP-16-1EP_3x3mm_P0.5mm_EP1.6x1.6mm_ThermalVias +Package_CSP:LFCSP-16-1EP_3x3mm_P0.5mm_EP1.7x1.7mm +Package_CSP:LFCSP-16-1EP_3x3mm_P0.5mm_EP1.7x1.7mm_ThermalVias +Package_CSP:LFCSP-16-1EP_3x3mm_P0.5mm_EP1.854x1.854mm +Package_CSP:LFCSP-16-1EP_4x4mm_P0.65mm_EP2.1x2.1mm +Package_CSP:LFCSP-16-1EP_4x4mm_P0.65mm_EP2.4x2.4mm +Package_CSP:LFCSP-16-1EP_4x4mm_P0.65mm_EP2.4x2.4mm_ThermalVias +Package_CSP:LFCSP-16-1EP_4x4mm_P0.65mm_EP2.6x2.6mm +Package_CSP:LFCSP-16-1EP_4x4mm_P0.65mm_EP2.6x2.6mm_ThermalVias +Package_CSP:LFCSP-16_3x3mm_P0.5mm +Package_CSP:LFCSP-20-1EP_4x4mm_P0.5mm_EP2.1x2.1mm +Package_CSP:LFCSP-20-1EP_4x4mm_P0.5mm_EP2.1x2.1mm_ThermalVias +Package_CSP:LFCSP-20-1EP_4x4mm_P0.5mm_EP2.5x2.5mm +Package_CSP:LFCSP-20-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias +Package_CSP:LFCSP-20-1EP_4x4mm_P0.5mm_EP2.6x2.6mm +Package_CSP:LFCSP-20-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias +Package_CSP:LFCSP-24-1EP_4x4mm_P0.5mm_EP0.5x0.5mm +Package_CSP:LFCSP-24-1EP_4x4mm_P0.5mm_EP2.3x2.3mm +Package_CSP:LFCSP-24-1EP_4x4mm_P0.5mm_EP2.3x2.3mm_ThermalVias +Package_CSP:LFCSP-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm +Package_CSP:LFCSP-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias +Package_CSP:LFCSP-28-1EP_5x5mm_P0.5mm_EP3.14x3.14mm +Package_CSP:LFCSP-28-1EP_5x5mm_P0.5mm_EP3.14x3.14mm_ThermalVias +Package_CSP:LFCSP-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm +Package_CSP:LFCSP-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm_ThermalVias +Package_CSP:LFCSP-32-1EP_5x5mm_P0.5mm_EP3.25x3.25mm +Package_CSP:LFCSP-32-1EP_5x5mm_P0.5mm_EP3.5x3.5mm +Package_CSP:LFCSP-32-1EP_5x5mm_P0.5mm_EP3.5x3.5mm_ThermalVias +Package_CSP:LFCSP-32-1EP_5x5mm_P0.5mm_EP3.6x3.6mm +Package_CSP:LFCSP-32-1EP_5x5mm_P0.5mm_EP3.6x3.6mm_ThermalVias +Package_CSP:LFCSP-40-1EP_6x6mm_P0.5mm_EP3.9x3.9mm +Package_CSP:LFCSP-40-1EP_6x6mm_P0.5mm_EP3.9x3.9mm_ThermalVias +Package_CSP:LFCSP-40-1EP_6x6mm_P0.5mm_EP4.65x4.65mm +Package_CSP:LFCSP-40-1EP_6x6mm_P0.5mm_EP4.65x4.65mm_ThermalVias +Package_CSP:LFCSP-40-1EP_6x6mm_P0.5mm_EP4.6x4.6mm +Package_CSP:LFCSP-40-1EP_6x6mm_P0.5mm_EP4.6x4.6mm_ThermalVias +Package_CSP:LFCSP-48-1EP_7x7mm_P0.5mm_EP4.1x4.1mm +Package_CSP:LFCSP-48-1EP_7x7mm_P0.5mm_EP4.1x4.1mm_ThermalVias +Package_CSP:LFCSP-56-1EP_8x8mm_P0.5mm_EP6.6x6.6mm +Package_CSP:LFCSP-56-1EP_8x8mm_P0.5mm_EP6.6x6.6mm_ThermalVias +Package_CSP:LFCSP-6-1EP_2x2mm_P0.65mm_EP1x1.6mm +Package_CSP:LFCSP-64-1EP_9x9mm_P0.5mm_EP5.21x5.21mm +Package_CSP:LFCSP-64-1EP_9x9mm_P0.5mm_EP5.21x5.21mm_ThermalVias +Package_CSP:LFCSP-72-1EP_10x10mm_P0.5mm_EP5.3x5.3mm +Package_CSP:LFCSP-72-1EP_10x10mm_P0.5mm_EP5.3x5.3mm_ThermalVias +Package_CSP:LFCSP-72-1EP_10x10mm_P0.5mm_EP6.15x6.15mm +Package_CSP:LFCSP-8-1EP_3x2mm_P0.5mm_EP1.6x1.65mm +Package_CSP:LFCSP-8-1EP_3x3mm_P0.5mm_EP1.45x1.74mm +Package_CSP:LFCSP-8-1EP_3x3mm_P0.5mm_EP1.6x2.34mm +Package_CSP:LFCSP-8-1EP_3x3mm_P0.5mm_EP1.6x2.34mm_ThermalVias +Package_CSP:LFCSP-8_2x2mm_P0.5mm +Package_CSP:LFCSP-VQ-24-1EP_4x4mm_P0.5mm_EP2.642x2.642mm +Package_CSP:LFCSP-VQ-48-1EP_7x7mm_P0.5mm +Package_CSP:LFCSP-WD-10-1EP_3x3mm_P0.5mm_EP1.64x2.38mm +Package_CSP:LFCSP-WD-10-1EP_3x3mm_P0.5mm_EP1.64x2.38mm_ThermalVias +Package_CSP:LFCSP-WD-8-1EP_3x3mm_P0.65mm_EP1.6x2.44mm +Package_CSP:LFCSP-WD-8-1EP_3x3mm_P0.65mm_EP1.6x2.44mm_ThermalVias +Package_CSP:Macronix_WLCSP-12_2.02x2.09mm_Layout4x4_P0.5mm +Package_CSP:Maxim_WLCSP-35_2.998x2.168mm_Layout7x5_P0.4mm +Package_CSP:Nexperia_WLCSP-15_2.37x1.17mm_Layout6x3_P0.4mmP0.8mm +Package_CSP:OnSemi_ODCSP36_BGA-36_6.13x6.13mm_Layout6x6_P1.0mm +Package_CSP:OnSemi_ODCSP36_BGA-36_6.13x6.13mm_Layout6x6_P1.0mm_ManualAssembly +Package_CSP:OnSemi_ODCSP8_BGA-8_3.16x3.16mm_Layout3x3_P1.26mm +Package_CSP:OnSemi_ODCSP8_BGA-8_3.16x3.16mm_Layout3x3_P1.26mm_ManualAssembly +Package_CSP:pSemi_CSP-16_1.64x2.04mm_P0.4mm +Package_CSP:pSemi_CSP-16_1.64x2.04mm_P0.4mm_Pad0.18mm +Package_CSP:ST_WLCSP-100_4.437x4.456mm_Layout10x10_P0.4mm +Package_CSP:ST_WLCSP-100_4.4x4.38mm_Layout10x10_P0.4mm_Offcenter +Package_CSP:ST_WLCSP-100_Die422 +Package_CSP:ST_WLCSP-100_Die446 +Package_CSP:ST_WLCSP-100_Die452 +Package_CSP:ST_WLCSP-100_Die461 +Package_CSP:ST_WLCSP-101_3.86x3.79mm_Layout11x19_P0.35mm_Stagger +Package_CSP:ST_WLCSP-104_Die437 +Package_CSP:ST_WLCSP-115_3.73x4.15mm_Layout11x21_P0.35mm_Stagger +Package_CSP:ST_WLCSP-115_4.63x4.15mm_Layout21x11_P0.4mm_Stagger +Package_CSP:ST_WLCSP-12_1.7x1.42mm_Layout4x6_P0.35mm_Stagger +Package_CSP:ST_WLCSP-132_4.57x4.37mm_Layout12x11_P0.35mm +Package_CSP:ST_WLCSP-143_Die419 +Package_CSP:ST_WLCSP-143_Die449 +Package_CSP:ST_WLCSP-144_Die470 +Package_CSP:ST_WLCSP-150_5.38x5.47mm_Layout13x23_P0.4mm_Stagger +Package_CSP:ST_WLCSP-156_4.96x4.64mm_Layout13x12_P0.35mm +Package_CSP:ST_WLCSP-168_Die434 +Package_CSP:ST_WLCSP-180_Die451 +Package_CSP:ST_WLCSP-18_1.86x2.14mm_Layout7x5_P0.4mm_Stagger +Package_CSP:ST_WLCSP-208_5.38x5.47mm_Layout26x16_P0.35mm_Stagger +Package_CSP:ST_WLCSP-208_5.8x5.6mm_Layout26x16_P0.35mm_Stagger +Package_CSP:ST_WLCSP-20_1.94x2.4mm_Layout4x5_P0.4mm +Package_CSP:ST_WLCSP-25_2.33x2.24mm_Layout5x5_P0.4mm +Package_CSP:ST_WLCSP-25_2.3x2.48mm_Layout5x5_P0.4mm +Package_CSP:ST_WLCSP-25_Die425 +Package_CSP:ST_WLCSP-25_Die444 +Package_CSP:ST_WLCSP-25_Die457 +Package_CSP:ST_WLCSP-27_2.34x2.55mm_Layout9x6_P0.4mm_Stagger +Package_CSP:ST_WLCSP-27_2.55x2.34mm_P0.40mm_Stagger +Package_CSP:ST_WLCSP-36_2.58x3.07mm_Layout6x6_P0.4mm +Package_CSP:ST_WLCSP-36_Die417 +Package_CSP:ST_WLCSP-36_Die440 +Package_CSP:ST_WLCSP-36_Die445 +Package_CSP:ST_WLCSP-36_Die458 +Package_CSP:ST_WLCSP-41_2.98x2.76mm_Layout13x7_P0.4mm_Stagger +Package_CSP:ST_WLCSP-42_2.82x2.93mm_P0.40mm_Stagger +Package_CSP:ST_WLCSP-42_2.93x2.82mm_Layout12x7_P0.4mm_Stagger +Package_CSP:ST_WLCSP-49_3.15x3.13mm_Layout7x7_P0.4mm +Package_CSP:ST_WLCSP-49_3.3x3.38mm_Layout7x7_P0.4mm_Offcenter +Package_CSP:ST_WLCSP-49_Die423 +Package_CSP:ST_WLCSP-49_Die431 +Package_CSP:ST_WLCSP-49_Die433 +Package_CSP:ST_WLCSP-49_Die435 +Package_CSP:ST_WLCSP-49_Die438 +Package_CSP:ST_WLCSP-49_Die439 +Package_CSP:ST_WLCSP-49_Die447 +Package_CSP:ST_WLCSP-49_Die448 +Package_CSP:ST_WLCSP-52_3.09x3.15mm_Layout13x8_P0.4mm_Stagger +Package_CSP:ST_WLCSP-56_3.38x3.38mm_Layout14x8_P0.4mm_Stagger +Package_CSP:ST_WLCSP-63_Die427 +Package_CSP:ST_WLCSP-64_3.56x3.52mm_Layout8x8_P0.4mm +Package_CSP:ST_WLCSP-64_Die414 +Package_CSP:ST_WLCSP-64_Die427 +Package_CSP:ST_WLCSP-64_Die435 +Package_CSP:ST_WLCSP-64_Die436 +Package_CSP:ST_WLCSP-64_Die441 +Package_CSP:ST_WLCSP-64_Die442 +Package_CSP:ST_WLCSP-64_Die462 +Package_CSP:ST_WLCSP-66_Die411 +Package_CSP:ST_WLCSP-66_Die432 +Package_CSP:ST_WLCSP-72_3.38x3.38mm_Layout16x9_P0.35mm_Stagger +Package_CSP:ST_WLCSP-72_Die415 +Package_CSP:ST_WLCSP-80_3.5x3.27mm_Layout10x16_P0.35mm_Stagger_Offcenter +Package_CSP:ST_WLCSP-81_4.02x4.27mm_Layout9x9_P0.4mm +Package_CSP:ST_WLCSP-81_4.36x4.07mm_Layout9x9_P0.4mm +Package_CSP:ST_WLCSP-81_Die415 +Package_CSP:ST_WLCSP-81_Die421 +Package_CSP:ST_WLCSP-81_Die463 +Package_CSP:ST_WLCSP-90_4.2x3.95mm_Layout18x10_P0.4mm_Stagger +Package_CSP:ST_WLCSP-90_Die413 +Package_CSP:ST_WLCSP-99_4.42x3.77mm_Layout11x9_P0.35mm +Package_CSP:WLCSP-12_1.403x1.555mm_Layout6x4_P0.4mm_Stagger +Package_CSP:WLCSP-12_1.56x1.56mm_P0.4mm +Package_CSP:WLCSP-16_1.409x1.409mm_Layout4x4_P0.35mm +Package_CSP:WLCSP-16_2.225x2.17mm_Layout4x4_P0.5mm +Package_CSP:WLCSP-16_4x4_B2.17x2.32mm_P0.5mm +Package_CSP:WLCSP-20_1.934x2.434mm_Layout4x5_P0.4mm +Package_CSP:WLCSP-20_1.994x1.609mm_Layout5x4_P0.4mm +Package_CSP:WLCSP-20_1.994x1.94mm_Layout4x5_P0.4mm +Package_CSP:WLCSP-36_2.374x2.459mm_Layout6x6_P0.35mm +Package_CSP:WLCSP-36_2.82x2.67mm_Layout6x6_P0.4mm +Package_CSP:WLCSP-4_0.64x0.64mm_Layout2x2_P0.35mm +Package_CSP:WLCSP-4_0.89x0.89mm_Layout2x2_P0.5mm +Package_CSP:WLCSP-56_3.170x3.444mm_Layout7x8_P0.4mm +Package_CSP:WLCSP-6_1.4x1.0mm_P0.4mm +Package_CSP:WLCSP-81_4.41x3.76mm_P0.4mm +Package_CSP:WLCSP-8_1.551x2.284mm_Layout2x4_P0.5mm +Package_CSP:WLCSP-8_1.58x1.63x0.35mm_Layout3x5_P0.35x0.4mm_Ball0.25mm_Pad0.25mm_NSMD +Package_CSP:WLCSP-9_1.21x1.22mm_Layout3x3_P0.4mm +Package_DFN_QFN:AMS_QFN-4-1EP_2x2mm_P0.95mm_EP0.7x1.6mm +Package_DFN_QFN:Analog_QFN-28-36-2EP_5x6mm_P0.5mm +Package_DFN_QFN:AO_AOZ666xDI_DFN-8-1EP_3x3mm_P0.65mm_EP1.25x2.7mm +Package_DFN_QFN:AO_DFN-8-1EP_5.55x5.2mm_P1.27mm_EP4.12x4.6mm +Package_DFN_QFN:ArtInChip_QFN-100-1EP_12x12mm_P0.4mm_EP7.4x7.4mm +Package_DFN_QFN:ArtInChip_QFN-100-1EP_12x12mm_P0.4mm_EP7.4x7.4mm_ThermalVias +Package_DFN_QFN:ArtInChip_QFN-68-1EP_7x7mm_P0.35mm_EP5.49x5.49mm +Package_DFN_QFN:ArtInChip_QFN-68-1EP_7x7mm_P0.35mm_EP5.49x5.49mm_ThermalVias +Package_DFN_QFN:ArtInChip_QFN-88-1EP_10x10mm_P0.4mm_EP6.74x6.74mm +Package_DFN_QFN:ArtInChip_QFN-88-1EP_10x10mm_P0.4mm_EP6.74x6.74mm_ThermalVias +Package_DFN_QFN:Cypress_QFN-56-1EP_8x8mm_P0.5mm_EP6.22x6.22mm_ThermalVias +Package_DFN_QFN:DFN-10-1EP_2.6x2.6mm_P0.5mm_EP1.3x2.2mm +Package_DFN_QFN:DFN-10-1EP_2.6x2.6mm_P0.5mm_EP1.3x2.2mm_ThermalVias +Package_DFN_QFN:DFN-10-1EP_2x3mm_P0.5mm_EP0.64x2.4mm +Package_DFN_QFN:DFN-10-1EP_3x3mm_P0.5mm_EP1.55x2.48mm +Package_DFN_QFN:DFN-10-1EP_3x3mm_P0.5mm_EP1.58x2.35mm +Package_DFN_QFN:DFN-10-1EP_3x3mm_P0.5mm_EP1.58x2.35mm_ThermalVias +Package_DFN_QFN:DFN-10-1EP_3x3mm_P0.5mm_EP1.65x2.38mm +Package_DFN_QFN:DFN-10-1EP_3x3mm_P0.5mm_EP1.65x2.38mm_ThermalVias +Package_DFN_QFN:DFN-10-1EP_3x3mm_P0.5mm_EP1.75x2.7mm +Package_DFN_QFN:DFN-10-1EP_3x3mm_P0.5mm_EP1.7x2.5mm +Package_DFN_QFN:DFN-10_2x2mm_P0.4mm +Package_DFN_QFN:DFN-12-1EP_2x3mm_P0.45mm_EP0.64x2.4mm +Package_DFN_QFN:DFN-12-1EP_3x3mm_P0.45mm_EP1.65x2.38mm +Package_DFN_QFN:DFN-12-1EP_3x3mm_P0.45mm_EP1.65x2.38mm_ThermalVias +Package_DFN_QFN:DFN-12-1EP_3x3mm_P0.5mm_EP1.6x2.5mm +Package_DFN_QFN:DFN-12-1EP_3x3mm_P0.5mm_EP1.6x2.5mm_ThermalVias +Package_DFN_QFN:DFN-12-1EP_3x3mm_P0.5mm_EP2.05x2.86mm +Package_DFN_QFN:DFN-12-1EP_3x4mm_P0.5mm_EP1.7x3.3mm +Package_DFN_QFN:DFN-12-1EP_4x4mm_P0.5mm_EP2.66x3.38mm +Package_DFN_QFN:DFN-12-1EP_4x4mm_P0.65mm_EP2.64x3.54mm +Package_DFN_QFN:DFN-14-1EP_3x3mm_P0.4mm_EP1.78x2.35mm +Package_DFN_QFN:DFN-14-1EP_3x4.5mm_P0.65mm_EP1.65x4.25mm +Package_DFN_QFN:DFN-14-1EP_3x4.5mm_P0.65mm_EP1.65x4.25mm_ThermalVias +Package_DFN_QFN:DFN-14-1EP_3x4mm_P0.5mm_EP1.7x3.3mm +Package_DFN_QFN:DFN-14_1.35x3.5mm_P0.5mm +Package_DFN_QFN:DFN-16-1EP_3x4mm_P0.45mm_EP1.7x3.3mm +Package_DFN_QFN:DFN-16-1EP_3x5mm_P0.5mm_EP1.66x4.4mm +Package_DFN_QFN:DFN-16-1EP_4x5mm_P0.5mm_EP2.44x4.34mm +Package_DFN_QFN:DFN-16-1EP_5x5mm_P0.5mm_EP3.46x4mm +Package_DFN_QFN:DFN-18-1EP_3x5mm_P0.5mm_EP1.66x4.4mm +Package_DFN_QFN:DFN-18-1EP_4x5mm_P0.5mm_EP2.44x4.34mm +Package_DFN_QFN:DFN-20-1EP_5x6mm_P0.5mm_EP3.24x4.24mm +Package_DFN_QFN:DFN-22-1EP_5x6mm_P0.5mm_EP3.14x4.3mm +Package_DFN_QFN:DFN-24-1EP_4x7mm_P0.5mm_EP2.64x6.44mm +Package_DFN_QFN:DFN-32-1EP_4x7mm_P0.4mm_EP2.64x6.44mm +Package_DFN_QFN:DFN-44-1EP_5x8.9mm_P0.4mm_EP3.7x8.4mm +Package_DFN_QFN:DFN-4_5x7mm_P5.08mm +Package_DFN_QFN:DFN-6-1EP_1.2x1.2mm_P0.4mm_EP0.3x0.94mm_PullBack +Package_DFN_QFN:DFN-6-1EP_2x1.6mm_P0.5mm_EP1.15x1.3mm +Package_DFN_QFN:DFN-6-1EP_2x1.8mm_P0.5mm_EP1.2x1.6mm +Package_DFN_QFN:DFN-6-1EP_2x2mm_P0.5mm_EP0.61x1.42mm +Package_DFN_QFN:DFN-6-1EP_2x2mm_P0.5mm_EP0.6x1.37mm +Package_DFN_QFN:DFN-6-1EP_2x2mm_P0.5mm_EP0.7x1.6mm +Package_DFN_QFN:DFN-6-1EP_2x2mm_P0.65mm_EP1.01x1.7mm +Package_DFN_QFN:DFN-6-1EP_2x2mm_P0.65mm_EP1x1.6mm +Package_DFN_QFN:DFN-6-1EP_3x2mm_P0.5mm_EP1.65x1.35mm +Package_DFN_QFN:DFN-6-1EP_3x3mm_P0.95mm_EP1.7x2.6mm +Package_DFN_QFN:DFN-6-1EP_3x3mm_P1mm_EP1.5x2.4mm +Package_DFN_QFN:DFN-6_1.3x1.2mm_P0.4mm +Package_DFN_QFN:DFN-6_1.6x1.3mm_P0.4mm +Package_DFN_QFN:DFN-8-1EP_1.5x1.5mm_P0.4mm_EP0.7x1.2mm +Package_DFN_QFN:DFN-8-1EP_2x2mm_P0.45mm_EP0.64x1.37mm +Package_DFN_QFN:DFN-8-1EP_2x2mm_P0.5mm_EP0.6x1.2mm +Package_DFN_QFN:DFN-8-1EP_2x2mm_P0.5mm_EP0.86x1.55mm +Package_DFN_QFN:DFN-8-1EP_2x2mm_P0.5mm_EP0.8x1.6mm +Package_DFN_QFN:DFN-8-1EP_2x2mm_P0.5mm_EP0.9x1.3mm +Package_DFN_QFN:DFN-8-1EP_2x2mm_P0.5mm_EP0.9x1.5mm +Package_DFN_QFN:DFN-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mm +Package_DFN_QFN:DFN-8-1EP_2x2mm_P0.5mm_EP0.9x1.7mm +Package_DFN_QFN:DFN-8-1EP_2x2mm_P0.5mm_EP1.05x1.75mm +Package_DFN_QFN:DFN-8-1EP_2x3mm_P0.5mm_EP0.61x2.2mm +Package_DFN_QFN:DFN-8-1EP_3x2mm_P0.45mm_EP1.66x1.36mm +Package_DFN_QFN:DFN-8-1EP_3x2mm_P0.5mm_EP1.36x1.46mm +Package_DFN_QFN:DFN-8-1EP_3x2mm_P0.5mm_EP1.3x1.5mm +Package_DFN_QFN:DFN-8-1EP_3x2mm_P0.5mm_EP1.75x1.45mm +Package_DFN_QFN:DFN-8-1EP_3x2mm_P0.5mm_EP1.7x1.4mm +Package_DFN_QFN:DFN-8-1EP_3x2mm_P0.5mm_EP1.7x1.6mm +Package_DFN_QFN:DFN-8-1EP_3x3mm_P0.5mm_EP1.65x2.38mm +Package_DFN_QFN:DFN-8-1EP_3x3mm_P0.5mm_EP1.65x2.38mm_ThermalVias +Package_DFN_QFN:DFN-8-1EP_3x3mm_P0.5mm_EP1.66x2.38mm +Package_DFN_QFN:DFN-8-1EP_3x3mm_P0.5mm_EP1.7x2.4mm +Package_DFN_QFN:DFN-8-1EP_3x3mm_P0.5mm_EP1.7x2.4mm_ThermalVias +Package_DFN_QFN:DFN-8-1EP_3x3mm_P0.65mm_EP1.55x2.4mm +Package_DFN_QFN:DFN-8-1EP_3x3mm_P0.65mm_EP1.5x2.25mm +Package_DFN_QFN:DFN-8-1EP_3x3mm_P0.65mm_EP1.7x2.05mm +Package_DFN_QFN:DFN-8-1EP_4x4mm_P0.8mm_EP2.39x2.21mm +Package_DFN_QFN:DFN-8-1EP_4x4mm_P0.8mm_EP2.3x3.24mm +Package_DFN_QFN:DFN-8-1EP_4x4mm_P0.8mm_EP2.5x3.6mm +Package_DFN_QFN:DFN-8-1EP_6x5mm_P1.27mm_EP2x2mm +Package_DFN_QFN:DFN-8-1EP_6x5mm_P1.27mm_EP4x4mm +Package_DFN_QFN:DFN-8_2x2mm_P0.5mm +Package_DFN_QFN:DFN-S-8-1EP_6x5mm_P1.27mm +Package_DFN_QFN:DHVQFN-14-1EP_2.5x3mm_P0.5mm_EP1x1.5mm +Package_DFN_QFN:DHVQFN-16-1EP_2.5x3.5mm_P0.5mm_EP1x2mm +Package_DFN_QFN:DHVQFN-20-1EP_2.5x4.5mm_P0.5mm_EP1x3mm +Package_DFN_QFN:Diodes_DFN1006-3 +Package_DFN_QFN:Diodes_UDFN-10_1.0x2.5mm_P0.5mm +Package_DFN_QFN:Diodes_UDFN2020-6_Type-F +Package_DFN_QFN:Diodes_UDFN3810-9_TYPE_B +Package_DFN_QFN:Diodes_ZL32_TQFN-32-1EP_3x6mm_P0.4mm_EP1.25x3.5mm +Package_DFN_QFN:EPC_QFN-13-3EP_3.5x5mm_P0.5mm +Package_DFN_QFN:HVQFN-16-1EP_3x3mm_P0.5mm_EP1.5x1.5mm +Package_DFN_QFN:HVQFN-24-1EP_4x4mm_P0.5mm_EP2.1x2.1mm +Package_DFN_QFN:HVQFN-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm +Package_DFN_QFN:HVQFN-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias +Package_DFN_QFN:HVQFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm +Package_DFN_QFN:HVQFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:HVQFN-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm +Package_DFN_QFN:HVQFN-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm_ThermalVias +Package_DFN_QFN:HVQFN-40-1EP_6x6mm_P0.5mm_EP4.1x4.1mm +Package_DFN_QFN:HVQFN-40-1EP_6x6mm_P0.5mm_EP4.1x4.1mm_ThermalVias +Package_DFN_QFN:HXQFN-16-1EP_3x3mm_P0.5mm_EP1.85x1.85mm +Package_DFN_QFN:HXQFN-16-1EP_3x3mm_P0.5mm_EP1.85x1.85mm_ThermalVias +Package_DFN_QFN:Infineon_MLPQ-16-14-1EP_4x4mm_P0.5mm +Package_DFN_QFN:Infineon_MLPQ-40-32-1EP_7x7mm_P0.5mm +Package_DFN_QFN:Infineon_MLPQ-48-1EP_7x7mm_P0.5mm_EP5.15x5.15mm +Package_DFN_QFN:Infineon_MLPQ-48-1EP_7x7mm_P0.5mm_EP5.55x5.55mm +Package_DFN_QFN:Infineon_PQFN-22-15-4EP_6x5mm_P0.65mm +Package_DFN_QFN:Infineon_PQFN-44-31-5EP_7x7mm_P0.5mm +Package_DFN_QFN:Linear_DE14MA +Package_DFN_QFN:Linear_UGK52_QFN-46-52 +Package_DFN_QFN:LQFN-10-1EP_2x2mm_P0.5mm_EP0.7x0.7mm +Package_DFN_QFN:LQFN-12-1EP_2x2mm_P0.5mm_EP0.7x0.7mm +Package_DFN_QFN:LQFN-16-1EP_3x3mm_P0.5mm_EP1.7x1.7mm +Package_DFN_QFN:Maxim_FC2QFN-14_2.5x2.5mm_P0.5mm +Package_DFN_QFN:Maxim_TDFN-12-1EP_3x3mm_P0.5mm_EP1.7x2.5mm +Package_DFN_QFN:Maxim_TDFN-12-1EP_3x3mm_P0.5mm_EP1.7x2.5mm_ThermalVias +Package_DFN_QFN:Maxim_TDFN-6-1EP_3x3mm_P0.95mm_EP1.5x2.3mm +Package_DFN_QFN:Micrel_MLF-8-1EP_2x2mm_P0.5mm_EP0.6x1.2mm +Package_DFN_QFN:Micrel_MLF-8-1EP_2x2mm_P0.5mm_EP0.6x1.2mm_ThermalVias +Package_DFN_QFN:Micrel_MLF-8-1EP_2x2mm_P0.5mm_EP0.8x1.3mm_ThermalVias +Package_DFN_QFN:Microchip_8E-16 +Package_DFN_QFN:Microchip_DRQFN-44-1EP_5x5mm_P0.7mm_EP2.65x2.65mm +Package_DFN_QFN:Microchip_DRQFN-44-1EP_5x5mm_P0.7mm_EP2.65x2.65mm_ThermalVias +Package_DFN_QFN:Microchip_DRQFN-64-1EP_7x7mm_P0.65mm_EP4.1x4.1mm +Package_DFN_QFN:Microchip_DRQFN-64-1EP_7x7mm_P0.65mm_EP4.1x4.1mm_ThermalVias +Package_DFN_QFN:Microsemi_QFN-40-32-2EP_6x8mm_P0.5mm +Package_DFN_QFN:Mini-Circuits_DL805 +Package_DFN_QFN:Mini-Circuits_FG873-4_3x3mm +Package_DFN_QFN:MLF-20-1EP_4x4mm_P0.5mm_EP2.6x2.6mm +Package_DFN_QFN:MLF-20-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:MLF-6-1EP_1.6x1.6mm_P0.5mm_EP0.5x1.26mm +Package_DFN_QFN:MLF-8-1EP_3x3mm_P0.65mm_EP1.55x2.3mm +Package_DFN_QFN:MLF-8-1EP_3x3mm_P0.65mm_EP1.55x2.3mm_ThermalVias +Package_DFN_QFN:MLPQ-16-1EP_4x4mm_P0.65mm_EP2.8x2.8mm +Package_DFN_QFN:MPS_QFN-12_2x2mm_P0.4mm +Package_DFN_QFN:Nordic_AQFN-73-1EP_7x7mm_P0.5mm +Package_DFN_QFN:Nordic_AQFN-94-1EP_7x7mm_P0.4mm +Package_DFN_QFN:NXP_LQFN-48-1EP_7x7mm_P0.5mm_EP3.5x3.5mm_16xMask0.45x0.45 +Package_DFN_QFN:NXP_LQFN-48-1EP_7x7mm_P0.5mm_EP3.5x3.5mm_16xMask0.45x0.45_ThermalVias +Package_DFN_QFN:OnSemi_DFN-14-1EP_4x4mm_P0.5mm_EP2.7x3.4mm +Package_DFN_QFN:OnSemi_DFN-8_2x2mm_P0.5mm +Package_DFN_QFN:OnSemi_SIP-38-6EP-9x7mm_P0.65mm_EP1.2x1.2mm +Package_DFN_QFN:OnSemi_UDFN-16-1EP_1.35x3.3mm_P0.4mm_EP0.4x2.8mm +Package_DFN_QFN:OnSemi_UDFN-8_1.2x1.8mm_P0.4mm +Package_DFN_QFN:OnSemi_VCT-28_3.5x3.5mm_P0.4mm +Package_DFN_QFN:OnSemi_XDFN-10_1.35x2.2mm_P0.4mm +Package_DFN_QFN:OnSemi_XDFN4-1EP_1.0x1.0mm_EP0.52x0.52mm +Package_DFN_QFN:Panasonic_HQFN-16-1EP_4x4mm_P0.65mm_EP2.9x2.9mm +Package_DFN_QFN:Panasonic_HSON-8_8x8mm_P2.00mm +Package_DFN_QFN:PQFN-8-EP_6x5mm_P1.27mm_Generic +Package_DFN_QFN:QFN-12-1EP_3x3mm_P0.51mm_EP1.45x1.45mm +Package_DFN_QFN:QFN-12-1EP_3x3mm_P0.5mm_EP1.65x1.65mm +Package_DFN_QFN:QFN-12-1EP_3x3mm_P0.5mm_EP1.65x1.65mm_ThermalVias +Package_DFN_QFN:QFN-12-1EP_3x3mm_P0.5mm_EP1.6x1.6mm +Package_DFN_QFN:QFN-12-1EP_3x3mm_P0.5mm_EP1.6x1.6mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_1.8x2.6mm_P0.4mm_EP0.7x1.5mm +Package_DFN_QFN:QFN-16-1EP_1.8x2.6mm_P0.4mm_EP0.7x1.5mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.45x1.45mm +Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.45x1.45mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.675x1.675mm +Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.75x1.75mm +Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.75x1.75mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.7x1.7mm +Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.7x1.7mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.9x1.9mm +Package_DFN_QFN:QFN-16-1EP_3x3mm_P0.5mm_EP1.9x1.9mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.5mm_EP2.45x2.45mm +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.5mm_EP2.45x2.45mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.15x2.15mm +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.15x2.15mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.1x2.1mm +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.1x2.1mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.5x2.5mm +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.5x2.5mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.7x2.7mm +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.7x2.7mm_PullBack +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.7x2.7mm_PullBack_ThermalVias +Package_DFN_QFN:QFN-16-1EP_4x4mm_P0.65mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:QFN-16-1EP_5x5mm_P0.8mm_EP2.7x2.7mm +Package_DFN_QFN:QFN-16-1EP_5x5mm_P0.8mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:QFN-20-1EP_3.5x3.5mm_P0.5mm_EP2x2mm +Package_DFN_QFN:QFN-20-1EP_3.5x3.5mm_P0.5mm_EP2x2mm_ThermalVias +Package_DFN_QFN:QFN-20-1EP_3x3mm_P0.45mm_EP1.6x1.6mm +Package_DFN_QFN:QFN-20-1EP_3x3mm_P0.45mm_EP1.6x1.6mm_ThermalVias +Package_DFN_QFN:QFN-20-1EP_3x3mm_P0.4mm_EP1.65x1.65mm +Package_DFN_QFN:QFN-20-1EP_3x3mm_P0.4mm_EP1.65x1.65mm_ThermalVias +Package_DFN_QFN:QFN-20-1EP_3x4mm_P0.5mm_EP1.65x2.65mm +Package_DFN_QFN:QFN-20-1EP_3x4mm_P0.5mm_EP1.65x2.65mm_ThermalVias +Package_DFN_QFN:QFN-20-1EP_4x4mm_P0.5mm_EP2.5x2.5mm +Package_DFN_QFN:QFN-20-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias +Package_DFN_QFN:QFN-20-1EP_4x4mm_P0.5mm_EP2.6x2.6mm +Package_DFN_QFN:QFN-20-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:QFN-20-1EP_4x4mm_P0.5mm_EP2.7x2.7mm +Package_DFN_QFN:QFN-20-1EP_4x4mm_P0.5mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:QFN-20-1EP_4x5mm_P0.5mm_EP2.65x3.65mm +Package_DFN_QFN:QFN-20-1EP_4x5mm_P0.5mm_EP2.65x3.65mm_ThermalVias +Package_DFN_QFN:QFN-20-1EP_5x5mm_P0.65mm_EP3.35x3.35mm +Package_DFN_QFN:QFN-20-1EP_5x5mm_P0.65mm_EP3.35x3.35mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_3x3mm_P0.4mm_EP1.75x1.6mm +Package_DFN_QFN:QFN-24-1EP_3x3mm_P0.4mm_EP1.75x1.6mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_3x4mm_P0.4mm_EP1.65x2.65mm +Package_DFN_QFN:QFN-24-1EP_3x4mm_P0.4mm_EP1.65x2.65mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.15x2.15mm +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.15x2.15mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.65x2.65mm +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.65x2.65mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.75x2.75mm +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.75x2.75mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.6mm +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.6mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.7mm +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.8x2.8mm +Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.8x2.8mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_4x5mm_P0.5mm_EP2.65x3.65mm +Package_DFN_QFN:QFN-24-1EP_4x5mm_P0.5mm_EP2.65x3.65mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_5x5mm_P0.65mm_EP3.25x3.25mm +Package_DFN_QFN:QFN-24-1EP_5x5mm_P0.65mm_EP3.25x3.25mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_5x5mm_P0.65mm_EP3.2x3.2mm +Package_DFN_QFN:QFN-24-1EP_5x5mm_P0.65mm_EP3.2x3.2mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_5x5mm_P0.65mm_EP3.4x3.4mm +Package_DFN_QFN:QFN-24-1EP_5x5mm_P0.65mm_EP3.4x3.4mm_ThermalVias +Package_DFN_QFN:QFN-24-1EP_5x5mm_P0.65mm_EP3.6x3.6mm +Package_DFN_QFN:QFN-24-1EP_5x5mm_P0.65mm_EP3.6x3.6mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_3x6mm_P0.5mm_EP1.7x4.75mm +Package_DFN_QFN:QFN-28-1EP_3x6mm_P0.5mm_EP1.7x4.75mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.45mm_EP2.4x2.4mm +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.45mm_EP2.4x2.4mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.45mm_EP2.6x2.6mm +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.4mm_EP2.3x2.3mm +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.4mm_EP2.3x2.3mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.4mm_EP2.4x2.4mm +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.4mm_EP2.4x2.4mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.4mm_EP2.6x2.6mm +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.4mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_4x4mm_P0.4mm_EP2.7x2.7mm +Package_DFN_QFN:QFN-28-1EP_4x5mm_P0.5mm_EP2.65x3.65mm +Package_DFN_QFN:QFN-28-1EP_4x5mm_P0.5mm_EP2.65x3.65mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP2.7x2.7mm +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP3.1x3.1mm +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP3.1x3.1mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP3.25x3.25mm +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP3.25x3.25mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP3.35x3.35mm +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP3.35x3.35mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP3.75x3.75mm +Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP3.75x3.75mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_5x6mm_P0.5mm_EP3.65x4.65mm +Package_DFN_QFN:QFN-28-1EP_5x6mm_P0.5mm_EP3.65x4.65mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_6x6mm_P0.65mm_EP4.25x4.25mm +Package_DFN_QFN:QFN-28-1EP_6x6mm_P0.65mm_EP4.25x4.25mm_ThermalVias +Package_DFN_QFN:QFN-28-1EP_6x6mm_P0.65mm_EP4.8x4.8mm +Package_DFN_QFN:QFN-28-1EP_6x6mm_P0.65mm_EP4.8x4.8mm_ThermalVias +Package_DFN_QFN:QFN-28_4x4mm_P0.5mm +Package_DFN_QFN:QFN-32-1EP_4x4mm_P0.4mm_EP2.65x2.65mm +Package_DFN_QFN:QFN-32-1EP_4x4mm_P0.4mm_EP2.65x2.65mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_4x4mm_P0.4mm_EP2.9x2.9mm +Package_DFN_QFN:QFN-32-1EP_4x4mm_P0.4mm_EP2.9x2.9mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.3x3.3mm +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.3x3.3mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.65x3.65mm +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.65x3.65mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.6x3.6mm +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.6x3.6mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.7x3.7mm +Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.7x3.7mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_7x7mm_P0.65mm_EP4.65x4.65mm +Package_DFN_QFN:QFN-32-1EP_7x7mm_P0.65mm_EP4.65x4.65mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_7x7mm_P0.65mm_EP4.7x4.7mm +Package_DFN_QFN:QFN-32-1EP_7x7mm_P0.65mm_EP4.7x4.7mm_ThermalVias +Package_DFN_QFN:QFN-32-1EP_7x7mm_P0.65mm_EP5.4x5.4mm +Package_DFN_QFN:QFN-32-1EP_7x7mm_P0.65mm_EP5.4x5.4mm_ThermalVias +Package_DFN_QFN:QFN-36-1EP_5x6mm_P0.5mm_EP3.6x4.1mm +Package_DFN_QFN:QFN-36-1EP_5x6mm_P0.5mm_EP3.6x4.1mm_ThermalVias +Package_DFN_QFN:QFN-36-1EP_5x6mm_P0.5mm_EP3.6x4.6mm +Package_DFN_QFN:QFN-36-1EP_5x6mm_P0.5mm_EP3.6x4.6mm_ThermalVias +Package_DFN_QFN:QFN-36-1EP_6x6mm_P0.5mm_EP3.7x3.7mm +Package_DFN_QFN:QFN-36-1EP_6x6mm_P0.5mm_EP3.7x3.7mm_ThermalVias +Package_DFN_QFN:QFN-36-1EP_6x6mm_P0.5mm_EP4.1x4.1mm +Package_DFN_QFN:QFN-36-1EP_6x6mm_P0.5mm_EP4.1x4.1mm_ThermalVias +Package_DFN_QFN:QFN-38-1EP_4x6mm_P0.4mm_EP2.65x4.65mm +Package_DFN_QFN:QFN-38-1EP_4x6mm_P0.4mm_EP2.65x4.65mm_ThermalVias +Package_DFN_QFN:QFN-38-1EP_5x7mm_P0.5mm_EP3.15x5.15mm +Package_DFN_QFN:QFN-38-1EP_5x7mm_P0.5mm_EP3.15x5.15mm_ThermalVias +Package_DFN_QFN:QFN-40-1EP_5x5mm_P0.4mm_EP3.6x3.6mm +Package_DFN_QFN:QFN-40-1EP_5x5mm_P0.4mm_EP3.6x3.6mm_ThermalVias +Package_DFN_QFN:QFN-40-1EP_5x5mm_P0.4mm_EP3.8x3.8mm +Package_DFN_QFN:QFN-40-1EP_5x5mm_P0.4mm_EP3.8x3.8mm_ThermalVias +Package_DFN_QFN:QFN-40-1EP_6x6mm_P0.5mm_EP4.6x4.6mm +Package_DFN_QFN:QFN-40-1EP_6x6mm_P0.5mm_EP4.6x4.6mm_ThermalVias +Package_DFN_QFN:QFN-42-1EP_5x6mm_P0.4mm_EP3.7x4.7mm +Package_DFN_QFN:QFN-42-1EP_5x6mm_P0.4mm_EP3.7x4.7mm_ThermalVias +Package_DFN_QFN:QFN-44-1EP_7x7mm_P0.5mm_EP5.15x5.15mm +Package_DFN_QFN:QFN-44-1EP_7x7mm_P0.5mm_EP5.15x5.15mm_ThermalVias +Package_DFN_QFN:QFN-44-1EP_7x7mm_P0.5mm_EP5.2x5.2mm +Package_DFN_QFN:QFN-44-1EP_7x7mm_P0.5mm_EP5.2x5.2mm_ThermalVias +Package_DFN_QFN:QFN-44-1EP_8x8mm_P0.65mm_EP6.45x6.45mm +Package_DFN_QFN:QFN-44-1EP_8x8mm_P0.65mm_EP6.45x6.45mm_ThermalVias +Package_DFN_QFN:QFN-44-1EP_9x9mm_P0.65mm_EP7.5x7.5mm +Package_DFN_QFN:QFN-44-1EP_9x9mm_P0.65mm_EP7.5x7.5mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_5x5mm_P0.35mm_EP3.7x3.7mm +Package_DFN_QFN:QFN-48-1EP_5x5mm_P0.35mm_EP3.7x3.7mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_6x6mm_P0.4mm_EP4.2x4.2mm +Package_DFN_QFN:QFN-48-1EP_6x6mm_P0.4mm_EP4.2x4.2mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_6x6mm_P0.4mm_EP4.3x4.3mm +Package_DFN_QFN:QFN-48-1EP_6x6mm_P0.4mm_EP4.3x4.3mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_6x6mm_P0.4mm_EP4.66x4.66mm +Package_DFN_QFN:QFN-48-1EP_6x6mm_P0.4mm_EP4.66x4.66mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_6x6mm_P0.4mm_EP4.6x4.6mm +Package_DFN_QFN:QFN-48-1EP_6x6mm_P0.4mm_EP4.6x4.6mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP3.5x3.5mm +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP3.5x3.5mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.15x5.15mm +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.15x5.15mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.1x5.1mm +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.1x5.1mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.3x5.3mm +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.3x5.3mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.45x5.45mm +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.45x5.45mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.6x5.6mm +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.6x5.6mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.7x5.7mm +Package_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.7x5.7mm_ThermalVias +Package_DFN_QFN:QFN-48-1EP_8x8mm_P0.5mm_EP6.2x6.2mm +Package_DFN_QFN:QFN-48-1EP_8x8mm_P0.5mm_EP6.2x6.2mm_ThermalVias +Package_DFN_QFN:QFN-52-1EP_7x8mm_P0.5mm_EP5.41x6.45mm +Package_DFN_QFN:QFN-52-1EP_7x8mm_P0.5mm_EP5.41x6.45mm_ThermalVias +Package_DFN_QFN:QFN-56-1EP_7x7mm_P0.4mm_EP3.2x3.2mm +Package_DFN_QFN:QFN-56-1EP_7x7mm_P0.4mm_EP3.2x3.2mm_ThermalVias +Package_DFN_QFN:QFN-56-1EP_7x7mm_P0.4mm_EP4x4mm +Package_DFN_QFN:QFN-56-1EP_7x7mm_P0.4mm_EP4x4mm_ThermalVias +Package_DFN_QFN:QFN-56-1EP_7x7mm_P0.4mm_EP5.6x5.6mm +Package_DFN_QFN:QFN-56-1EP_7x7mm_P0.4mm_EP5.6x5.6mm_ThermalVias +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP4.3x4.3mm +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP4.3x4.3mm_ThermalVias +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP4.5x5.2mm +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP4.5x5.2mm_ThermalVias +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP4.5x5.2mm_ThermalVias_TopTented +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP5.6x5.6mm +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP5.6x5.6mm_ThermalVias +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP5.9x5.9mm +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP5.9x5.9mm_ThermalVias +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP6.1x6.1mm +Package_DFN_QFN:QFN-56-1EP_8x8mm_P0.5mm_EP6.1x6.1mm_ThermalVias +Package_DFN_QFN:QFN-60-1EP_7x7mm_P0.4mm_EP3.4x3.4mm +Package_DFN_QFN:QFN-60-1EP_7x7mm_P0.4mm_EP3.4x3.4mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_8x8mm_P0.4mm_EP6.5x6.5mm +Package_DFN_QFN:QFN-64-1EP_8x8mm_P0.4mm_EP6.5x6.5mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP3.4x3.4mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP3.4x3.4mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP3.8x3.8mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP3.8x3.8mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP4.1x4.1mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP4.1x4.1mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP4.35x4.35mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP4.35x4.35mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP4.7x4.7mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP4.7x4.7mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP5.2x5.2mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP5.2x5.2mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP5.45x5.45mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP5.45x5.45mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP5.4x5.4mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP5.4x5.4mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP5.7x5.7mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP5.7x5.7mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP6x6mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP6x6mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.15x7.15mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.15x7.15mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.25x7.25mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.35x7.35mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.3x7.3mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.3x7.3mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.5x7.5mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.5x7.5mm_ThermalVias +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.65x7.65mm +Package_DFN_QFN:QFN-64-1EP_9x9mm_P0.5mm_EP7.65x7.65mm_ThermalVias +Package_DFN_QFN:QFN-68-1EP_8x8mm_P0.4mm_EP5.2x5.2mm +Package_DFN_QFN:QFN-68-1EP_8x8mm_P0.4mm_EP5.2x5.2mm_ThermalVias +Package_DFN_QFN:QFN-68-1EP_8x8mm_P0.4mm_EP6.4x6.4mm +Package_DFN_QFN:QFN-68-1EP_8x8mm_P0.4mm_EP6.4x6.4mm_ThermalVias +Package_DFN_QFN:QFN-72-1EP_10x10mm_P0.5mm_EP6x6mm +Package_DFN_QFN:QFN-72-1EP_10x10mm_P0.5mm_EP6x6mm_ThermalVias +Package_DFN_QFN:QFN-76-1EP_9x9mm_P0.4mm_EP3.8x3.8mm +Package_DFN_QFN:QFN-76-1EP_9x9mm_P0.4mm_EP3.8x3.8mm_ThermalVias +Package_DFN_QFN:QFN-76-1EP_9x9mm_P0.4mm_EP5.81x6.31mm +Package_DFN_QFN:QFN-76-1EP_9x9mm_P0.4mm_EP5.81x6.31mm_ThermalVias +Package_DFN_QFN:QFN-80-1EP_10x10mm_P0.4mm_EP3.4x3.4mm +Package_DFN_QFN:QFN-80-1EP_10x10mm_P0.4mm_EP3.4x3.4mm_ThermalVias +Package_DFN_QFN:Qorvo_DFN-8-1EP_2x2mm_P0.5mm +Package_DFN_QFN:Qorvo_TQFN66-48-1EP_6x6mm_P0.4mm_EP4.2x4.2mm +Package_DFN_QFN:Qorvo_TQFN66-48-1EP_6x6mm_P0.4mm_EP4.2x4.2mm_ThermalVias +Package_DFN_QFN:ROHM_DFN0604-3 +Package_DFN_QFN:SiliconLabs_QFN-20-1EP_3x3mm_P0.5mm_EP1.8x1.8mm +Package_DFN_QFN:SiliconLabs_QFN-20-1EP_3x3mm_P0.5mm_EP1.8x1.8mm_ThermalVias +Package_DFN_QFN:ST_UFDFPN-12-1EP_3x3mm_P0.5mm_EP1.4x2.55mm +Package_DFN_QFN:ST_UFQFPN-20_3x3mm_P0.5mm +Package_DFN_QFN:ST_UQFN-6L_1.5x1.7mm_P0.5mm +Package_DFN_QFN:TDFN-10-1EP_2x3mm_P0.5mm_EP0.9x2mm +Package_DFN_QFN:TDFN-10-1EP_2x3mm_P0.5mm_EP0.9x2mm_ThermalVias +Package_DFN_QFN:TDFN-12-1EP_3x3mm_P0.4mm_EP1.7x2.45mm +Package_DFN_QFN:TDFN-12-1EP_3x3mm_P0.4mm_EP1.7x2.45mm_ThermalVias +Package_DFN_QFN:TDFN-12_2x3mm_P0.5mm +Package_DFN_QFN:TDFN-14-1EP_3x3mm_P0.4mm_EP1.78x2.35mm +Package_DFN_QFN:TDFN-14-1EP_3x3mm_P0.4mm_EP1.78x2.35mm_ThermalVias +Package_DFN_QFN:TDFN-6-1EP_2.5x2.5mm_P0.65mm_EP1.3x2mm +Package_DFN_QFN:TDFN-6-1EP_2.5x2.5mm_P0.65mm_EP1.3x2mm_ThermalVias +Package_DFN_QFN:TDFN-8-1EP_2x2mm_P0.5mm_EP0.8x1.2mm +Package_DFN_QFN:TDFN-8-1EP_3x2mm_P0.5mm_EP1.3x1.4mm +Package_DFN_QFN:TDFN-8-1EP_3x2mm_P0.5mm_EP1.4x1.4mm +Package_DFN_QFN:TDFN-8-1EP_3x2mm_P0.5mm_EP1.80x1.65mm +Package_DFN_QFN:TDFN-8-1EP_3x2mm_P0.5mm_EP1.80x1.65mm_ThermalVias +Package_DFN_QFN:TDFN-8_1.4x1.6mm_P0.4mm +Package_DFN_QFN:Texas_B3QFN-14-1EP_5x5.5mm_P0.65mm +Package_DFN_QFN:Texas_B3QFN-14-1EP_5x5.5mm_P0.65mm_ThermalVia +Package_DFN_QFN:Texas_DRB0008A +Package_DFN_QFN:Texas_MOF0009A +Package_DFN_QFN:Texas_PicoStar_DFN-3_0.69x0.60mm +Package_DFN_QFN:Texas_QFN-41_10x16mm +Package_DFN_QFN:Texas_R-PUQFN-N10 +Package_DFN_QFN:Texas_R-PUQFN-N12 +Package_DFN_QFN:Texas_REF0038A_WQFN-38-2EP_6x4mm_P0.4 +Package_DFN_QFN:Texas_RGC0064B_VQFN-64-1EP_9x9mm_P0.5mm_EP4.25x4.25mm +Package_DFN_QFN:Texas_RGC0064B_VQFN-64-1EP_9x9mm_P0.5mm_EP4.25x4.25mm_ThermalVias +Package_DFN_QFN:Texas_RGE0024C_VQFN-24-1EP_4x4mm_P0.5mm_EP2.1x2.1mm +Package_DFN_QFN:Texas_RGE0024C_VQFN-24-1EP_4x4mm_P0.5mm_EP2.1x2.1mm_ThermalVias +Package_DFN_QFN:Texas_RGE0024H_VQFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.7mm +Package_DFN_QFN:Texas_RGE0024H_VQFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:Texas_RGP0020D_VQFN-20-1EP_4x4mm_P0.5mm_EP2.7x2.7mm +Package_DFN_QFN:Texas_RGP0020D_VQFN-20-1EP_4x4mm_P0.5mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:Texas_RGP0020H_VQFN-20-1EP_4x4mm_P0.5mm_EP2.4x2.4mm +Package_DFN_QFN:Texas_RGP0020H_VQFN-20-1EP_4x4mm_P0.5mm_EP2.4x2.4mm_ThermalVias +Package_DFN_QFN:Texas_RGV0016A_VQFN-16-1EP_4x4mm_P0.65mm_EP2.1x2.1mm +Package_DFN_QFN:Texas_RGV0016A_VQFN-16-1EP_4x4mm_P0.65mm_EP2.1x2.1mm_ThermalVias +Package_DFN_QFN:Texas_RGW0020A_VQFN-20-1EP_5x5mm_P0.65mm_EP3.15x3.15mm +Package_DFN_QFN:Texas_RGW0020A_VQFN-20-1EP_5x5mm_P0.65mm_EP3.15x3.15mm_ThermalVias +Package_DFN_QFN:Texas_RGY_R-PVQFN-N16_EP2.05x2.55mm +Package_DFN_QFN:Texas_RGY_R-PVQFN-N16_EP2.05x2.55mm_ThermalVias +Package_DFN_QFN:Texas_RGY_R-PVQFN-N20_EP2.05x3.05mm +Package_DFN_QFN:Texas_RGY_R-PVQFN-N20_EP2.05x3.05mm_ThermalVias +Package_DFN_QFN:Texas_RGY_R-PVQFN-N24_EP2.05x3.1mm +Package_DFN_QFN:Texas_RGY_R-PVQFN-N24_EP2.05x3.1mm_ThermalVias +Package_DFN_QFN:Texas_RGZ0048A_VQFN-48-1EP_7x7mm_P0.5mm_EP5.15x5.15mm +Package_DFN_QFN:Texas_RGZ0048A_VQFN-48-1EP_7x7mm_P0.5mm_EP5.15x5.15mm_ThermalVias +Package_DFN_QFN:Texas_RHA0040B_VQFN-40-1EP_6x6mm_P0.5mm_EP4.15x4.15mm +Package_DFN_QFN:Texas_RHA0040B_VQFN-40-1EP_6x6mm_P0.5mm_EP4.15x4.15mm_ThermalVias +Package_DFN_QFN:Texas_RHA0040D_VQFN-40-1EP_6x6mm_P0.5mm_EP2.9x2.9mm +Package_DFN_QFN:Texas_RHA0040D_VQFN-40-1EP_6x6mm_P0.5mm_EP2.9x2.9mm_ThermalVias +Package_DFN_QFN:Texas_RHA0040E_VQFN-40-1EP_6x6mm_P0.5mm_EP3.52x2.62mm +Package_DFN_QFN:Texas_RHA0040E_VQFN-40-1EP_6x6mm_P0.5mm_EP3.52x2.62mm_ThermalVias +Package_DFN_QFN:Texas_RHA_VQFN-40-1EP_6x6mm_P0.5mm_EP4.6x4.6mm +Package_DFN_QFN:Texas_RHA_VQFN-40-1EP_6x6mm_P0.5mm_EP4.6x4.6mm_ThermalVias +Package_DFN_QFN:Texas_RHB0032E_VQFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm +Package_DFN_QFN:Texas_RHB0032E_VQFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm_ThermalVias +Package_DFN_QFN:Texas_RHB0032M_VQFN-32-1EP_5x5mm_P0.5mm_EP2.1x2.1mm +Package_DFN_QFN:Texas_RHB0032M_VQFN-32-1EP_5x5mm_P0.5mm_EP2.1x2.1mm_ThermalVias +Package_DFN_QFN:Texas_RHH0036C_VQFN-36-1EP_6x6mm_P0.5mm_EP4.4x4.4mm +Package_DFN_QFN:Texas_RHH0036C_VQFN-36-1EP_6x6mm_P0.5mm_EP4.4x4.4mm_ThermalVias +Package_DFN_QFN:Texas_RJE0020A_VQFN-20-1EP_3x3mm_P0.45mm_EP0.675x0.76mm +Package_DFN_QFN:Texas_RJE0020A_VQFN-20-1EP_3x3mm_P0.45mm_EP0.675x0.76mm_ThermalVias +Package_DFN_QFN:Texas_RMG0012A_WQFN-12_1.8x1.8mm_P0.4mm +Package_DFN_QFN:Texas_RMQ0024A_WQFN-24-1EP_3x3mm_P0.4mm_EP1.9x1.9mm +Package_DFN_QFN:Texas_RMQ0024A_WQFN-24-1EP_3x3mm_P0.4mm_EP1.9x1.9mm_ThermalVias +Package_DFN_QFN:Texas_RNN0018A +Package_DFN_QFN:Texas_RNP0030B_WQFN-30-1EP_4x6mm_P0.5mm_EP1.8x4.5mm +Package_DFN_QFN:Texas_RNP0030B_WQFN-30-1EP_4x6mm_P0.5mm_EP1.8x4.5mm_ThermalVias +Package_DFN_QFN:Texas_RPU0010A_VQFN-HR-10_2x2mm_P0.5mm +Package_DFN_QFN:Texas_RSA_VQFN-16-1EP_4x4mm_P0.65mm_EP2.7x2.7mm +Package_DFN_QFN:Texas_RSA_VQFN-16-1EP_4x4mm_P0.65mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:Texas_RSN_WQFN-32-1EP_4x4mm_P0.4mm_EP2.8x2.8mm +Package_DFN_QFN:Texas_RSN_WQFN-32-1EP_4x4mm_P0.4mm_EP2.8x2.8mm_ThermalVias +Package_DFN_QFN:Texas_RSW0010A_UQFN-10_1.4x1.8mm_P0.4mm +Package_DFN_QFN:Texas_RTE0016D_WQFN-16-1EP_3x3mm_P0.5mm_EP0.8x0.8mm +Package_DFN_QFN:Texas_RTE0016D_WQFN-16-1EP_3x3mm_P0.5mm_EP0.8x0.8mm_ThermalVias +Package_DFN_QFN:Texas_RTE_WQFN-16-1EP_3x3mm_P0.5mm_EP1.2x0.8mm +Package_DFN_QFN:Texas_RTE_WQFN-16-1EP_3x3mm_P0.5mm_EP1.2x0.8mm_ThermalVias +Package_DFN_QFN:Texas_RTW_WQFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.7mm +Package_DFN_QFN:Texas_RTW_WQFN-24-1EP_4x4mm_P0.5mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:Texas_RTY_WQFN-16-1EP_4x4mm_P0.65mm_EP2.1x2.1mm +Package_DFN_QFN:Texas_RTY_WQFN-16-1EP_4x4mm_P0.65mm_EP2.1x2.1mm_ThermalVias +Package_DFN_QFN:Texas_RUM0016A_WQFN-16-1EP_4x4mm_P0.65mm_EP2.6x2.6mm +Package_DFN_QFN:Texas_RUM0016A_WQFN-16-1EP_4x4mm_P0.65mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:Texas_RUN0010A_WQFN-10_2x2mm_P0.5mm +Package_DFN_QFN:Texas_RVA_VQFN-16-1EP_3.5x3.5mm_P0.5mm_EP2.14x2.14mm +Package_DFN_QFN:Texas_RVA_VQFN-16-1EP_3.5x3.5mm_P0.5mm_EP2.14x2.14mm_ThermalVias +Package_DFN_QFN:Texas_RVE0028A_VQFN-28-1EP_3.5x4.5mm_P0.4mm_EP2.1x3.1mm +Package_DFN_QFN:Texas_RVE0028A_VQFN-28-1EP_3.5x4.5mm_P0.4mm_EP2.1x3.1mm_ThermalVias +Package_DFN_QFN:Texas_RWH0032A +Package_DFN_QFN:Texas_RWH0032A_ThermalVias +Package_DFN_QFN:Texas_RWU0007A_VQFN-7_2x2mm_P0.5mm +Package_DFN_QFN:Texas_S-PDSO-N10_EP1.2x2mm +Package_DFN_QFN:Texas_S-PDSO-N10_EP1.2x2mm_ThermalVias +Package_DFN_QFN:Texas_S-PVQFN-N14 +Package_DFN_QFN:Texas_S-PVQFN-N14_ThermalVias +Package_DFN_QFN:Texas_S-PWQFN-N100_EP5.5x5.5mm +Package_DFN_QFN:Texas_S-PWQFN-N100_EP5.5x5.5mm_ThermalVias +Package_DFN_QFN:Texas_S-PWQFN-N20 +Package_DFN_QFN:Texas_S-PX2QFN-14 +Package_DFN_QFN:Texas_UQFN-10_1.5x2mm_P0.5mm +Package_DFN_QFN:Texas_VQFN-HR-12_2x2.5mm_P0.5mm +Package_DFN_QFN:Texas_VQFN-HR-12_2x2.5mm_P0.5mm_ThermalVias +Package_DFN_QFN:Texas_VQFN-HR-20_3x2.5mm_P0.5mm_RQQ0011A +Package_DFN_QFN:Texas_VQFN-RHL-20 +Package_DFN_QFN:Texas_VQFN-RHL-20_ThermalVias +Package_DFN_QFN:Texas_VQFN-RNR0011A-11 +Package_DFN_QFN:Texas_WQFN-MR-100_3x3-DapStencil +Package_DFN_QFN:Texas_WQFN-MR-100_ThermalVias_3x3-DapStencil +Package_DFN_QFN:Texas_X2QFN-12_1.6x1.6mm_P0.4mm +Package_DFN_QFN:Texas_X2QFN-RUE-12_1.4x2mm_P0.4mm +Package_DFN_QFN:TQFN-16-1EP_3x3mm_P0.5mm_EP1.23x1.23mm +Package_DFN_QFN:TQFN-16-1EP_3x3mm_P0.5mm_EP1.23x1.23mm_ThermalVias +Package_DFN_QFN:TQFN-16-1EP_3x3mm_P0.5mm_EP1.6x1.6mm +Package_DFN_QFN:TQFN-16-1EP_5x5mm_P0.8mm_EP2.29x2.29mm +Package_DFN_QFN:TQFN-16-1EP_5x5mm_P0.8mm_EP2.29x2.29mm_ThermalVias +Package_DFN_QFN:TQFN-16-1EP_5x5mm_P0.8mm_EP3.1x3.1mm +Package_DFN_QFN:TQFN-16-1EP_5x5mm_P0.8mm_EP3.1x3.1mm_ThermalVias +Package_DFN_QFN:TQFN-20-1EP_4x4mm_P0.5mm_EP2.1x2.1mm +Package_DFN_QFN:TQFN-20-1EP_4x4mm_P0.5mm_EP2.1x2.1mm_ThermalVias +Package_DFN_QFN:TQFN-20-1EP_4x4mm_P0.5mm_EP2.7x2.7mm +Package_DFN_QFN:TQFN-20-1EP_4x4mm_P0.5mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:TQFN-20-1EP_4x4mm_P0.5mm_EP2.9x2.9mm +Package_DFN_QFN:TQFN-20-1EP_4x4mm_P0.5mm_EP2.9x2.9mm_ThermalVias +Package_DFN_QFN:TQFN-20-1EP_5x5mm_P0.65mm_EP3.1x3.1mm +Package_DFN_QFN:TQFN-20-1EP_5x5mm_P0.65mm_EP3.1x3.1mm_ThermalVias +Package_DFN_QFN:TQFN-20-1EP_5x5mm_P0.65mm_EP3.25x3.25mm +Package_DFN_QFN:TQFN-20-1EP_5x5mm_P0.65mm_EP3.25x3.25mm_ThermalVias +Package_DFN_QFN:TQFN-24-1EP_4x4mm_P0.5mm_EP2.1x2.1mm +Package_DFN_QFN:TQFN-24-1EP_4x4mm_P0.5mm_EP2.1x2.1mm_ThermalVias +Package_DFN_QFN:TQFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm +Package_DFN_QFN:TQFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:TQFN-24-1EP_4x4mm_P0.5mm_EP2.8x2.8mm_PullBack +Package_DFN_QFN:TQFN-24-1EP_4x4mm_P0.5mm_EP2.8x2.8mm_PullBack_ThermalVias +Package_DFN_QFN:TQFN-28-1EP_5x5mm_P0.5mm_EP2.7x2.7mm +Package_DFN_QFN:TQFN-28-1EP_5x5mm_P0.5mm_EP2.7x2.7mm_ThermalVias +Package_DFN_QFN:TQFN-28-1EP_5x5mm_P0.5mm_EP3.25x3.25mm +Package_DFN_QFN:TQFN-28-1EP_5x5mm_P0.5mm_EP3.25x3.25mm_ThermalVias +Package_DFN_QFN:TQFN-32-1EP_5x5mm_P0.5mm_EP2.1x2.1mm +Package_DFN_QFN:TQFN-32-1EP_5x5mm_P0.5mm_EP2.1x2.1mm_ThermalVias +Package_DFN_QFN:TQFN-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm +Package_DFN_QFN:TQFN-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm_ThermalVias +Package_DFN_QFN:TQFN-32-1EP_5x5mm_P0.5mm_EP3.4x3.4mm +Package_DFN_QFN:TQFN-32-1EP_5x5mm_P0.5mm_EP3.4x3.4mm_ThermalVias +Package_DFN_QFN:TQFN-40-1EP_5x5mm_P0.4mm_EP3.5x3.5mm +Package_DFN_QFN:TQFN-40-1EP_5x5mm_P0.4mm_EP3.5x3.5mm_ThermalVias +Package_DFN_QFN:TQFN-44-1EP_7x7mm_P0.5mm_EP4.7x4.7mm +Package_DFN_QFN:TQFN-44-1EP_7x7mm_P0.5mm_EP4.7x4.7mm_ThermalVias +Package_DFN_QFN:TQFN-48-1EP_7x7mm_P0.5mm_EP5.1x5.1mm +Package_DFN_QFN:TQFN-48-1EP_7x7mm_P0.5mm_EP5.1x5.1mm_ThermalVias +Package_DFN_QFN:UDC-QFN-20-4EP_3x4mm_P0.5mm_EP0.41x0.25mm +Package_DFN_QFN:UDFN-10_1.35x2.6mm_P0.5mm +Package_DFN_QFN:UDFN-4-1EP_1x1mm_P0.65mm_EP0.48x0.48mm +Package_DFN_QFN:UDFN-9_1.0x3.8mm_P0.5mm +Package_DFN_QFN:UFQFPN-32-1EP_5x5mm_P0.5mm_EP3.5x3.5mm +Package_DFN_QFN:UFQFPN-32-1EP_5x5mm_P0.5mm_EP3.5x3.5mm_ThermalVias +Package_DFN_QFN:UQFN-10_1.3x1.8mm_P0.4mm +Package_DFN_QFN:UQFN-10_1.4x1.8mm_P0.4mm +Package_DFN_QFN:UQFN-10_1.6x2.1mm_P0.5mm +Package_DFN_QFN:UQFN-16-1EP_3x3mm_P0.5mm_EP1.75x1.75mm +Package_DFN_QFN:UQFN-16-1EP_4x4mm_P0.65mm_EP2.6x2.6mm +Package_DFN_QFN:UQFN-16-1EP_4x4mm_P0.65mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:UQFN-16-1EP_4x4mm_P0.65mm_EP2.7x2.7mm +Package_DFN_QFN:UQFN-16_1.8x2.6mm_P0.4mm +Package_DFN_QFN:UQFN-20-1EP_3x3mm_P0.4mm_EP1.7x1.7mm +Package_DFN_QFN:UQFN-20-1EP_3x3mm_P0.4mm_EP1.7x1.7mm_ThermalVias +Package_DFN_QFN:UQFN-20-1EP_3x3mm_P0.4mm_EP1.85x1.85mm +Package_DFN_QFN:UQFN-20-1EP_3x3mm_P0.4mm_EP1.85x1.85mm_ThermalVias +Package_DFN_QFN:UQFN-20-1EP_4x4mm_P0.5mm_EP2.8x2.8mm +Package_DFN_QFN:UQFN-20-1EP_4x4mm_P0.5mm_EP2.8x2.8mm_ThermalVias +Package_DFN_QFN:UQFN-20_3x3mm_P0.4mm +Package_DFN_QFN:UQFN-28-1EP_4x4mm_P0.4mm_EP2.35x2.35mm +Package_DFN_QFN:UQFN-28-1EP_4x4mm_P0.4mm_EP2.35x2.35mm_ThermalVias +Package_DFN_QFN:UQFN-40-1EP_5x5mm_P0.4mm_EP3.8x3.8mm +Package_DFN_QFN:UQFN-40-1EP_5x5mm_P0.4mm_EP3.8x3.8mm_ThermalVias +Package_DFN_QFN:UQFN-48-1EP_6x6mm_P0.4mm_EP4.45x4.45mm +Package_DFN_QFN:UQFN-48-1EP_6x6mm_P0.4mm_EP4.45x4.45mm_ThermalVias +Package_DFN_QFN:UQFN-48-1EP_6x6mm_P0.4mm_EP4.62x4.62mm +Package_DFN_QFN:UQFN-48-1EP_6x6mm_P0.4mm_EP4.62x4.62mm_ThermalVias +Package_DFN_QFN:VDFN-8-1EP_2x2mm_P0.5mm_EP0.9x1.7mm +Package_DFN_QFN:Vishay_PowerPAK_MLP44-24L +Package_DFN_QFN:Vishay_PowerPAK_MLP44-24L_ThermalVias +Package_DFN_QFN:VQFN-100-1EP_12x12mm_P0.4mm_EP8x8mm +Package_DFN_QFN:VQFN-100-1EP_12x12mm_P0.4mm_EP8x8mm_ThermalVias +Package_DFN_QFN:VQFN-12-1EP_4x4mm_P0.8mm_EP2.1x2.1mm +Package_DFN_QFN:VQFN-12-1EP_4x4mm_P0.8mm_EP2.1x2.1mm_ThermalVias +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.1x1.1mm +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.1x1.1mm_ThermalVias +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.45x1.45mm +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.45x1.45mm_ThermalVias +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.68x1.68mm +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.68x1.68mm_ThermalVias +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.6x1.6mm +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.6x1.6mm_ThermalVias +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.8x1.8mm +Package_DFN_QFN:VQFN-16-1EP_3x3mm_P0.5mm_EP1.8x1.8mm_ThermalVias +Package_DFN_QFN:VQFN-20-1EP_3x3mm_P0.45mm_EP1.55x1.55mm +Package_DFN_QFN:VQFN-20-1EP_3x3mm_P0.45mm_EP1.55x1.55mm_ThermalVias +Package_DFN_QFN:VQFN-20-1EP_3x3mm_P0.4mm_EP1.7x1.7mm +Package_DFN_QFN:VQFN-20-1EP_3x3mm_P0.4mm_EP1.7x1.7mm_ThermalVias +Package_DFN_QFN:VQFN-24-1EP_4x4mm_P0.5mm_EP2.45x2.45mm +Package_DFN_QFN:VQFN-24-1EP_4x4mm_P0.5mm_EP2.45x2.45mm_ThermalVias +Package_DFN_QFN:VQFN-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm +Package_DFN_QFN:VQFN-24-1EP_4x4mm_P0.5mm_EP2.5x2.5mm_ThermalVias +Package_DFN_QFN:VQFN-28-1EP_4x4mm_P0.45mm_EP2.4x2.4mm +Package_DFN_QFN:VQFN-28-1EP_4x4mm_P0.45mm_EP2.4x2.4mm_ThermalVias +Package_DFN_QFN:VQFN-28-1EP_4x5mm_P0.5mm_EP2.55x3.55mm +Package_DFN_QFN:VQFN-28-1EP_4x5mm_P0.5mm_EP2.55x3.55mm_ThermalVias +Package_DFN_QFN:VQFN-28-1EP_5x5mm_P0.5mm_EP3.25x3.25mm +Package_DFN_QFN:VQFN-28-1EP_5x5mm_P0.5mm_EP3.25x3.25mm_ThermalVias +Package_DFN_QFN:VQFN-32-1EP_4x4mm_P0.4mm_EP2.8x2.8mm +Package_DFN_QFN:VQFN-32-1EP_4x4mm_P0.4mm_EP2.8x2.8mm_ThermalVias +Package_DFN_QFN:VQFN-32-1EP_5x5mm_P0.5mm_EP3.15x3.15mm +Package_DFN_QFN:VQFN-32-1EP_5x5mm_P0.5mm_EP3.15x3.15mm_ThermalVias +Package_DFN_QFN:VQFN-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm +Package_DFN_QFN:VQFN-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm_ThermalVias +Package_DFN_QFN:VQFN-32-1EP_5x5mm_P0.5mm_EP3.5x3.5mm +Package_DFN_QFN:VQFN-32-1EP_5x5mm_P0.5mm_EP3.5x3.5mm_ThermalVias +Package_DFN_QFN:VQFN-40-1EP_5x5mm_P0.4mm_EP3.5x3.5mm +Package_DFN_QFN:VQFN-40-1EP_5x5mm_P0.4mm_EP3.5x3.5mm_ThermalVias +Package_DFN_QFN:VQFN-40-1EP_5x5mm_P0.4mm_EP3.6x3.6mm +Package_DFN_QFN:VQFN-40-1EP_5x5mm_P0.4mm_EP3.6x3.6mm_ThermalVias +Package_DFN_QFN:VQFN-46-1EP_5x6mm_P0.4mm_EP2.8x3.8mm +Package_DFN_QFN:VQFN-46-1EP_5x6mm_P0.4mm_EP2.8x3.8mm_ThermalVias +Package_DFN_QFN:VQFN-48-1EP_6x6mm_P0.4mm_EP4.1x4.1mm +Package_DFN_QFN:VQFN-48-1EP_6x6mm_P0.4mm_EP4.1x4.1mm_ThermalVias +Package_DFN_QFN:VQFN-48-1EP_7x7mm_P0.5mm_EP4.1x4.1mm +Package_DFN_QFN:VQFN-48-1EP_7x7mm_P0.5mm_EP4.1x4.1mm_ThermalVias +Package_DFN_QFN:VQFN-48-1EP_7x7mm_P0.5mm_EP5.15x5.15mm +Package_DFN_QFN:VQFN-48-1EP_7x7mm_P0.5mm_EP5.15x5.15mm_ThermalVias +Package_DFN_QFN:VQFN-64-1EP_9x9mm_P0.5mm_EP5.4x5.4mm +Package_DFN_QFN:VQFN-64-1EP_9x9mm_P0.5mm_EP5.4x5.4mm_ThermalVias +Package_DFN_QFN:VQFN-64-1EP_9x9mm_P0.5mm_EP7.15x7.15mm +Package_DFN_QFN:VQFN-64-1EP_9x9mm_P0.5mm_EP7.15x7.15mm_ThermalVias +Package_DFN_QFN:W-PDFN-8-1EP_6x5mm_P1.27mm_EP3x3mm +Package_DFN_QFN:WCH_QFN-16-1EP_3x3mm_P0.5mm_EP1.8x1.8mm +Package_DFN_QFN:WDFN-10-1EP_3x3mm_P0.5mm_EP1.8x2.5mm +Package_DFN_QFN:WDFN-10-1EP_3x3mm_P0.5mm_EP1.8x2.5mm_ThermalVias +Package_DFN_QFN:WDFN-12-1EP_3x3mm_P0.45mm_EP1.7x2.5mm +Package_DFN_QFN:WDFN-6-2EP_4.0x2.6mm_P0.65mm +Package_DFN_QFN:WDFN-8-1EP_2x2.2mm_P0.5mm_EP0.80x0.54 +Package_DFN_QFN:WDFN-8-1EP_2x2mm_P0.5mm_EP0.8x1.2mm +Package_DFN_QFN:WDFN-8-1EP_3x2mm_P0.5mm_EP1.3x1.4mm +Package_DFN_QFN:WDFN-8-1EP_4x3mm_P0.65mm_EP2.4x1.8mm +Package_DFN_QFN:WDFN-8-1EP_4x3mm_P0.65mm_EP2.4x1.8mm_ThermalVias +Package_DFN_QFN:WDFN-8-1EP_6x5mm_P1.27mm_EP3.4x4mm +Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm +Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm_ThermalVias +Package_DFN_QFN:WDFN-8_2x2mm_P0.5mm +Package_DFN_QFN:WFDFPN-8-1EP_3x2mm_P0.5mm_EP1.25x1.35mm +Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm +Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm_ThermalVias +Package_DFN_QFN:WQFN-16-1EP_3x3mm_P0.5mm_EP1.68x1.68mm +Package_DFN_QFN:WQFN-16-1EP_3x3mm_P0.5mm_EP1.68x1.68mm_ThermalVias +Package_DFN_QFN:WQFN-16-1EP_3x3mm_P0.5mm_EP1.6x1.6mm +Package_DFN_QFN:WQFN-16-1EP_3x3mm_P0.5mm_EP1.6x1.6mm_ThermalVias +Package_DFN_QFN:WQFN-16-1EP_3x3mm_P0.5mm_EP1.75x1.75mm +Package_DFN_QFN:WQFN-16-1EP_3x3mm_P0.5mm_EP1.75x1.75mm_ThermalVias +Package_DFN_QFN:WQFN-16-1EP_4x4mm_P0.5mm_EP2.6x2.6mm +Package_DFN_QFN:WQFN-16-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:WQFN-20-1EP_2.5x4.5mm_P0.5mm_EP1x2.9mm +Package_DFN_QFN:WQFN-20-1EP_3x3mm_P0.4mm_EP1.7x1.7mm +Package_DFN_QFN:WQFN-20-1EP_3x3mm_P0.4mm_EP1.7x1.7mm_ThermalVias +Package_DFN_QFN:WQFN-24-1EP_4x4mm_P0.5mm_EP2.45x2.45mm +Package_DFN_QFN:WQFN-24-1EP_4x4mm_P0.5mm_EP2.45x2.45mm_ThermalVias +Package_DFN_QFN:WQFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm +Package_DFN_QFN:WQFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias +Package_DFN_QFN:WQFN-32-1EP_5x5mm_P0.5mm_EP3.1x3.1mm +Package_DFN_QFN:WQFN-42-1EP_3.5x9mm_P0.5mm_EP2.05x7.55mm +Package_DFN_QFN:WQFN-42-1EP_3.5x9mm_P0.5mm_EP2.05x7.55mm_ThermalVias +Package_DIP:CERDIP-14_W7.62mm_SideBrazed +Package_DIP:CERDIP-14_W7.62mm_SideBrazed_LongPads +Package_DIP:CERDIP-14_W7.62mm_SideBrazed_LongPads_Socket +Package_DIP:CERDIP-14_W7.62mm_SideBrazed_Socket +Package_DIP:CERDIP-16_W7.62mm_SideBrazed +Package_DIP:CERDIP-16_W7.62mm_SideBrazed_LongPads +Package_DIP:CERDIP-16_W7.62mm_SideBrazed_LongPads_Socket +Package_DIP:CERDIP-16_W7.62mm_SideBrazed_Socket +Package_DIP:CERDIP-18_W7.62mm_SideBrazed +Package_DIP:CERDIP-18_W7.62mm_SideBrazed_LongPads +Package_DIP:CERDIP-18_W7.62mm_SideBrazed_LongPads_Socket +Package_DIP:CERDIP-18_W7.62mm_SideBrazed_Socket +Package_DIP:CERDIP-20_W7.62mm_SideBrazed +Package_DIP:CERDIP-20_W7.62mm_SideBrazed_LongPads +Package_DIP:CERDIP-20_W7.62mm_SideBrazed_LongPads_Socket +Package_DIP:CERDIP-20_W7.62mm_SideBrazed_Socket +Package_DIP:CERDIP-22_W7.62mm_SideBrazed +Package_DIP:CERDIP-22_W7.62mm_SideBrazed_LongPads +Package_DIP:CERDIP-22_W7.62mm_SideBrazed_LongPads_Socket +Package_DIP:CERDIP-22_W7.62mm_SideBrazed_Socket +Package_DIP:CERDIP-24_W7.62mm_SideBrazed +Package_DIP:CERDIP-24_W7.62mm_SideBrazed_LongPads +Package_DIP:CERDIP-24_W7.62mm_SideBrazed_LongPads_Socket +Package_DIP:CERDIP-24_W7.62mm_SideBrazed_Socket +Package_DIP:CERDIP-28_W7.62mm_SideBrazed +Package_DIP:CERDIP-28_W7.62mm_SideBrazed_LongPads +Package_DIP:CERDIP-28_W7.62mm_SideBrazed_LongPads_Socket +Package_DIP:CERDIP-28_W7.62mm_SideBrazed_Socket +Package_DIP:CERDIP-8_W7.62mm_SideBrazed +Package_DIP:CERDIP-8_W7.62mm_SideBrazed_LongPads +Package_DIP:CERDIP-8_W7.62mm_SideBrazed_LongPads_Socket +Package_DIP:CERDIP-8_W7.62mm_SideBrazed_Socket +Package_DIP:DIP-10_W10.16mm +Package_DIP:DIP-10_W10.16mm_LongPads +Package_DIP:DIP-10_W7.62mm +Package_DIP:DIP-10_W7.62mm_LongPads +Package_DIP:DIP-10_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-10_W7.62mm_Socket +Package_DIP:DIP-10_W7.62mm_Socket_LongPads +Package_DIP:DIP-10_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-12_W10.16mm +Package_DIP:DIP-12_W10.16mm_LongPads +Package_DIP:DIP-12_W7.62mm +Package_DIP:DIP-12_W7.62mm_LongPads +Package_DIP:DIP-12_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-12_W7.62mm_Socket +Package_DIP:DIP-12_W7.62mm_Socket_LongPads +Package_DIP:DIP-12_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-14_W10.16mm +Package_DIP:DIP-14_W10.16mm_LongPads +Package_DIP:DIP-14_W7.62mm +Package_DIP:DIP-14_W7.62mm_LongPads +Package_DIP:DIP-14_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-14_W7.62mm_Socket +Package_DIP:DIP-14_W7.62mm_Socket_LongPads +Package_DIP:DIP-14_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-16_W10.16mm +Package_DIP:DIP-16_W10.16mm_LongPads +Package_DIP:DIP-16_W7.62mm +Package_DIP:DIP-16_W7.62mm_LongPads +Package_DIP:DIP-16_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-16_W7.62mm_Socket +Package_DIP:DIP-16_W7.62mm_Socket_LongPads +Package_DIP:DIP-16_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-18_W7.62mm +Package_DIP:DIP-18_W7.62mm_LongPads +Package_DIP:DIP-18_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-18_W7.62mm_Socket +Package_DIP:DIP-18_W7.62mm_Socket_LongPads +Package_DIP:DIP-18_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-20_W7.62mm +Package_DIP:DIP-20_W7.62mm_LongPads +Package_DIP:DIP-20_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-20_W7.62mm_Socket +Package_DIP:DIP-20_W7.62mm_Socket_LongPads +Package_DIP:DIP-20_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-22_W10.16mm +Package_DIP:DIP-22_W10.16mm_LongPads +Package_DIP:DIP-22_W10.16mm_SMDSocket_SmallPads +Package_DIP:DIP-22_W10.16mm_Socket +Package_DIP:DIP-22_W10.16mm_Socket_LongPads +Package_DIP:DIP-22_W11.43mm_SMDSocket_LongPads +Package_DIP:DIP-22_W7.62mm +Package_DIP:DIP-22_W7.62mm_LongPads +Package_DIP:DIP-22_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-22_W7.62mm_Socket +Package_DIP:DIP-22_W7.62mm_Socket_LongPads +Package_DIP:DIP-22_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-24_18.0mmx34.29mm_W15.24mm +Package_DIP:DIP-24_18.0mmx34.29mm_W15.24mm_LongPads +Package_DIP:DIP-24_18.0mmx34.29mm_W15.24mm_SMDSocket_SmallPads +Package_DIP:DIP-24_18.0mmx34.29mm_W15.24mm_Socket +Package_DIP:DIP-24_18.0mmx34.29mm_W15.24mm_Socket_LongPads +Package_DIP:DIP-24_W10.16mm +Package_DIP:DIP-24_W10.16mm_LongPads +Package_DIP:DIP-24_W10.16mm_SMDSocket_SmallPads +Package_DIP:DIP-24_W10.16mm_Socket +Package_DIP:DIP-24_W10.16mm_Socket_LongPads +Package_DIP:DIP-24_W11.43mm_SMDSocket_LongPads +Package_DIP:DIP-24_W15.24mm +Package_DIP:DIP-24_W15.24mm_LongPads +Package_DIP:DIP-24_W15.24mm_SMDSocket_SmallPads +Package_DIP:DIP-24_W15.24mm_Socket +Package_DIP:DIP-24_W15.24mm_Socket_LongPads +Package_DIP:DIP-24_W16.51mm_SMDSocket_LongPads +Package_DIP:DIP-24_W7.62mm +Package_DIP:DIP-24_W7.62mm_LongPads +Package_DIP:DIP-24_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-24_W7.62mm_Socket +Package_DIP:DIP-24_W7.62mm_Socket_LongPads +Package_DIP:DIP-24_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-28_W15.24mm +Package_DIP:DIP-28_W15.24mm_LongPads +Package_DIP:DIP-28_W15.24mm_SMDSocket_SmallPads +Package_DIP:DIP-28_W15.24mm_Socket +Package_DIP:DIP-28_W15.24mm_Socket_LongPads +Package_DIP:DIP-28_W16.51mm_SMDSocket_LongPads +Package_DIP:DIP-28_W7.62mm +Package_DIP:DIP-28_W7.62mm_LongPads +Package_DIP:DIP-28_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-28_W7.62mm_Socket +Package_DIP:DIP-28_W7.62mm_Socket_LongPads +Package_DIP:DIP-28_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-32_W15.24mm +Package_DIP:DIP-32_W15.24mm_LongPads +Package_DIP:DIP-32_W15.24mm_SMDSocket_SmallPads +Package_DIP:DIP-32_W15.24mm_Socket +Package_DIP:DIP-32_W15.24mm_Socket_LongPads +Package_DIP:DIP-32_W16.51mm_SMDSocket_LongPads +Package_DIP:DIP-32_W7.62mm +Package_DIP:DIP-40_W15.24mm +Package_DIP:DIP-40_W15.24mm_LongPads +Package_DIP:DIP-40_W15.24mm_SMDSocket_SmallPads +Package_DIP:DIP-40_W15.24mm_Socket +Package_DIP:DIP-40_W15.24mm_Socket_LongPads +Package_DIP:DIP-40_W16.51mm_SMDSocket_LongPads +Package_DIP:DIP-40_W25.4mm +Package_DIP:DIP-40_W25.4mm_LongPads +Package_DIP:DIP-40_W25.4mm_SMDSocket_SmallPads +Package_DIP:DIP-40_W25.4mm_Socket +Package_DIP:DIP-40_W25.4mm_Socket_LongPads +Package_DIP:DIP-40_W26.67mm_SMDSocket_LongPads +Package_DIP:DIP-42_W15.24mm +Package_DIP:DIP-42_W15.24mm_LongPads +Package_DIP:DIP-42_W15.24mm_SMDSocket_SmallPads +Package_DIP:DIP-42_W15.24mm_Socket +Package_DIP:DIP-42_W15.24mm_Socket_LongPads +Package_DIP:DIP-42_W16.51mm_SMDSocket_LongPads +Package_DIP:DIP-48_W15.24mm +Package_DIP:DIP-48_W15.24mm_LongPads +Package_DIP:DIP-48_W15.24mm_SMDSocket_SmallPads +Package_DIP:DIP-48_W15.24mm_Socket +Package_DIP:DIP-48_W15.24mm_Socket_LongPads +Package_DIP:DIP-48_W16.51mm_SMDSocket_LongPads +Package_DIP:DIP-4_W10.16mm +Package_DIP:DIP-4_W10.16mm_LongPads +Package_DIP:DIP-4_W7.62mm +Package_DIP:DIP-4_W7.62mm_LongPads +Package_DIP:DIP-4_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-4_W7.62mm_Socket +Package_DIP:DIP-4_W7.62mm_Socket_LongPads +Package_DIP:DIP-4_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-5-6_W10.16mm +Package_DIP:DIP-5-6_W10.16mm_LongPads +Package_DIP:DIP-5-6_W7.62mm +Package_DIP:DIP-5-6_W7.62mm_LongPads +Package_DIP:DIP-5-6_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-5-6_W7.62mm_Socket +Package_DIP:DIP-5-6_W7.62mm_Socket_LongPads +Package_DIP:DIP-5-6_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-64_W15.24mm +Package_DIP:DIP-64_W15.24mm_LongPads +Package_DIP:DIP-64_W15.24mm_SMDSocket_SmallPads +Package_DIP:DIP-64_W15.24mm_Socket +Package_DIP:DIP-64_W15.24mm_Socket_LongPads +Package_DIP:DIP-64_W16.51mm_SMDSocket_LongPads +Package_DIP:DIP-64_W22.86mm +Package_DIP:DIP-64_W22.86mm_LongPads +Package_DIP:DIP-64_W22.86mm_SMDSocket_SmallPads +Package_DIP:DIP-64_W22.86mm_Socket +Package_DIP:DIP-64_W22.86mm_Socket_LongPads +Package_DIP:DIP-64_W24.13mm_SMDSocket_LongPads +Package_DIP:DIP-64_W25.4mm +Package_DIP:DIP-64_W25.4mm_LongPads +Package_DIP:DIP-64_W25.4mm_SMDSocket_SmallPads +Package_DIP:DIP-64_W25.4mm_Socket +Package_DIP:DIP-64_W25.4mm_Socket_LongPads +Package_DIP:DIP-64_W26.67mm_SMDSocket_LongPads +Package_DIP:DIP-6_W10.16mm +Package_DIP:DIP-6_W10.16mm_LongPads +Package_DIP:DIP-6_W7.62mm +Package_DIP:DIP-6_W7.62mm_LongPads +Package_DIP:DIP-6_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-6_W7.62mm_Socket +Package_DIP:DIP-6_W7.62mm_Socket_LongPads +Package_DIP:DIP-6_W8.89mm_SMDSocket_LongPads +Package_DIP:DIP-8-16_W7.62mm +Package_DIP:DIP-8-16_W7.62mm_Socket +Package_DIP:DIP-8-16_W7.62mm_Socket_LongPads +Package_DIP:DIP-8-N6_W7.62mm +Package_DIP:DIP-8-N7_W7.62mm +Package_DIP:DIP-8_W10.16mm +Package_DIP:DIP-8_W10.16mm_LongPads +Package_DIP:DIP-8_W7.62mm +Package_DIP:DIP-8_W7.62mm_LongPads +Package_DIP:DIP-8_W7.62mm_SMDSocket_SmallPads +Package_DIP:DIP-8_W7.62mm_Socket +Package_DIP:DIP-8_W7.62mm_Socket_LongPads +Package_DIP:DIP-8_W8.89mm_SMDSocket_LongPads +Package_DIP:Fairchild_LSOP-8 +Package_DIP:IXYS_Flatpak-8_6.3x9.7mm_P2.54mm +Package_DIP:IXYS_SMD-8_6.3x9.7mm_P2.54mm +Package_DIP:PowerIntegrations_eDIP-12B +Package_DIP:PowerIntegrations_PDIP-8B +Package_DIP:PowerIntegrations_PDIP-8C +Package_DIP:PowerIntegrations_SDIP-10C +Package_DIP:PowerIntegrations_SMD-8 +Package_DIP:PowerIntegrations_SMD-8B +Package_DIP:PowerIntegrations_SMD-8C +Package_DIP:SMDIP-10_W11.48mm +Package_DIP:SMDIP-10_W7.62mm +Package_DIP:SMDIP-10_W9.53mm +Package_DIP:SMDIP-10_W9.53mm_Clearance8mm +Package_DIP:SMDIP-12_W11.48mm +Package_DIP:SMDIP-12_W7.62mm +Package_DIP:SMDIP-12_W9.53mm +Package_DIP:SMDIP-12_W9.53mm_Clearance8mm +Package_DIP:SMDIP-14_W11.48mm +Package_DIP:SMDIP-14_W7.62mm +Package_DIP:SMDIP-14_W9.53mm +Package_DIP:SMDIP-14_W9.53mm_Clearance8mm +Package_DIP:SMDIP-16_W11.48mm +Package_DIP:SMDIP-16_W7.62mm +Package_DIP:SMDIP-16_W9.53mm +Package_DIP:SMDIP-16_W9.53mm_Clearance8mm +Package_DIP:SMDIP-18_W11.48mm +Package_DIP:SMDIP-18_W7.62mm +Package_DIP:SMDIP-18_W9.53mm +Package_DIP:SMDIP-18_W9.53mm_Clearance8mm +Package_DIP:SMDIP-20_W11.48mm +Package_DIP:SMDIP-20_W7.62mm +Package_DIP:SMDIP-20_W9.53mm +Package_DIP:SMDIP-20_W9.53mm_Clearance8mm +Package_DIP:SMDIP-22_W11.48mm +Package_DIP:SMDIP-22_W7.62mm +Package_DIP:SMDIP-22_W9.53mm +Package_DIP:SMDIP-22_W9.53mm_Clearance8mm +Package_DIP:SMDIP-24_W11.48mm +Package_DIP:SMDIP-24_W15.24mm +Package_DIP:SMDIP-24_W7.62mm +Package_DIP:SMDIP-24_W9.53mm +Package_DIP:SMDIP-28_W15.24mm +Package_DIP:SMDIP-32_W11.48mm +Package_DIP:SMDIP-32_W15.24mm +Package_DIP:SMDIP-32_W7.62mm +Package_DIP:SMDIP-32_W9.53mm +Package_DIP:SMDIP-40_W15.24mm +Package_DIP:SMDIP-40_W25.24mm +Package_DIP:SMDIP-42_W15.24mm +Package_DIP:SMDIP-48_W15.24mm +Package_DIP:SMDIP-4_W11.48mm +Package_DIP:SMDIP-4_W7.62mm +Package_DIP:SMDIP-4_W9.53mm +Package_DIP:SMDIP-4_W9.53mm_Clearance8mm +Package_DIP:SMDIP-64_W15.24mm +Package_DIP:SMDIP-6_W11.48mm +Package_DIP:SMDIP-6_W7.62mm +Package_DIP:SMDIP-6_W9.53mm +Package_DIP:SMDIP-6_W9.53mm_Clearance8mm +Package_DIP:SMDIP-8_W11.48mm +Package_DIP:SMDIP-8_W7.62mm +Package_DIP:SMDIP-8_W9.53mm +Package_DIP:SMDIP-8_W9.53mm_Clearance8mm +Package_DIP:Toshiba_11-7A9 +Package_DIP:Vishay_HVM-DIP-3_W7.62mm +Package_DirectFET:DirectFET_L4 +Package_DirectFET:DirectFET_L6 +Package_DirectFET:DirectFET_L8 +Package_DirectFET:DirectFET_LA +Package_DirectFET:DirectFET_M2 +Package_DirectFET:DirectFET_M4 +Package_DirectFET:DirectFET_MA +Package_DirectFET:DirectFET_MB +Package_DirectFET:DirectFET_MC +Package_DirectFET:DirectFET_MD +Package_DirectFET:DirectFET_ME +Package_DirectFET:DirectFET_MF +Package_DirectFET:DirectFET_MN +Package_DirectFET:DirectFET_MP +Package_DirectFET:DirectFET_MQ +Package_DirectFET:DirectFET_MT +Package_DirectFET:DirectFET_MU +Package_DirectFET:DirectFET_MX +Package_DirectFET:DirectFET_MZ +Package_DirectFET:DirectFET_S1 +Package_DirectFET:DirectFET_S2 +Package_DirectFET:DirectFET_S3C +Package_DirectFET:DirectFET_SA +Package_DirectFET:DirectFET_SB +Package_DirectFET:DirectFET_SC +Package_DirectFET:DirectFET_SH +Package_DirectFET:DirectFET_SJ +Package_DirectFET:DirectFET_SQ +Package_DirectFET:DirectFET_ST +Package_LCC:Analog_LCC-8_5x5mm_P1.27mm +Package_LCC:PLCC-20 +Package_LCC:PLCC-20_SMD-Socket +Package_LCC:PLCC-20_THT-Socket +Package_LCC:PLCC-28 +Package_LCC:PLCC-28_SMD-Socket +Package_LCC:PLCC-28_THT-Socket +Package_LCC:PLCC-32_11.4x14.0mm_P1.27mm +Package_LCC:PLCC-32_THT-Socket +Package_LCC:PLCC-44 +Package_LCC:PLCC-44_16.6x16.6mm_P1.27mm +Package_LCC:PLCC-44_SMD-Socket +Package_LCC:PLCC-44_THT-Socket +Package_LCC:PLCC-52 +Package_LCC:PLCC-52_SMD-Socket +Package_LCC:PLCC-52_THT-Socket +Package_LCC:PLCC-68 +Package_LCC:PLCC-68_24.2x24.2mm_P1.27mm +Package_LCC:PLCC-68_SMD-Socket +Package_LCC:PLCC-68_THT-Socket +Package_LCC:PLCC-84 +Package_LCC:PLCC-84_29.3x29.3mm_P1.27mm +Package_LCC:PLCC-84_SMD-Socket +Package_LCC:PLCC-84_THT-Socket +Package_LGA:AMS_LGA-10-1EP_2.7x4mm_P0.6mm +Package_LGA:AMS_LGA-20_4.7x4.5mm_P0.65mm +Package_LGA:AMS_OLGA-8_2x3.1mm_P0.8mm +Package_LGA:Bosch_LGA-14_3x2.5mm_P0.5mm +Package_LGA:Bosch_LGA-8_2.5x2.5mm_P0.65mm_ClockwisePinNumbering +Package_LGA:Bosch_LGA-8_2x2.5mm_P0.65mm_ClockwisePinNumbering +Package_LGA:Bosch_LGA-8_3x3mm_P0.8mm_ClockwisePinNumbering +Package_LGA:Infineon_PG-TSNP-6-10_0.7x1.1mm_0.7x1.1mm_P0.4mm +Package_LGA:Kionix_LGA-12_2x2mm_P0.5mm_LayoutBorder2x4y +Package_LGA:LGA-12_2x2mm_P0.5mm +Package_LGA:LGA-14_2x2mm_P0.35mm_LayoutBorder3x4y +Package_LGA:LGA-14_3x2.5mm_P0.5mm_LayoutBorder3x4y +Package_LGA:LGA-14_3x5mm_P0.8mm_LayoutBorder1x6y +Package_LGA:LGA-16_3x3mm_P0.5mm +Package_LGA:LGA-16_3x3mm_P0.5mm_LayoutBorder3x5y +Package_LGA:LGA-16_4x4mm_P0.65mm_LayoutBorder4x4y +Package_LGA:LGA-24L_3x3.5mm_P0.43mm +Package_LGA:LGA-28_5.2x3.8mm_P0.5mm +Package_LGA:LGA-8_3x5mm_P1.25mm +Package_LGA:LGA-8_8x6.2mm_P1.27mm +Package_LGA:LGA-8_8x6mm_P1.27mm +Package_LGA:Linear_LGA-133_15.0x15.0mm_Layout12x12_P1.27mm +Package_LGA:MPS_LGA-18-10EP_12x12mm_P3.3mm +Package_LGA:Nordic_nRF9160-SIxx_LGA-102-59EP_16.0x10.5mm_P0.5mm +Package_LGA:NXP_LGA-8_3x5mm_P1.25mm_H1.1mm +Package_LGA:NXP_LGA-8_3x5mm_P1.25mm_H1.2mm +Package_LGA:Rohm_MLGA010V020A_LGA-10_2x2mm_P0.45mm_LayoutBorder2x3y +Package_LGA:ST_CCLGA-7L_2.8x2.8mm_P1.15mm_H1.95mm +Package_LGA:ST_HLGA-10_2.5x2.5mm_P0.6mm_LayoutBorder3x2y +Package_LGA:ST_HLGA-10_2x2mm_P0.5mm_LayoutBorder3x2y +Package_LGA:Texas_SIL0008D_MicroSiP-8-1EP_2.8x3mm_P0.65mm_EP1.1x1.9mm +Package_LGA:Texas_SIL0008D_MicroSiP-8-1EP_2.8x3mm_P0.65mm_EP1.1x1.9mm_ThermalVias +Package_LGA:Texas_SIL0010A_MicroSiP-10-1EP_3.8x3mm_P0.6mm_EP0.7x2.9mm +Package_LGA:Texas_SIL0010A_MicroSiP-10-1EP_3.8x3mm_P0.6mm_EP0.7x2.9mm_ThermalVias +Package_LGA:VLGA-4_2x2.5mm_P1.65mm +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP4x4mm +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP4x4mm_ThermalVias +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP5x5mm +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP5x5mm_ThermalVias +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP6.61x5.615mm +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP6.61x5.615mm_ThermalVias +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP7.2x6.35mm +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP7.2x6.35mm_ThermalVias +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP8.93x8.7mm +Package_QFP:EQFP-144-1EP_20x20mm_P0.5mm_EP8.93x8.7mm_ThermalVias +Package_QFP:HTQFP-64-1EP_10x10mm_P0.5mm_EP8x8mm +Package_QFP:HTQFP-64-1EP_10x10mm_P0.5mm_EP8x8mm_Mask4.4x4.4mm_ThermalVias +Package_QFP:LQFP-100_14x14mm_P0.5mm +Package_QFP:LQFP-128_14x14mm_P0.4mm +Package_QFP:LQFP-128_14x20mm_P0.5mm +Package_QFP:LQFP-144-1EP_20x20mm_P0.5mm_EP6.5x6.5mm +Package_QFP:LQFP-144-1EP_20x20mm_P0.5mm_EP6.5x6.5mm_ThermalVias +Package_QFP:LQFP-144_20x20mm_P0.5mm +Package_QFP:LQFP-160_24x24mm_P0.5mm +Package_QFP:LQFP-176_20x20mm_P0.4mm +Package_QFP:LQFP-176_24x24mm_P0.5mm +Package_QFP:LQFP-208_28x28mm_P0.5mm +Package_QFP:LQFP-216_24x24mm_P0.4mm +Package_QFP:LQFP-32_5x5mm_P0.5mm +Package_QFP:LQFP-32_7x7mm_P0.8mm +Package_QFP:LQFP-36_7x7mm_P0.65mm +Package_QFP:LQFP-44_10x10mm_P0.8mm +Package_QFP:LQFP-48-1EP_7x7mm_P0.5mm_EP3.6x3.6mm +Package_QFP:LQFP-48-1EP_7x7mm_P0.5mm_EP3.6x3.6mm_ThermalVias +Package_QFP:LQFP-48_7x7mm_P0.5mm +Package_QFP:LQFP-52-1EP_10x10mm_P0.65mm_EP4.8x4.8mm +Package_QFP:LQFP-52-1EP_10x10mm_P0.65mm_EP4.8x4.8mm_ThermalVias +Package_QFP:LQFP-52_10x10mm_P0.65mm +Package_QFP:LQFP-52_14x14mm_P1mm +Package_QFP:LQFP-64-1EP_10x10mm_P0.5mm_EP5x5mm +Package_QFP:LQFP-64-1EP_10x10mm_P0.5mm_EP5x5mm_ThermalVias +Package_QFP:LQFP-64-1EP_10x10mm_P0.5mm_EP6.5x6.5mm +Package_QFP:LQFP-64-1EP_10x10mm_P0.5mm_EP6.5x6.5mm_ThermalVias +Package_QFP:LQFP-64_10x10mm_P0.5mm +Package_QFP:LQFP-64_14x14mm_P0.8mm +Package_QFP:LQFP-64_7x7mm_P0.4mm +Package_QFP:LQFP-80_10x10mm_P0.4mm +Package_QFP:LQFP-80_12x12mm_P0.5mm +Package_QFP:LQFP-80_14x14mm_P0.65mm +Package_QFP:Microchip_PQFP-44_10x10mm_P0.8mm +Package_QFP:MQFP-44_10x10mm_P0.8mm +Package_QFP:PQFP-100_14x20mm_P0.65mm +Package_QFP:PQFP-112_20x20mm_P0.65mm +Package_QFP:PQFP-132_24x24mm_P0.635mm +Package_QFP:PQFP-132_24x24mm_P0.635mm_i386 +Package_QFP:PQFP-144_28x28mm_P0.65mm +Package_QFP:PQFP-160_28x28mm_P0.65mm +Package_QFP:PQFP-168_28x28mm_P0.65mm +Package_QFP:PQFP-208_28x28mm_P0.5mm +Package_QFP:PQFP-240_32.1x32.1mm_P0.5mm +Package_QFP:PQFP-256_28x28mm_P0.4mm +Package_QFP:PQFP-32_5x5mm_P0.5mm +Package_QFP:PQFP-44_10x10mm_P0.8mm +Package_QFP:PQFP-64_14x14mm_P0.8mm +Package_QFP:PQFP-80_14x20mm_P0.8mm +Package_QFP:Texas_PHP0048E_HTQFP-48-1EP_7x7mm_P0.5mm_EP6.5x6.5mm_Mask3.62x3.62mm +Package_QFP:Texas_PHP0048E_HTQFP-48-1EP_7x7mm_P0.5mm_EP6.5x6.5mm_Mask3.62x3.62mm_ThermalVias +Package_QFP:TQFP-100-1EP_14x14mm_P0.5mm_EP5x5mm +Package_QFP:TQFP-100-1EP_14x14mm_P0.5mm_EP5x5mm_ThermalVias +Package_QFP:TQFP-100_12x12mm_P0.4mm +Package_QFP:TQFP-100_14x14mm_P0.5mm +Package_QFP:TQFP-120_14x14mm_P0.4mm +Package_QFP:TQFP-128_14x14mm_P0.4mm +Package_QFP:TQFP-144_16x16mm_P0.4mm +Package_QFP:TQFP-144_20x20mm_P0.5mm +Package_QFP:TQFP-176_24x24mm_P0.5mm +Package_QFP:TQFP-32_7x7mm_P0.8mm +Package_QFP:TQFP-44-1EP_10x10mm_P0.8mm_EP4.5x4.5mm +Package_QFP:TQFP-44_10x10mm_P0.8mm +Package_QFP:TQFP-48-1EP_7x7mm_P0.5mm_EP3.5x3.5mm +Package_QFP:TQFP-48-1EP_7x7mm_P0.5mm_EP4.11x4.11mm +Package_QFP:TQFP-48-1EP_7x7mm_P0.5mm_EP5x5mm +Package_QFP:TQFP-48-1EP_7x7mm_P0.5mm_EP5x5mm_ThermalVias +Package_QFP:TQFP-48_7x7mm_P0.5mm +Package_QFP:TQFP-52-1EP_10x10mm_P0.65mm_EP6.5x6.5mm +Package_QFP:TQFP-52-1EP_10x10mm_P0.65mm_EP6.5x6.5mm_ThermalVias +Package_QFP:TQFP-64-1EP_10x10mm_P0.5mm_EP5.305x5.305mm +Package_QFP:TQFP-64-1EP_10x10mm_P0.5mm_EP5.305x5.305mm_ThermalVias +Package_QFP:TQFP-64-1EP_10x10mm_P0.5mm_EP8x8mm +Package_QFP:TQFP-64_10x10mm_P0.5mm +Package_QFP:TQFP-64_14x14mm_P0.8mm +Package_QFP:TQFP-64_7x7mm_P0.4mm +Package_QFP:TQFP-80-1EP_14x14mm_P0.65mm_EP9.5x9.5mm +Package_QFP:TQFP-80_12x12mm_P0.5mm +Package_QFP:TQFP-80_14x14mm_P0.65mm +Package_QFP:VQFP-100_14x14mm_P0.5mm +Package_QFP:VQFP-128_14x14mm_P0.4mm +Package_QFP:VQFP-176_20x20mm_P0.4mm +Package_QFP:VQFP-80_14x14mm_P0.65mm +Package_SIP:PowerIntegrations_eSIP-7C +Package_SIP:PowerIntegrations_eSIP-7F +Package_SIP:Sanyo_STK4xx-15_59.2x8.0mm_P2.54mm +Package_SIP:Sanyo_STK4xx-15_78.0x8.0mm_P2.54mm +Package_SIP:SIP-8_19x3mm_P2.54mm +Package_SIP:SIP-9_21.54x3mm_P2.54mm +Package_SIP:SIP-9_22.3x3mm_P2.54mm +Package_SIP:SIP3_11.6x8.5mm +Package_SIP:SIP4_Sharp-SSR_P7.62mm_Angled +Package_SIP:SIP4_Sharp-SSR_P7.62mm_Angled_NoHole +Package_SIP:SIP4_Sharp-SSR_P7.62mm_Straight +Package_SIP:SIP9_Housing +Package_SIP:SIP9_Housing_BigPads +Package_SIP:SLA704XM +Package_SIP:STK672-040-E +Package_SIP:STK672-080-E +Package_SO:Analog_MSOP-12-16-1EP_3x4.039mm_P0.5mm_EP1.651x2.845mm +Package_SO:Analog_MSOP-12-16-1EP_3x4.039mm_P0.5mm_EP1.651x2.845mm_ThermalVias +Package_SO:Analog_MSOP-12-16_3x4.039mm_P0.5mm +Package_SO:Diodes_PSOP-8 +Package_SO:Diodes_SO-8EP +Package_SO:ETSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP3x4.2mm +Package_SO:HSOP-20-1EP_11.0x15.9mm_P1.27mm_SlugDown +Package_SO:HSOP-20-1EP_11.0x15.9mm_P1.27mm_SlugDown_ThermalVias +Package_SO:HSOP-20-1EP_11.0x15.9mm_P1.27mm_SlugUp +Package_SO:HSOP-32-1EP_7.5x11mm_P0.65mm_EP4.7x4.7mm +Package_SO:HSOP-36-1EP_11.0x15.9mm_P0.65mm_SlugDown +Package_SO:HSOP-36-1EP_11.0x15.9mm_P0.65mm_SlugDown_ThermalVias +Package_SO:HSOP-36-1EP_11.0x15.9mm_P0.65mm_SlugUp +Package_SO:HSOP-54-1EP_7.5x17.9mm_P0.65mm_EP4.6x4.6mm +Package_SO:HSOP-8-1EP_3.9x4.9mm_P1.27mm_EP2.3x2.3mm +Package_SO:HSOP-8-1EP_3.9x4.9mm_P1.27mm_EP2.3x2.3mm_ThermalVias +Package_SO:HSOP-8-1EP_3.9x4.9mm_P1.27mm_EP2.41x3.1mm +Package_SO:HSOP-8-1EP_3.9x4.9mm_P1.27mm_EP2.41x3.1mm_ThermalVias +Package_SO:HTSOP-8-1EP_3.9x4.9mm_P1.27mm_EP2.4x3.2mm +Package_SO:HTSOP-8-1EP_3.9x4.9mm_P1.27mm_EP2.4x3.2mm_ThermalVias +Package_SO:HTSSOP-14-1EP_4.4x5mm_P0.65mm_EP3.4x5mm_Mask3x3.1mm +Package_SO:HTSSOP-14-1EP_4.4x5mm_P0.65mm_EP3.4x5mm_Mask3x3.1mm_ThermalVias +Package_SO:HTSSOP-16-1EP_4.4x5mm_P0.65mm_EP3.4x5mm +Package_SO:HTSSOP-16-1EP_4.4x5mm_P0.65mm_EP3.4x5mm_Mask2.46x2.31mm +Package_SO:HTSSOP-16-1EP_4.4x5mm_P0.65mm_EP3.4x5mm_Mask2.46x2.31mm_ThermalVias +Package_SO:HTSSOP-16-1EP_4.4x5mm_P0.65mm_EP3.4x5mm_Mask3x3mm_ThermalVias +Package_SO:HTSSOP-16-1EP_4.4x5mm_P0.65mm_EP3x3mm +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP2.74x3.86mm +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP2.85x4mm +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP3.4x6.5mm +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP3.4x6.5mm_Mask2.4x3.7mm +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP3.4x6.5mm_Mask2.75x3.43mm +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP3.4x6.5mm_Mask2.75x3.43mm_ThermalVias +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP3.4x6.5mm_Mask2.75x3.43mm_ThermalVias_HandSolder +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP3.4x6.5mm_Mask2.96x2.96mm +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP3.4x6.5mm_Mask2.96x2.96mm_ThermalVias +Package_SO:HTSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP3.4x6.5mm_ThermalVias +Package_SO:HTSSOP-24-1EP_4.4x7.8mm_P0.65mm_EP3.2x5mm +Package_SO:HTSSOP-24-1EP_4.4x7.8mm_P0.65mm_EP3.4x7.8mm_Mask2.4x2.98mm +Package_SO:HTSSOP-24-1EP_4.4x7.8mm_P0.65mm_EP3.4x7.8mm_Mask2.4x2.98mm_ThermalVias +Package_SO:HTSSOP-24-1EP_4.4x7.8mm_P0.65mm_EP3.4x7.8mm_Mask2.4x4.68mm +Package_SO:HTSSOP-24-1EP_4.4x7.8mm_P0.65mm_EP3.4x7.8mm_Mask2.4x4.68mm_ThermalVias +Package_SO:HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP2.75x6.2mm +Package_SO:HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP2.75x6.2mm_ThermalVias +Package_SO:HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP2.85x5.4mm +Package_SO:HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP2.85x5.4mm_ThermalVias +Package_SO:HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.4x9.5mm +Package_SO:HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.4x9.5mm_Mask2.4x6.17mm +Package_SO:HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.4x9.5mm_Mask2.4x6.17mm_ThermalVias +Package_SO:HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.4x9.5mm_ThermalVias +Package_SO:HTSSOP-32-1EP_6.1x11mm_P0.65mm_EP5.2x11mm_Mask4.11x4.36mm +Package_SO:HTSSOP-32-1EP_6.1x11mm_P0.65mm_EP5.2x11mm_Mask4.11x4.36mm_ThermalVias +Package_SO:HTSSOP-38-1EP_4.4x9.7mm_P0.5mm_EP1.5x3.3mm +Package_SO:HTSSOP-38-1EP_4.4x9.7mm_P0.5mm_EP1.5x3.3mm_ThermalVias +Package_SO:HTSSOP-38-1EP_4.4x9.7mm_P0.5mm_EP2.74x4.75mm +Package_SO:HTSSOP-38-1EP_4.4x9.7mm_P0.5mm_EP2.74x4.75mm_ThermalVias +Package_SO:HTSSOP-38-1EP_6.1x12.5mm_P0.65mm_EP5.2x12.5mm_Mask3.39x6.35mm +Package_SO:HTSSOP-38-1EP_6.1x12.5mm_P0.65mm_EP5.2x12.5mm_Mask3.39x6.35mm_ThermalVias +Package_SO:HTSSOP-44-1EP_6.1x14mm_P0.635mm_EP5.2x14mm_Mask4.31x8.26mm +Package_SO:HTSSOP-44-1EP_6.1x14mm_P0.635mm_EP5.2x14mm_Mask4.31x8.26mm_ThermalVias +Package_SO:HTSSOP-44_6.1x14mm_P0.635mm_TopEP4.14x7.01mm +Package_SO:HTSSOP-56-1EP_6.1x14mm_P0.5mm_EP3.61x6.35mm +Package_SO:HVSSOP-10-1EP_3x3mm_P0.5mm_EP1.57x1.88mm +Package_SO:HVSSOP-10-1EP_3x3mm_P0.5mm_EP1.57x1.88mm_ThermalVias +Package_SO:HVSSOP-8-1EP_3x3mm_P0.65mm_EP1.57x1.89mm +Package_SO:HVSSOP-8-1EP_3x3mm_P0.65mm_EP1.57x1.89mm_ThermalVias +Package_SO:Infineon_PG-DSO-12-11 +Package_SO:Infineon_PG-DSO-12-11_ThermalVias +Package_SO:Infineon_PG-DSO-12-9 +Package_SO:Infineon_PG-DSO-12-9_ThermalVias +Package_SO:Infineon_PG-DSO-20-30 +Package_SO:Infineon_PG-DSO-20-30_ThermalVias +Package_SO:Infineon_PG-DSO-20-32 +Package_SO:Infineon_PG-DSO-20-85 +Package_SO:Infineon_PG-DSO-20-85_ThermalVias +Package_SO:Infineon_PG-DSO-20-87 +Package_SO:Infineon_PG-DSO-20-U03_7.5x12.8mm +Package_SO:Infineon_PG-DSO-8-24_4x5mm +Package_SO:Infineon_PG-DSO-8-27_3.9x4.9mm_EP2.65x3mm +Package_SO:Infineon_PG-DSO-8-27_3.9x4.9mm_EP2.65x3mm_ThermalVias +Package_SO:Infineon_PG-DSO-8-43 +Package_SO:Infineon_PG-DSO-8-59_7.5x6.3mm +Package_SO:Infineon_PG-TSDSO-14-22 +Package_SO:Infineon_SOIC-20W_7.6x12.8mm_P1.27mm +Package_SO:Linear_HTSSOP-31-38-1EP_4.4x9.7mm_P0.5mm_EP2.74x4.75mm +Package_SO:Linear_HTSSOP-31-38-1EP_4.4x9.7mm_P0.5mm_EP2.74x4.75mm_ThermalVias +Package_SO:MFSOP6-4_4.4x3.6mm_P1.27mm +Package_SO:MFSOP6-5_4.4x3.6mm_P1.27mm +Package_SO:MSOP-10-1EP_3x3mm_P0.5mm_EP1.68x1.88mm +Package_SO:MSOP-10-1EP_3x3mm_P0.5mm_EP1.68x1.88mm_ThermalVias +Package_SO:MSOP-10-1EP_3x3mm_P0.5mm_EP1.73x1.98mm +Package_SO:MSOP-10-1EP_3x3mm_P0.5mm_EP1.73x1.98mm_ThermalVias +Package_SO:MSOP-10-1EP_3x3mm_P0.5mm_EP2.2x3.1mm_Mask1.83x1.89mm +Package_SO:MSOP-10-1EP_3x3mm_P0.5mm_EP2.2x3.1mm_Mask1.83x1.89mm_ThermalVias +Package_SO:MSOP-10_3x3mm_P0.5mm +Package_SO:MSOP-12-1EP_3x4.039mm_P0.65mm_EP1.651x2.845mm +Package_SO:MSOP-12-1EP_3x4.039mm_P0.65mm_EP1.651x2.845mm_ThermalVias +Package_SO:MSOP-12_3x4.039mm_P0.65mm +Package_SO:MSOP-16-1EP_3x4.039mm_P0.5mm_EP1.651x2.845mm +Package_SO:MSOP-16-1EP_3x4.039mm_P0.5mm_EP1.651x2.845mm_ThermalVias +Package_SO:MSOP-16_3x4.039mm_P0.5mm +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP1.5x1.8mm +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP1.5x1.8mm_ThermalVias +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP1.68x1.88mm +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP1.68x1.88mm_ThermalVias +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP1.73x1.85mm +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP1.73x1.85mm_ThermalVias +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP1.95x2.15mm +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP1.95x2.15mm_ThermalVias +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP2.5x3mm_Mask1.73x2.36mm +Package_SO:MSOP-8-1EP_3x3mm_P0.65mm_EP2.5x3mm_Mask1.73x2.36mm_ThermalVias +Package_SO:MSOP-8_3x3mm_P0.65mm +Package_SO:NXP_HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP2.2x3.4mm +Package_SO:NXP_HTSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP2.2x3.4mm_ThermalVias +Package_SO:OnSemi_Micro8 +Package_SO:ONSemi_SO-8FL_488AA +Package_SO:PowerIntegrations_eSOP-12B +Package_SO:PowerIntegrations_SO-8 +Package_SO:PowerIntegrations_SO-8B +Package_SO:PowerIntegrations_SO-8C +Package_SO:PowerPAK_SO-8L_Single +Package_SO:PowerPAK_SO-8_Dual +Package_SO:PowerPAK_SO-8_Single +Package_SO:PowerSSO-16-1EP_3.9x4.9mm_P0.5mm_EP2.5x3.61mm +Package_SO:PowerSSO-16-1EP_3.9x4.9mm_P0.5mm_EP2.5x3.61mm_ThermalVias +Package_SO:PSOP-44_16.9x27.17mm_P1.27mm +Package_SO:QSOP-16_3.9x4.9mm_P0.635mm +Package_SO:QSOP-20_3.9x8.7mm_P0.635mm +Package_SO:QSOP-24_3.9x8.7mm_P0.635mm +Package_SO:QSOP-28_3.9x9.9mm_P0.635mm +Package_SO:Renesas_SOP-32_11.4x20.75mm_P1.27mm +Package_SO:SO-14_3.9x8.65mm_P1.27mm +Package_SO:SO-14_5.3x10.2mm_P1.27mm +Package_SO:SO-16_3.9x9.9mm_P1.27mm +Package_SO:SO-16_5.3x10.2mm_P1.27mm +Package_SO:SO-20-1EP_7.52x12.825mm_P1.27mm_EP6.045x12.09mm_Mask3.56x4.47mm +Package_SO:SO-20-1EP_7.52x12.825mm_P1.27mm_EP6.045x12.09mm_Mask3.56x4.47mm_ThermalVias +Package_SO:SO-20_12.8x7.5mm_P1.27mm +Package_SO:SO-20_5.3x12.6mm_P1.27mm +Package_SO:SO-24_5.3x15mm_P1.27mm +Package_SO:SO-4_4.4x2.3mm_P1.27mm +Package_SO:SO-4_4.4x3.6mm_P2.54mm +Package_SO:SO-4_4.4x3.9mm_P2.54mm +Package_SO:SO-4_4.4x4.3mm_P2.54mm +Package_SO:SO-4_7.6x3.6mm_P2.54mm +Package_SO:SO-5-6_4.55x3.7mm_P1.27mm +Package_SO:SO-5_4.4x3.6mm_P1.27mm +Package_SO:SO-6L_10x3.84mm_P1.27mm +Package_SO:SO-6_4.4x3.6mm_P1.27mm +Package_SO:SO-8_3.9x4.9mm_P1.27mm +Package_SO:SOIC-10_3.9x4.9mm_P1mm +Package_SO:SOIC-14-16_3.9x9.9mm_P1.27mm +Package_SO:SOIC-14W_7.5x9mm_P1.27mm +Package_SO:SOIC-14_3.9x8.7mm_P1.27mm +Package_SO:SOIC-16W-12_7.5x10.3mm_P1.27mm +Package_SO:SOIC-16W_5.3x10.2mm_P1.27mm +Package_SO:SOIC-16W_7.5x10.3mm_P1.27mm +Package_SO:SOIC-16W_7.5x12.8mm_P1.27mm +Package_SO:SOIC-16_3.9x9.9mm_P1.27mm +Package_SO:SOIC-16_4.55x10.3mm_P1.27mm +Package_SO:SOIC-18W_7.5x11.6mm_P1.27mm +Package_SO:SOIC-20W_7.5x12.8mm_P1.27mm +Package_SO:SOIC-20W_7.5x15.4mm_P1.27mm +Package_SO:SOIC-24W_7.5x15.4mm_P1.27mm +Package_SO:SOIC-28W_7.5x17.9mm_P1.27mm +Package_SO:SOIC-28W_7.5x18.7mm_P1.27mm +Package_SO:SOIC-32_7.518x20.777mm_P1.27mm +Package_SO:SOIC-4_4.55x2.6mm_P1.27mm +Package_SO:SOIC-4_4.55x3.7mm_P2.54mm +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.29x3mm +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.29x3mm_ThermalVias +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.41x3.3mm +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.41x3.3mm_ThermalVias +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.41x3.81mm +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.41x3.81mm_ThermalVias +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.514x3.2mm +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.514x3.2mm_ThermalVias +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.62x3.51mm +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.62x3.51mm_ThermalVias +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.95x4.9mm_Mask2.71x3.4mm +Package_SO:SOIC-8-1EP_3.9x4.9mm_P1.27mm_EP2.95x4.9mm_Mask2.71x3.4mm_ThermalVias +Package_SO:SOIC-8-N7_3.9x4.9mm_P1.27mm +Package_SO:SOIC-8_3.9x4.9mm_P1.27mm +Package_SO:SOIC-8_5.3x5.3mm_P1.27mm +Package_SO:SOIC-8_5.3x6.2mm_P1.27mm +Package_SO:SOIC-8_7.5x5.85mm_P1.27mm +Package_SO:SOJ-24_7.62x15.875mm_P1.27mm +Package_SO:SOJ-28_10.16x18.415mm_P1.27mm +Package_SO:SOJ-28_7.62x18.415mm_P1.27mm +Package_SO:SOJ-32_10.16x20.955mm_P1.27mm +Package_SO:SOJ-32_7.62x20.955mm_P1.27mm +Package_SO:SOJ-36_10.16x23.495mm_P1.27mm +Package_SO:SOJ-44_10.16x28.575mm_P1.27mm +Package_SO:SOP-16_3.9x9.9mm_P1.27mm +Package_SO:SOP-16_4.4x10.4mm_P1.27mm +Package_SO:SOP-16_4.55x10.3mm_P1.27mm +Package_SO:SOP-18_7.495x11.515mm_P1.27mm +Package_SO:SOP-18_7x12.5mm_P1.27mm +Package_SO:SOP-20_7.5x12.8mm_P1.27mm +Package_SO:SOP-24_7.5x15.4mm_P1.27mm +Package_SO:SOP-28_8.4x18.16mm_P1.27mm +Package_SO:SOP-32_11.305x20.495mm_P1.27mm +Package_SO:SOP-44_12.6x28.5mm_P1.27mm +Package_SO:SOP-44_13.3x28.2mm_P1.27mm +Package_SO:SOP-4_3.8x4.1mm_P2.54mm +Package_SO:SOP-4_4.4x2.6mm_P1.27mm +Package_SO:SOP-4_7.5x4.1mm_P2.54mm +Package_SO:SOP-8-1EP_4.57x4.57mm_P1.27mm_EP4.57x4.45mm +Package_SO:SOP-8-1EP_4.57x4.57mm_P1.27mm_EP4.57x4.45mm_ThermalVias +Package_SO:SOP-8_3.76x4.96mm_P1.27mm +Package_SO:SOP-8_3.9x4.9mm_P1.27mm +Package_SO:SOP-8_6.605x9.655mm_P2.54mm +Package_SO:SOP-8_6.62x9.15mm_P2.54mm +Package_SO:SSO-4_6.7x5.1mm_P2.54mm_Clearance8mm +Package_SO:SSO-6_6.8x4.6mm_P1.27mm_Clearance7mm +Package_SO:SSO-6_6.8x4.6mm_P1.27mm_Clearance8mm +Package_SO:SSO-7-8_6.4x9.78mm_P2.54mm +Package_SO:SSO-8-7_6.4x9.7mm_P2.54mm +Package_SO:SSO-8_13.6x6.3mm_P1.27mm_Clearance14.2mm +Package_SO:SSO-8_6.7x9.8mm_P2.54mm_Clearance8mm +Package_SO:SSO-8_6.8x5.9mm_P1.27mm_Clearance7mm +Package_SO:SSO-8_6.8x5.9mm_P1.27mm_Clearance8mm +Package_SO:SSO-8_9.6x6.3mm_P1.27mm_Clearance10.5mm +Package_SO:SSOP-10-1EP_3.9x4.9mm_P1mm_EP2.1x3.3mm +Package_SO:SSOP-10-1EP_3.9x4.9mm_P1mm_EP2.1x3.3mm_ThermalVias +Package_SO:SSOP-10_3.9x4.9mm_P1.00mm +Package_SO:SSOP-14_5.3x6.2mm_P0.65mm +Package_SO:SSOP-16_3.9x4.9mm_P0.635mm +Package_SO:SSOP-16_4.4x5.2mm_P0.65mm +Package_SO:SSOP-16_5.3x6.2mm_P0.65mm +Package_SO:SSOP-18_4.4x6.5mm_P0.65mm +Package_SO:SSOP-20_3.9x8.7mm_P0.635mm +Package_SO:SSOP-20_4.4x6.5mm_P0.65mm +Package_SO:SSOP-20_5.3x7.2mm_P0.65mm +Package_SO:SSOP-24_3.9x8.7mm_P0.635mm +Package_SO:SSOP-24_5.3x8.2mm_P0.65mm +Package_SO:SSOP-28_3.9x9.9mm_P0.635mm +Package_SO:SSOP-28_5.3x10.2mm_P0.65mm +Package_SO:SSOP-44_5.3x12.8mm_P0.5mm +Package_SO:SSOP-48_5.3x12.8mm_P0.5mm +Package_SO:SSOP-48_7.5x15.9mm_P0.635mm +Package_SO:SSOP-4_4.4x2.6mm_P1.27mm +Package_SO:SSOP-56_7.5x18.5mm_P0.635mm +Package_SO:SSOP-8_2.95x2.8mm_P0.65mm +Package_SO:SSOP-8_3.95x5.21x3.27mm_P1.27mm +Package_SO:SSOP-8_3.9x5.05mm_P1.27mm +Package_SO:SSOP-8_5.25x5.24mm_P1.27mm +Package_SO:STC_SOP-16_3.9x9.9mm_P1.27mm +Package_SO:ST_MultiPowerSO-30 +Package_SO:ST_PowerSSO-24_SlugDown +Package_SO:ST_PowerSSO-24_SlugDown_ThermalVias +Package_SO:ST_PowerSSO-24_SlugUp +Package_SO:ST_PowerSSO-36_SlugDown +Package_SO:ST_PowerSSO-36_SlugDown_ThermalVias +Package_SO:ST_PowerSSO-36_SlugUp +Package_SO:Texas_DAD0032A_HTSSOP-32_6.1x11mm_P0.65mm_TopEP3.71x3.81mm +Package_SO:Texas_DGN0008B_VSSOP-8-1EP_3x3mm_P0.65mm_EP2x3mm_Mask1.88x1.98mm +Package_SO:Texas_DGN0008B_VSSOP-8-1EP_3x3mm_P0.65mm_EP2x3mm_Mask1.88x1.98mm_ThermalVias +Package_SO:Texas_DGN0008D_VSSOP-8-1EP_3x3mm_P0.65mm_EP2x2.94mm_Mask1.57x1.89mm +Package_SO:Texas_DGN0008D_VSSOP-8-1EP_3x3mm_P0.65mm_EP2x2.94mm_Mask1.57x1.89mm_ThermalVias +Package_SO:Texas_DGN0008G_VSSOP-8-1EP_3x3mm_P0.65mm_EP2x2.94mm_Mask1.846x2.15mm +Package_SO:Texas_DGN0008G_VSSOP-8-1EP_3x3mm_P0.65mm_EP2x2.94mm_Mask1.846x2.15mm_ThermalVias +Package_SO:Texas_DKD0036A_HSSOP-36_11x15.9mm_P0.65mm_TopEP5.85x12.65mm +Package_SO:Texas_DYY0016A_TSOT-23-16_4.2x2.0mm_P0.5mm +Package_SO:Texas_HSOP-8-1EP_3.9x4.9mm_P1.27mm +Package_SO:Texas_HSOP-8-1EP_3.9x4.9mm_P1.27mm_ThermalVias +Package_SO:Texas_HTSOP-8-1EP_3.9x4.9mm_P1.27mm_EP2.95x4.9mm_Mask2.4x3.1mm_ThermalVias +Package_SO:Texas_PW0020A_TSSOP-20_4.4x6.5mm_P0.65mm +Package_SO:Texas_PWP0020A +Package_SO:Texas_PWP0028V_TSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.4x9.7mm_Mask2.94x5.62mm +Package_SO:Texas_PWP0028V_TSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.4x9.7mm_Mask2.94x5.62mm_ThermalVias +Package_SO:Texas_R-PDSO-G8_EP2.95x4.9mm_Mask2.4x3.1mm +Package_SO:Texas_R-PDSO-G8_EP2.95x4.9mm_Mask2.4x3.1mm_ThermalVias +Package_SO:Texas_S-PDSO-G8_3x3mm_P0.65mm +Package_SO:TI_SO-PowerPAD-8 +Package_SO:TI_SO-PowerPAD-8_ThermalVias +Package_SO:TSOP-5_1.65x3.05mm_P0.95mm +Package_SO:TSOP-6_1.65x3.05mm_P0.95mm +Package_SO:TSOP-I-24_12.4x6mm_P0.5mm +Package_SO:TSOP-I-24_14.4x6mm_P0.5mm +Package_SO:TSOP-I-24_16.4x6mm_P0.5mm +Package_SO:TSOP-I-24_18.4x6mm_P0.5mm +Package_SO:TSOP-I-28_11.8x8mm_P0.55mm +Package_SO:TSOP-I-32_11.8x8mm_P0.5mm +Package_SO:TSOP-I-32_12.4x8mm_P0.5mm +Package_SO:TSOP-I-32_14.4x8mm_P0.5mm +Package_SO:TSOP-I-32_16.4x8mm_P0.5mm +Package_SO:TSOP-I-32_18.4x8mm_P0.5mm +Package_SO:TSOP-I-32_18.4x8mm_P0.5mm_Reverse +Package_SO:TSOP-I-40_12.4x10mm_P0.5mm +Package_SO:TSOP-I-40_14.4x10mm_P0.5mm +Package_SO:TSOP-I-40_16.4x10mm_P0.5mm +Package_SO:TSOP-I-40_18.4x10mm_P0.5mm +Package_SO:TSOP-I-48_12.4x12mm_P0.5mm +Package_SO:TSOP-I-48_14.4x12mm_P0.5mm +Package_SO:TSOP-I-48_16.4x12mm_P0.5mm +Package_SO:TSOP-I-48_18.4x12mm_P0.5mm +Package_SO:TSOP-I-56_14.4x14mm_P0.5mm +Package_SO:TSOP-I-56_16.4x14mm_P0.5mm +Package_SO:TSOP-I-56_18.4x14mm_P0.5mm +Package_SO:TSOP-II-32_21.0x10.2mm_P1.27mm +Package_SO:TSOP-II-40-44_10.16x18.37mm_P0.8mm +Package_SO:TSOP-II-44_10.16x18.41mm_P0.8mm +Package_SO:TSOP-II-54_22.2x10.16mm_P0.8mm +Package_SO:TSSOP-100_6.1x20.8mm_P0.4mm +Package_SO:TSSOP-10_3x3mm_P0.5mm +Package_SO:TSSOP-14-1EP_4.4x5mm_P0.65mm +Package_SO:TSSOP-14_4.4x3.6mm_P0.4mm +Package_SO:TSSOP-14_4.4x5mm_P0.65mm +Package_SO:TSSOP-16-1EP_4.4x5mm_P0.65mm +Package_SO:TSSOP-16-1EP_4.4x5mm_P0.65mm_EP3x3mm +Package_SO:TSSOP-16-1EP_4.4x5mm_P0.65mm_EP3x3mm_ThermalVias +Package_SO:TSSOP-16_4.4x3.6mm_P0.4mm +Package_SO:TSSOP-16_4.4x5mm_P0.65mm +Package_SO:TSSOP-20-1EP_4.4x6.5mm_P0.65mm_EP2.15x3.35mm +Package_SO:TSSOP-20_4.4x5mm_P0.4mm +Package_SO:TSSOP-20_4.4x5mm_P0.5mm +Package_SO:TSSOP-20_4.4x6.5mm_P0.65mm +Package_SO:TSSOP-24-1EP_4.4x7.8mm_P0.65mm_EP3.2x5mm +Package_SO:TSSOP-24_4.4x5mm_P0.4mm +Package_SO:TSSOP-24_4.4x6.5mm_P0.5mm +Package_SO:TSSOP-24_4.4x7.8mm_P0.65mm +Package_SO:TSSOP-24_6.1x7.8mm_P0.65mm +Package_SO:TSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP2.74x4.75mm +Package_SO:TSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP2.74x4.75mm_ThermalVias +Package_SO:TSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP2.85x6.7mm +Package_SO:TSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.05x7.56mm +Package_SO:TSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.05x7.56mm_ThermalVias +Package_SO:TSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.4x9.7mm_Mask3.1x4.05mm +Package_SO:TSSOP-28-1EP_4.4x9.7mm_P0.65mm_EP3.4x9.7mm_Mask3.1x4.05mm_ThermalVias +Package_SO:TSSOP-28_4.4x7.8mm_P0.5mm +Package_SO:TSSOP-28_4.4x9.7mm_P0.65mm +Package_SO:TSSOP-28_6.1x7.8mm_P0.5mm +Package_SO:TSSOP-28_6.1x9.7mm_P0.65mm +Package_SO:TSSOP-28_8x9.7mm_P0.65mm +Package_SO:TSSOP-30_4.4x7.8mm_P0.5mm +Package_SO:TSSOP-30_6.1x9.7mm_P0.65mm +Package_SO:TSSOP-32_4.4x6.5mm_P0.4mm +Package_SO:TSSOP-32_6.1x11mm_P0.65mm +Package_SO:TSSOP-32_8x11mm_P0.65mm +Package_SO:TSSOP-36_4.4x7.8mm_P0.4mm +Package_SO:TSSOP-36_4.4x9.7mm_P0.5mm +Package_SO:TSSOP-36_6.1x12.5mm_P0.65mm +Package_SO:TSSOP-36_6.1x7.8mm_P0.4mm +Package_SO:TSSOP-36_6.1x9.7mm_P0.5mm +Package_SO:TSSOP-36_8x12.5mm_P0.65mm +Package_SO:TSSOP-36_8x9.7mm_P0.5mm +Package_SO:TSSOP-38_4.4x9.7mm_P0.5mm +Package_SO:TSSOP-38_6.1x12.5mm_P0.65mm +Package_SO:TSSOP-40_6.1x11mm_P0.5mm +Package_SO:TSSOP-40_6.1x14mm_P0.65mm +Package_SO:TSSOP-40_8x11mm_P0.5mm +Package_SO:TSSOP-40_8x14mm_P0.65mm +Package_SO:TSSOP-44_4.4x11.2mm_P0.5mm +Package_SO:TSSOP-44_4.4x11mm_P0.5mm +Package_SO:TSSOP-44_6.1x11mm_P0.5mm +Package_SO:TSSOP-48_4.4x9.7mm_P0.4mm +Package_SO:TSSOP-48_6.1x12.5mm_P0.5mm +Package_SO:TSSOP-48_6.1x9.7mm_P0.4mm +Package_SO:TSSOP-48_8x12.5mm_P0.5mm +Package_SO:TSSOP-48_8x9.7mm_P0.4mm +Package_SO:TSSOP-4_4.4x5mm_P4mm +Package_SO:TSSOP-50_4.4x12.5mm_P0.5mm +Package_SO:TSSOP-52_6.1x11mm_P0.4mm +Package_SO:TSSOP-52_8x11mm_P0.4mm +Package_SO:TSSOP-56_4.4x11.3mm_P0.4mm +Package_SO:TSSOP-56_6.1x12.5mm_P0.4mm +Package_SO:TSSOP-56_6.1x14mm_P0.5mm +Package_SO:TSSOP-56_8x12.5mm_P0.4mm +Package_SO:TSSOP-56_8x14mm_P0.5mm +Package_SO:TSSOP-60_8x12.5mm_P0.4mm +Package_SO:TSSOP-64_6.1x14mm_P0.4mm +Package_SO:TSSOP-64_6.1x17mm_P0.5mm +Package_SO:TSSOP-64_8x14mm_P0.4mm +Package_SO:TSSOP-68_8x14mm_P0.4mm +Package_SO:TSSOP-80_6.1x17mm_P0.4mm +Package_SO:TSSOP-8_3x3mm_P0.65mm +Package_SO:TSSOP-8_4.4x3mm_P0.65mm +Package_SO:Vishay_PowerPAK_1212-8_Dual +Package_SO:Vishay_PowerPAK_1212-8_Single +Package_SO:VSO-40_7.6x15.4mm_P0.762mm +Package_SO:VSO-56_11.1x21.5mm_P0.75mm +Package_SO:VSSOP-10_3x3mm_P0.5mm +Package_SO:VSSOP-8_2.3x2mm_P0.5mm +Package_SO:VSSOP-8_3x3mm_P0.65mm +Package_SO:Zetex_SM8 +Package_SON:Diodes_PowerDI3333-8 +Package_SON:Diodes_PowerDI3333-8_UXC_3.3x3.3mm_P0.65mm +Package_SON:EPSON_CE-USON-10_USON-10_3.2x2.5mm_P0.7mm +Package_SON:Fairchild_DualPower33-6_3x3mm +Package_SON:Fairchild_MicroPak-6_1.0x1.45mm_P0.5mm +Package_SON:Fairchild_MicroPak2-6_1.0x1.0mm_P0.35mm +Package_SON:HUSON-3-1EP_2x2mm_P1.3mm_EP1.1x1.6mm +Package_SON:HVSON-8-1EP_3x3mm_P0.65mm_EP1.6x2.4mm +Package_SON:HVSON-8-1EP_4x4mm_P0.8mm_EP2.2x3.1mm +Package_SON:Infineon_PG-LSON-8-1 +Package_SON:Infineon_PG-TDSON-8_6.15x5.15mm +Package_SON:Infineon_PG-TISON-8-2 +Package_SON:Infineon_PG-TISON-8-3 +Package_SON:Infineon_PG-TISON-8-4 +Package_SON:Infineon_PG-TISON-8-5 +Package_SON:MicroCrystal_C7_SON-8_1.5x3.2mm_P0.9mm +Package_SON:Nexperia_HUSON-12_USON-12-1EP_1.35x2.5mm_P0.4mm_EP0.4x2mm +Package_SON:Nexperia_HUSON-16_USON-16-1EP_1.35x3.3mm_P0.4mm_EP0.4x2.8mm +Package_SON:Nexperia_HUSON-8_USON-8-1EP_1.35x1.7mm_P0.4mm_EP0.4x1.2mm +Package_SON:NXP_XSON-16 +Package_SON:ROHM_VML0806 +Package_SON:RTC_SMD_MicroCrystal_C3_2.5x3.7mm +Package_SON:SON-8-1EP_3x2mm_P0.5mm_EP1.4x1.6mm +Package_SON:ST_PowerFLAT-6L_5x6mm_P1.27mm +Package_SON:ST_PowerFLAT_HV-5_8x8mm +Package_SON:ST_PowerFLAT_HV-8_5x6mm +Package_SON:Texas_DPY0002A_0.6x1mm_P0.65mm +Package_SON:Texas_DQK +Package_SON:Texas_DQX002A +Package_SON:Texas_DRC0010J +Package_SON:Texas_DRC0010J_ThermalVias +Package_SON:Texas_DRX_WSON-10_2.5x2.5mm_P0.5mm +Package_SON:Texas_DSC0010J +Package_SON:Texas_DSC0010J_ThermalVias +Package_SON:Texas_PWSON-N6 +Package_SON:Texas_R-PUSON-N14 +Package_SON:Texas_R-PUSON-N8_USON-8-1EP_1.6x2.1mm_P0.5mm_EP0.4x1.7mm +Package_SON:Texas_R-PWSON-N12_EP0.4x2mm +Package_SON:Texas_S-PDSO-N12 +Package_SON:Texas_S-PVSON-N10 +Package_SON:Texas_S-PVSON-N10_ThermalVias +Package_SON:Texas_S-PVSON-N8 +Package_SON:Texas_S-PVSON-N8_ThermalVias +Package_SON:Texas_S-PWSON-N10 +Package_SON:Texas_S-PWSON-N10_ThermalVias +Package_SON:Texas_S-PWSON-N8_EP1.2x2mm +Package_SON:Texas_S-PWSON-N8_EP1.2x2mm_ThermalVias +Package_SON:Texas_USON-6_1x1.45mm_P0.5mm_SMD +Package_SON:Texas_VSON-HR-8_1.5x2mm_P0.5mm +Package_SON:Texas_X2SON-4_1x1mm_P0.65mm +Package_SON:Texas_X2SON-5_0.8x0.8mm_P0.48mm +Package_SON:Texas_X2SON-5_0.8x0.8mm_P0.48mm_RoutingVia +Package_SON:USON-10_2.5x1.0mm_P0.5mm +Package_SON:USON-20_2x4mm_P0.4mm +Package_SON:VSON-10-1EP_3x3mm_P0.5mm_EP1.2x2mm +Package_SON:VSON-10-1EP_3x3mm_P0.5mm_EP1.2x2mm_ThermalVias +Package_SON:VSON-10-1EP_3x3mm_P0.5mm_EP1.65x2.4mm +Package_SON:VSON-10-1EP_3x3mm_P0.5mm_EP1.65x2.4mm_ThermalVias +Package_SON:VSON-14-1EP_3x4.45mm_P0.65mm_EP1.6x4.2mm +Package_SON:VSON-14-1EP_3x4.45mm_P0.65mm_EP1.6x4.2mm_ThermalVias +Package_SON:VSON-8-1EP_3x3mm_P0.65mm_EP1.65x2.4mm +Package_SON:VSON-8-1EP_3x3mm_P0.65mm_EP1.65x2.4mm_ThermalVias +Package_SON:VSON-8-1EP_3x3mm_P0.65mm_EP1.6x2.4mm +Package_SON:VSON-8_1.5x2mm_P0.5mm +Package_SON:VSON-8_3.3x3.3mm_P0.65mm_NexFET +Package_SON:VSONP-8-1EP_5x6_P1.27mm +Package_SON:Winbond_USON-8-1EP_3x2mm_P0.5mm_EP0.2x1.6mm +Package_SON:Winbond_USON-8-2EP_3x4mm_P0.8mm_EP0.2x0.8mm +Package_SON:WSON-10-1EP_2.5x2.5mm_P0.5mm_EP1.2x2mm +Package_SON:WSON-10-1EP_2.5x2.5mm_P0.5mm_EP1.2x2mm_ThermalVias +Package_SON:WSON-10-1EP_2x3mm_P0.5mm_EP0.84x2.4mm +Package_SON:WSON-10-1EP_2x3mm_P0.5mm_EP0.84x2.4mm_ThermalVias +Package_SON:WSON-10-1EP_4x3mm_P0.5mm_EP2.2x2mm +Package_SON:WSON-10-1EP_4x4mm_P0.8mm_EP2.6x3mm +Package_SON:WSON-10-1EP_4x4mm_P0.8mm_EP2.6x3mm_ThermalVias +Package_SON:WSON-12-1EP_3x2mm_P0.5mm_EP1x2.65 +Package_SON:WSON-12-1EP_3x2mm_P0.5mm_EP1x2.65_ThermalVias +Package_SON:WSON-12-1EP_3x3mm_P0.5mm_EP1.5x2.5mm +Package_SON:WSON-12-1EP_3x3mm_P0.5mm_EP1.5x2.5mm_ThermalVias +Package_SON:WSON-12-1EP_4x4mm_P0.5mm_EP2.6x3mm +Package_SON:WSON-12-1EP_4x4mm_P0.5mm_EP2.6x3mm_ThermalVias +Package_SON:WSON-14-1EP_4.0x4.0mm_P0.5mm_EP2.6x2.6mm +Package_SON:WSON-16_3.3x1.35_P0.4mm +Package_SON:WSON-6-1EP_2x2mm_P0.65mm_EP1x1.6mm +Package_SON:WSON-6-1EP_2x2mm_P0.65mm_EP1x1.6mm_ThermalVias +Package_SON:WSON-6-1EP_3x3mm_P0.95mm +Package_SON:WSON-6_1.5x1.5mm_P0.5mm +Package_SON:WSON-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mm +Package_SON:WSON-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mm_ThermalVias +Package_SON:WSON-8-1EP_3x2.5mm_P0.5mm_EP1.2x1.5mm_PullBack +Package_SON:WSON-8-1EP_3x2.5mm_P0.5mm_EP1.2x1.5mm_PullBack_ThermalVias +Package_SON:WSON-8-1EP_3x3mm_P0.5mm_EP1.2x2mm +Package_SON:WSON-8-1EP_3x3mm_P0.5mm_EP1.2x2mm_ThermalVias +Package_SON:WSON-8-1EP_3x3mm_P0.5mm_EP1.45x2.4mm +Package_SON:WSON-8-1EP_3x3mm_P0.5mm_EP1.45x2.4mm_ThermalVias +Package_SON:WSON-8-1EP_3x3mm_P0.5mm_EP1.6x2.0mm +Package_SON:WSON-8-1EP_4x4mm_P0.8mm_EP1.98x3mm +Package_SON:WSON-8-1EP_4x4mm_P0.8mm_EP1.98x3mm_ThermalVias +Package_SON:WSON-8-1EP_4x4mm_P0.8mm_EP2.2x3mm +Package_SON:WSON-8-1EP_4x4mm_P0.8mm_EP2.2x3mm_ThermalVias +Package_SON:WSON-8-1EP_4x4mm_P0.8mm_EP2.6x3mm +Package_SON:WSON-8-1EP_4x4mm_P0.8mm_EP2.6x3mm_ThermalVias +Package_SON:WSON-8-1EP_6x5mm_P1.27mm_EP3.4x4.3mm +Package_SON:WSON-8-1EP_6x5mm_P1.27mm_EP3.4x4mm +Package_SON:WSON-8-1EP_8x6mm_P1.27mm_EP3.4x4.3mm +Package_SON:X2SON-8_1.4x1mm_P0.35mm +Package_SO_J-Lead:TSOC-6_3.76x3.94mm_P1.27mm +Package_TO_SOT_SMD:Analog_KS-4 +Package_TO_SOT_SMD:ATPAK-2 +Package_TO_SOT_SMD:Diodes_SOT-553 +Package_TO_SOT_SMD:HVSOF5 +Package_TO_SOT_SMD:HVSOF6 +Package_TO_SOT_SMD:Infineon_PG-HDSOP-10-1 +Package_TO_SOT_SMD:Infineon_PG-HSOF-8-1 +Package_TO_SOT_SMD:Infineon_PG-HSOF-8-1_ThermalVias +Package_TO_SOT_SMD:Infineon_PG-HSOF-8-2 +Package_TO_SOT_SMD:Infineon_PG-HSOF-8-2_ThermalVias +Package_TO_SOT_SMD:Infineon_PG-HSOF-8-2_ThermalVias2 +Package_TO_SOT_SMD:Infineon_PG-HSOF-8-3 +Package_TO_SOT_SMD:Infineon_PG-HSOF-8-3_ThermalVias +Package_TO_SOT_SMD:Infineon_PG-TO-220-7Lead_TabPin8 +Package_TO_SOT_SMD:Infineon_PG-TSFP-3-1 +Package_TO_SOT_SMD:LFPAK33 +Package_TO_SOT_SMD:LFPAK56 +Package_TO_SOT_SMD:LFPAK88 +Package_TO_SOT_SMD:Nexperia_CFP15_SOT-1289 +Package_TO_SOT_SMD:OnSemi_ECH8 +Package_TO_SOT_SMD:PowerMacro_M234_NoHole +Package_TO_SOT_SMD:PowerMacro_M234_WithHole +Package_TO_SOT_SMD:PQFN_8x8 +Package_TO_SOT_SMD:Rohm_HRP7 +Package_TO_SOT_SMD:ROHM_SOT-457_ClockwisePinNumbering +Package_TO_SOT_SMD:SC-59 +Package_TO_SOT_SMD:SC-59_Handsoldering +Package_TO_SOT_SMD:SC-70-8 +Package_TO_SOT_SMD:SC-70-8_Handsoldering +Package_TO_SOT_SMD:SC-74-6_1.55x2.9mm_P0.95mm +Package_TO_SOT_SMD:SC-74A-5_1.55x2.9mm_P0.95mm +Package_TO_SOT_SMD:SC-82AA +Package_TO_SOT_SMD:SC-82AA_Handsoldering +Package_TO_SOT_SMD:SC-82AB +Package_TO_SOT_SMD:SC-82AB_Handsoldering +Package_TO_SOT_SMD:SOT-1123 +Package_TO_SOT_SMD:SOT-1333-1 +Package_TO_SOT_SMD:SOT-1334-1 +Package_TO_SOT_SMD:SOT-143 +Package_TO_SOT_SMD:SOT-143R +Package_TO_SOT_SMD:SOT-143R_Handsoldering +Package_TO_SOT_SMD:SOT-143_Handsoldering +Package_TO_SOT_SMD:SOT-223-3_TabPin2 +Package_TO_SOT_SMD:SOT-223-5 +Package_TO_SOT_SMD:SOT-223-6 +Package_TO_SOT_SMD:SOT-223-6_TabPin3 +Package_TO_SOT_SMD:SOT-223-8 +Package_TO_SOT_SMD:SOT-223 +Package_TO_SOT_SMD:SOT-23-3 +Package_TO_SOT_SMD:SOT-23-5 +Package_TO_SOT_SMD:SOT-23-5_HandSoldering +Package_TO_SOT_SMD:SOT-23-6 +Package_TO_SOT_SMD:SOT-23-6_Handsoldering +Package_TO_SOT_SMD:SOT-23-8 +Package_TO_SOT_SMD:SOT-23-8_Handsoldering +Package_TO_SOT_SMD:SOT-23 +Package_TO_SOT_SMD:SOT-23W +Package_TO_SOT_SMD:SOT-23W_Handsoldering +Package_TO_SOT_SMD:SOT-23_Handsoldering +Package_TO_SOT_SMD:SOT-323_SC-70 +Package_TO_SOT_SMD:SOT-323_SC-70_Handsoldering +Package_TO_SOT_SMD:SOT-343_SC-70-4 +Package_TO_SOT_SMD:SOT-343_SC-70-4_Handsoldering +Package_TO_SOT_SMD:SOT-353_SC-70-5 +Package_TO_SOT_SMD:SOT-353_SC-70-5_Handsoldering +Package_TO_SOT_SMD:SOT-363_SC-70-6 +Package_TO_SOT_SMD:SOT-363_SC-70-6_Handsoldering +Package_TO_SOT_SMD:SOT-383F +Package_TO_SOT_SMD:SOT-383FL +Package_TO_SOT_SMD:SOT-416 +Package_TO_SOT_SMD:SOT-523 +Package_TO_SOT_SMD:SOT-543 +Package_TO_SOT_SMD:SOT-553 +Package_TO_SOT_SMD:SOT-563 +Package_TO_SOT_SMD:SOT-583-8 +Package_TO_SOT_SMD:SOT-665 +Package_TO_SOT_SMD:SOT-666 +Package_TO_SOT_SMD:SOT-723 +Package_TO_SOT_SMD:SOT-883 +Package_TO_SOT_SMD:SOT-886 +Package_TO_SOT_SMD:SOT-89-3 +Package_TO_SOT_SMD:SOT-89-3_Handsoldering +Package_TO_SOT_SMD:SOT-89-5 +Package_TO_SOT_SMD:SOT-89-5_Handsoldering +Package_TO_SOT_SMD:SOT-963 +Package_TO_SOT_SMD:SuperSOT-3 +Package_TO_SOT_SMD:SuperSOT-6 +Package_TO_SOT_SMD:SuperSOT-8 +Package_TO_SOT_SMD:TDSON-8-1 +Package_TO_SOT_SMD:Texas_DRT-3 +Package_TO_SOT_SMD:Texas_NDQ +Package_TO_SOT_SMD:Texas_NDW-7_TabPin4 +Package_TO_SOT_SMD:Texas_NDW-7_TabPin8 +Package_TO_SOT_SMD:Texas_NDY0011A +Package_TO_SOT_SMD:Texas_R-PDSO-G5_DCK-5 +Package_TO_SOT_SMD:Texas_R-PDSO-G6 +Package_TO_SOT_SMD:Texas_R-PDSO-N5_DRL-5 +Package_TO_SOT_SMD:Texas_R-PDSO-N6_DRL-6 +Package_TO_SOT_SMD:TO-252-2 +Package_TO_SOT_SMD:TO-252-2_TabPin1 +Package_TO_SOT_SMD:TO-252-3_TabPin2 +Package_TO_SOT_SMD:TO-252-3_TabPin4 +Package_TO_SOT_SMD:TO-252-4 +Package_TO_SOT_SMD:TO-252-5_TabPin3 +Package_TO_SOT_SMD:TO-252-5_TabPin6 +Package_TO_SOT_SMD:TO-263-2 +Package_TO_SOT_SMD:TO-263-2_TabPin1 +Package_TO_SOT_SMD:TO-263-3_TabPin2 +Package_TO_SOT_SMD:TO-263-3_TabPin4 +Package_TO_SOT_SMD:TO-263-4 +Package_TO_SOT_SMD:TO-263-5_TabPin3 +Package_TO_SOT_SMD:TO-263-5_TabPin6 +Package_TO_SOT_SMD:TO-263-6 +Package_TO_SOT_SMD:TO-263-7_TabPin4 +Package_TO_SOT_SMD:TO-263-7_TabPin8 +Package_TO_SOT_SMD:TO-263-9_TabPin10 +Package_TO_SOT_SMD:TO-263-9_TabPin5 +Package_TO_SOT_SMD:TO-268-2 +Package_TO_SOT_SMD:TO-269AA +Package_TO_SOT_SMD:TO-277A +Package_TO_SOT_SMD:TO-277B +Package_TO_SOT_SMD:TO-50-3_LongPad-NoHole_Housing +Package_TO_SOT_SMD:TO-50-3_LongPad-WithHole_Housing +Package_TO_SOT_SMD:TO-50-3_ShortPad-NoHole_Housing +Package_TO_SOT_SMD:TO-50-3_ShortPad-WithHole_Housing +Package_TO_SOT_SMD:TO-50-4_LongPad-NoHole_Housing +Package_TO_SOT_SMD:TO-50-4_LongPad-WithHole_Housing +Package_TO_SOT_SMD:TO-50-4_ShortPad-NoHole_Housing +Package_TO_SOT_SMD:TO-50-4_ShortPad-WithHole_Housing +Package_TO_SOT_SMD:TSOT-23-5 +Package_TO_SOT_SMD:TSOT-23-5_HandSoldering +Package_TO_SOT_SMD:TSOT-23-6 +Package_TO_SOT_SMD:TSOT-23-6_HandSoldering +Package_TO_SOT_SMD:TSOT-23-8 +Package_TO_SOT_SMD:TSOT-23-8_HandSoldering +Package_TO_SOT_SMD:TSOT-23 +Package_TO_SOT_SMD:TSOT-23_HandSoldering +Package_TO_SOT_SMD:Vishay_PowerPAK_SC70-6L_Dual +Package_TO_SOT_SMD:Vishay_PowerPAK_SC70-6L_Single +Package_TO_SOT_SMD:VSOF5 +Package_TO_SOT_THT:Analog_TO-46-4_ThermalShield +Package_TO_SOT_THT:Fairchild_TO-220F-6L +Package_TO_SOT_THT:Heraeus_TO-92-2 +Package_TO_SOT_THT:NEC_Molded_7x4x9mm +Package_TO_SOT_THT:PowerIntegrations_TO-220-7C +Package_TO_SOT_THT:SIPAK-1EP_Horizontal_TabDown +Package_TO_SOT_THT:SIPAK_Vertical +Package_TO_SOT_THT:SOD-70_P2.54mm +Package_TO_SOT_THT:SOD-70_P5.08mm +Package_TO_SOT_THT:SOT-227 +Package_TO_SOT_THT:TO-100-10 +Package_TO_SOT_THT:TO-100-10_Window +Package_TO_SOT_THT:TO-11-2 +Package_TO_SOT_THT:TO-11-2_Window +Package_TO_SOT_THT:TO-11-3 +Package_TO_SOT_THT:TO-11-3_Window +Package_TO_SOT_THT:TO-12-4 +Package_TO_SOT_THT:TO-12-4_Window +Package_TO_SOT_THT:TO-126-2_Horizontal_TabDown +Package_TO_SOT_THT:TO-126-2_Horizontal_TabUp +Package_TO_SOT_THT:TO-126-2_Vertical +Package_TO_SOT_THT:TO-126-3_Horizontal_TabDown +Package_TO_SOT_THT:TO-126-3_Horizontal_TabUp +Package_TO_SOT_THT:TO-126-3_Vertical +Package_TO_SOT_THT:TO-17-4 +Package_TO_SOT_THT:TO-17-4_Window +Package_TO_SOT_THT:TO-18-2 +Package_TO_SOT_THT:TO-18-2_Lens +Package_TO_SOT_THT:TO-18-2_Window +Package_TO_SOT_THT:TO-18-3 +Package_TO_SOT_THT:TO-18-3_Lens +Package_TO_SOT_THT:TO-18-3_Window +Package_TO_SOT_THT:TO-18-4 +Package_TO_SOT_THT:TO-18-4_Lens +Package_TO_SOT_THT:TO-18-4_Window +Package_TO_SOT_THT:TO-218-2_Horizontal_TabDown +Package_TO_SOT_THT:TO-218-2_Horizontal_TabUp +Package_TO_SOT_THT:TO-218-2_Vertical +Package_TO_SOT_THT:TO-218-3_Horizontal_TabDown +Package_TO_SOT_THT:TO-218-3_Horizontal_TabUp +Package_TO_SOT_THT:TO-218-3_Vertical +Package_TO_SOT_THT:TO-220-11_P3.4x2.54mm_StaggerEven_Lead5.84mm_TabDown +Package_TO_SOT_THT:TO-220-11_P3.4x2.54mm_StaggerOdd_Lead5.84mm_TabDown +Package_TO_SOT_THT:TO-220-11_P3.4x5.08mm_StaggerEven_Lead4.58mm_Vertical +Package_TO_SOT_THT:TO-220-11_P3.4x5.08mm_StaggerOdd_Lead4.58mm_Vertical +Package_TO_SOT_THT:TO-220-11_P3.4x5.08mm_StaggerOdd_Lead8.45mm_TabDown +Package_TO_SOT_THT:TO-220-15_P2.54x2.54mm_StaggerEven_Lead5.84mm_TabDown +Package_TO_SOT_THT:TO-220-15_P2.54x2.54mm_StaggerOdd_Lead5.84mm_TabDown +Package_TO_SOT_THT:TO-220-15_P2.54x5.08mm_StaggerEven_Lead4.58mm_Vertical +Package_TO_SOT_THT:TO-220-15_P2.54x5.08mm_StaggerOdd_Lead4.58mm_Vertical +Package_TO_SOT_THT:TO-220-2_Horizontal_TabDown +Package_TO_SOT_THT:TO-220-2_Horizontal_TabUp +Package_TO_SOT_THT:TO-220-2_Vertical +Package_TO_SOT_THT:TO-220-3_Horizontal_TabDown +Package_TO_SOT_THT:TO-220-3_Horizontal_TabUp +Package_TO_SOT_THT:TO-220-3_Vertical +Package_TO_SOT_THT:TO-220-4_Horizontal_TabDown +Package_TO_SOT_THT:TO-220-4_Horizontal_TabUp +Package_TO_SOT_THT:TO-220-4_P5.08x3.7mm_StaggerEven_Lead3.8mm_Vertical +Package_TO_SOT_THT:TO-220-4_P5.08x3.7mm_StaggerOdd_Lead3.8mm_Vertical +Package_TO_SOT_THT:TO-220-4_P5.08x3.8mm_StaggerEven_Lead5.85mm_TabDown +Package_TO_SOT_THT:TO-220-4_P5.08x3.8mm_StaggerOdd_Lead5.85mm_TabDown +Package_TO_SOT_THT:TO-220-4_Vertical +Package_TO_SOT_THT:TO-220-5_Horizontal_TabDown +Package_TO_SOT_THT:TO-220-5_Horizontal_TabUp +Package_TO_SOT_THT:TO-220-5_P3.4x3.7mm_StaggerEven_Lead3.8mm_Vertical +Package_TO_SOT_THT:TO-220-5_P3.4x3.7mm_StaggerOdd_Lead3.8mm_Vertical +Package_TO_SOT_THT:TO-220-5_P3.4x3.8mm_StaggerEven_Lead7.13mm_TabDown +Package_TO_SOT_THT:TO-220-5_P3.4x3.8mm_StaggerOdd_Lead7.13mm_TabDown +Package_TO_SOT_THT:TO-220-5_Vertical +Package_TO_SOT_THT:TO-220-7_P2.54x3.7mm_StaggerEven_Lead3.8mm_Vertical +Package_TO_SOT_THT:TO-220-7_P2.54x3.7mm_StaggerOdd_Lead3.8mm_Vertical +Package_TO_SOT_THT:TO-220-7_P2.54x3.8mm_StaggerEven_Lead5.85mm_TabDown +Package_TO_SOT_THT:TO-220-7_P2.54x3.8mm_StaggerOdd_Lead5.85mm_TabDown +Package_TO_SOT_THT:TO-220-7_P2.54x5.08mm_StaggerOdd_Lead3.08mm_Vertical +Package_TO_SOT_THT:TO-220-7_P2.54x5.1mm_StaggerOdd_Lead8.025mm_TabDown +Package_TO_SOT_THT:TO-220-8_Vertical +Package_TO_SOT_THT:TO-220-9_P1.94x3.7mm_StaggerEven_Lead3.8mm_Vertical +Package_TO_SOT_THT:TO-220-9_P1.94x3.7mm_StaggerOdd_Lead3.8mm_Vertical +Package_TO_SOT_THT:TO-220-9_P1.94x3.8mm_StaggerEven_Lead5.85mm_TabDown +Package_TO_SOT_THT:TO-220-9_P1.94x3.8mm_StaggerOdd_Lead5.85mm_TabDown +Package_TO_SOT_THT:TO-220F-11_P3.4x5.08mm_StaggerEven_Lead5.08mm_Vertical +Package_TO_SOT_THT:TO-220F-11_P3.4x5.08mm_StaggerOdd_Lead5.08mm_Vertical +Package_TO_SOT_THT:TO-220F-15_P2.54x5.08mm_StaggerEven_Lead5.08mm_Vertical +Package_TO_SOT_THT:TO-220F-15_P2.54x5.08mm_StaggerOdd_Lead5.08mm_Vertical +Package_TO_SOT_THT:TO-220F-2_Horizontal_TabDown +Package_TO_SOT_THT:TO-220F-2_Horizontal_TabUp +Package_TO_SOT_THT:TO-220F-2_Vertical +Package_TO_SOT_THT:TO-220F-3_Horizontal_TabDown +Package_TO_SOT_THT:TO-220F-3_Horizontal_TabUp +Package_TO_SOT_THT:TO-220F-3_Vertical +Package_TO_SOT_THT:TO-220F-4_Horizontal_TabDown +Package_TO_SOT_THT:TO-220F-4_Horizontal_TabUp +Package_TO_SOT_THT:TO-220F-4_P5.08x2.05mm_StaggerEven_Lead1.85mm_Vertical +Package_TO_SOT_THT:TO-220F-4_P5.08x2.05mm_StaggerOdd_Lead1.85mm_Vertical +Package_TO_SOT_THT:TO-220F-4_P5.08x3.7mm_StaggerEven_Lead3.5mm_Vertical +Package_TO_SOT_THT:TO-220F-4_P5.08x3.7mm_StaggerOdd_Lead3.5mm_Vertical +Package_TO_SOT_THT:TO-220F-4_Vertical +Package_TO_SOT_THT:TO-220F-5_Horizontal_TabDown +Package_TO_SOT_THT:TO-220F-5_Horizontal_TabUp +Package_TO_SOT_THT:TO-220F-5_P3.4x2.06mm_StaggerEven_Lead1.86mm_Vertical +Package_TO_SOT_THT:TO-220F-5_P3.4x2.06mm_StaggerOdd_Lead1.86mm_Vertical +Package_TO_SOT_THT:TO-220F-5_P3.4x3.7mm_StaggerEven_Lead3.5mm_Vertical +Package_TO_SOT_THT:TO-220F-5_P3.4x3.7mm_StaggerOdd_Lead3.5mm_Vertical +Package_TO_SOT_THT:TO-220F-5_Vertical +Package_TO_SOT_THT:TO-220F-7_P2.54x3.7mm_StaggerEven_Lead3.5mm_Vertical +Package_TO_SOT_THT:TO-220F-7_P2.54x3.7mm_StaggerOdd_Lead3.5mm_Vertical +Package_TO_SOT_THT:TO-220F-9_P1.8x3.7mm_StaggerEven_Lead3.5mm_Vertical +Package_TO_SOT_THT:TO-220F-9_P1.8x3.7mm_StaggerOdd_Lead3.5mm_Vertical +Package_TO_SOT_THT:TO-247-2_Horizontal_TabDown +Package_TO_SOT_THT:TO-247-2_Horizontal_TabUp +Package_TO_SOT_THT:TO-247-2_Vertical +Package_TO_SOT_THT:TO-247-3_Horizontal_TabDown +Package_TO_SOT_THT:TO-247-3_Horizontal_TabUp +Package_TO_SOT_THT:TO-247-3_Vertical +Package_TO_SOT_THT:TO-247-4_Horizontal_TabDown +Package_TO_SOT_THT:TO-247-4_Horizontal_TabUp +Package_TO_SOT_THT:TO-247-4_Vertical +Package_TO_SOT_THT:TO-247-5_Horizontal_TabDown +Package_TO_SOT_THT:TO-247-5_Horizontal_TabUp +Package_TO_SOT_THT:TO-247-5_Vertical +Package_TO_SOT_THT:TO-251-2-1EP_Horizontal_TabDown +Package_TO_SOT_THT:TO-251-2_Vertical +Package_TO_SOT_THT:TO-251-3-1EP_Horizontal_TabDown +Package_TO_SOT_THT:TO-251-3_Vertical +Package_TO_SOT_THT:TO-262-3-1EP_Horizontal_TabDown +Package_TO_SOT_THT:TO-262-3_Vertical +Package_TO_SOT_THT:TO-262-5-1EP_Horizontal_TabDown +Package_TO_SOT_THT:TO-262-5_Vertical +Package_TO_SOT_THT:TO-264-2_Horizontal_TabDown +Package_TO_SOT_THT:TO-264-2_Horizontal_TabUp +Package_TO_SOT_THT:TO-264-2_Vertical +Package_TO_SOT_THT:TO-264-3_Horizontal_TabDown +Package_TO_SOT_THT:TO-264-3_Horizontal_TabUp +Package_TO_SOT_THT:TO-264-3_Vertical +Package_TO_SOT_THT:TO-264-5_Horizontal_TabDown +Package_TO_SOT_THT:TO-264-5_Horizontal_TabUp +Package_TO_SOT_THT:TO-264-5_Vertical +Package_TO_SOT_THT:TO-3 +Package_TO_SOT_THT:TO-33-4 +Package_TO_SOT_THT:TO-33-4_Window +Package_TO_SOT_THT:TO-38-2 +Package_TO_SOT_THT:TO-38-2_Window +Package_TO_SOT_THT:TO-38-3 +Package_TO_SOT_THT:TO-38-3_Window +Package_TO_SOT_THT:TO-39-10 +Package_TO_SOT_THT:TO-39-10_Window +Package_TO_SOT_THT:TO-39-2 +Package_TO_SOT_THT:TO-39-2_Window +Package_TO_SOT_THT:TO-39-3 +Package_TO_SOT_THT:TO-39-3_Window +Package_TO_SOT_THT:TO-39-4 +Package_TO_SOT_THT:TO-39-4_Window +Package_TO_SOT_THT:TO-39-6 +Package_TO_SOT_THT:TO-39-6_Window +Package_TO_SOT_THT:TO-39-8 +Package_TO_SOT_THT:TO-39-8_Window +Package_TO_SOT_THT:TO-3P-3_Horizontal_TabDown +Package_TO_SOT_THT:TO-3P-3_Horizontal_TabUp +Package_TO_SOT_THT:TO-3P-3_Vertical +Package_TO_SOT_THT:TO-3PB-3_Horizontal_TabDown +Package_TO_SOT_THT:TO-3PB-3_Horizontal_TabUp +Package_TO_SOT_THT:TO-3PB-3_Vertical +Package_TO_SOT_THT:TO-46-2 +Package_TO_SOT_THT:TO-46-2_Pin2Center +Package_TO_SOT_THT:TO-46-2_Pin2Center_Window +Package_TO_SOT_THT:TO-46-2_Window +Package_TO_SOT_THT:TO-46-3 +Package_TO_SOT_THT:TO-46-3_Pin2Center +Package_TO_SOT_THT:TO-46-3_Pin2Center_Window +Package_TO_SOT_THT:TO-46-3_Window +Package_TO_SOT_THT:TO-46-4 +Package_TO_SOT_THT:TO-46-4_Window +Package_TO_SOT_THT:TO-5-10 +Package_TO_SOT_THT:TO-5-10_Window +Package_TO_SOT_THT:TO-5-2 +Package_TO_SOT_THT:TO-5-2_Window +Package_TO_SOT_THT:TO-5-3 +Package_TO_SOT_THT:TO-5-3_Window +Package_TO_SOT_THT:TO-5-4 +Package_TO_SOT_THT:TO-5-4_Window +Package_TO_SOT_THT:TO-5-6 +Package_TO_SOT_THT:TO-5-6_Window +Package_TO_SOT_THT:TO-5-8 +Package_TO_SOT_THT:TO-5-8_PD5.08 +Package_TO_SOT_THT:TO-5-8_PD5.08_Window +Package_TO_SOT_THT:TO-5-8_Window +Package_TO_SOT_THT:TO-52-2 +Package_TO_SOT_THT:TO-52-2_Window +Package_TO_SOT_THT:TO-52-3 +Package_TO_SOT_THT:TO-52-3_Window +Package_TO_SOT_THT:TO-72-4 +Package_TO_SOT_THT:TO-72-4_Window +Package_TO_SOT_THT:TO-75-6 +Package_TO_SOT_THT:TO-75-6_Window +Package_TO_SOT_THT:TO-78-10 +Package_TO_SOT_THT:TO-78-10_Window +Package_TO_SOT_THT:TO-78-6 +Package_TO_SOT_THT:TO-78-6_Window +Package_TO_SOT_THT:TO-78-8 +Package_TO_SOT_THT:TO-78-8_Window +Package_TO_SOT_THT:TO-8-2 +Package_TO_SOT_THT:TO-8-2_Window +Package_TO_SOT_THT:TO-8-3 +Package_TO_SOT_THT:TO-8-3_Window +Package_TO_SOT_THT:TO-92-2 +Package_TO_SOT_THT:TO-92-2_Horizontal1 +Package_TO_SOT_THT:TO-92-2_Horizontal2 +Package_TO_SOT_THT:TO-92-2_W4.0mm_Horizontal_FlatSideDown +Package_TO_SOT_THT:TO-92-2_W4.0mm_Horizontal_FlatSideUp +Package_TO_SOT_THT:TO-92-2_Wide +Package_TO_SOT_THT:TO-92 +Package_TO_SOT_THT:TO-92Flat +Package_TO_SOT_THT:TO-92L +Package_TO_SOT_THT:TO-92L_HandSolder +Package_TO_SOT_THT:TO-92L_Inline +Package_TO_SOT_THT:TO-92L_Inline_Wide +Package_TO_SOT_THT:TO-92L_Wide +Package_TO_SOT_THT:TO-92Mini-2 +Package_TO_SOT_THT:TO-92S-2 +Package_TO_SOT_THT:TO-92S +Package_TO_SOT_THT:TO-92S_Wide +Package_TO_SOT_THT:TO-92_HandSolder +Package_TO_SOT_THT:TO-92_Horizontal1 +Package_TO_SOT_THT:TO-92_Horizontal2 +Package_TO_SOT_THT:TO-92_Inline +Package_TO_SOT_THT:TO-92_Inline_Horizontal1 +Package_TO_SOT_THT:TO-92_Inline_Horizontal2 +Package_TO_SOT_THT:TO-92_Inline_W4.0mm_Horizontal_FlatSideDown +Package_TO_SOT_THT:TO-92_Inline_W4.0mm_Horizontal_FlatSideUp +Package_TO_SOT_THT:TO-92_Inline_Wide +Package_TO_SOT_THT:TO-92_W4.0mm_StaggerEven_Horizontal_FlatSideDown +Package_TO_SOT_THT:TO-92_W4.0mm_StaggerEven_Horizontal_FlatSideUp +Package_TO_SOT_THT:TO-92_Wide +Package_TO_SOT_THT:TO-99-6 +Package_TO_SOT_THT:TO-99-6_Window +Package_TO_SOT_THT:TO-99-8 +Package_TO_SOT_THT:TO-99-8_Window +Potentiometer_SMD:Potentiometer_ACP_CA14-VSMD_Vertical +Potentiometer_SMD:Potentiometer_ACP_CA14-VSMD_Vertical_Hole +Potentiometer_SMD:Potentiometer_ACP_CA6-VSMD_Vertical +Potentiometer_SMD:Potentiometer_ACP_CA6-VSMD_Vertical_Hole +Potentiometer_SMD:Potentiometer_ACP_CA9-VSMD_Vertical +Potentiometer_SMD:Potentiometer_ACP_CA9-VSMD_Vertical_Hole +Potentiometer_SMD:Potentiometer_Bourns_3214G_Horizontal +Potentiometer_SMD:Potentiometer_Bourns_3214J_Horizontal +Potentiometer_SMD:Potentiometer_Bourns_3214W_Vertical +Potentiometer_SMD:Potentiometer_Bourns_3214X_Vertical +Potentiometer_SMD:Potentiometer_Bourns_3224G_Horizontal +Potentiometer_SMD:Potentiometer_Bourns_3224J_Horizontal +Potentiometer_SMD:Potentiometer_Bourns_3224W_Vertical +Potentiometer_SMD:Potentiometer_Bourns_3224X_Vertical +Potentiometer_SMD:Potentiometer_Bourns_3269P_Horizontal +Potentiometer_SMD:Potentiometer_Bourns_3269W_Vertical +Potentiometer_SMD:Potentiometer_Bourns_3269X_Horizontal +Potentiometer_SMD:Potentiometer_Bourns_3314G_Vertical +Potentiometer_SMD:Potentiometer_Bourns_3314J_Vertical +Potentiometer_SMD:Potentiometer_Bourns_3314R-1_Vertical_Hole +Potentiometer_SMD:Potentiometer_Bourns_3314R-GM5_Vertical +Potentiometer_SMD:Potentiometer_Bourns_3314S_Horizontal +Potentiometer_SMD:Potentiometer_Bourns_PRS11S_Vertical +Potentiometer_SMD:Potentiometer_Bourns_TC33X_Vertical +Potentiometer_SMD:Potentiometer_Vishay_TS53YJ_Vertical +Potentiometer_SMD:Potentiometer_Vishay_TS53YL_Vertical +Potentiometer_THT:Potentiometer_ACP_CA14-H2,5_Horizontal +Potentiometer_THT:Potentiometer_ACP_CA14-H4_Horizontal +Potentiometer_THT:Potentiometer_ACP_CA14-H5_Horizontal +Potentiometer_THT:Potentiometer_ACP_CA14V-15_Vertical +Potentiometer_THT:Potentiometer_ACP_CA14V-15_Vertical_Hole +Potentiometer_THT:Potentiometer_ACP_CA6-H2,5_Horizontal +Potentiometer_THT:Potentiometer_ACP_CA9-H2,5_Horizontal +Potentiometer_THT:Potentiometer_ACP_CA9-H3,8_Horizontal +Potentiometer_THT:Potentiometer_ACP_CA9-H5_Horizontal +Potentiometer_THT:Potentiometer_ACP_CA9-V10_Vertical +Potentiometer_THT:Potentiometer_ACP_CA9-V10_Vertical_Hole +Potentiometer_THT:Potentiometer_Alpha_RD901F-40-00D_Single_Vertical +Potentiometer_THT:Potentiometer_Alpha_RD901F-40-00D_Single_Vertical_CircularHoles +Potentiometer_THT:Potentiometer_Alpha_RD902F-40-00D_Dual_Vertical +Potentiometer_THT:Potentiometer_Alpha_RD902F-40-00D_Dual_Vertical_CircularHoles +Potentiometer_THT:Potentiometer_Alps_RK097_Dual_Horizontal +Potentiometer_THT:Potentiometer_Alps_RK097_Dual_Horizontal_Switch +Potentiometer_THT:Potentiometer_Alps_RK097_Single_Horizontal +Potentiometer_THT:Potentiometer_Alps_RK097_Single_Horizontal_Switch +Potentiometer_THT:Potentiometer_Alps_RK09K_Single_Horizontal +Potentiometer_THT:Potentiometer_Alps_RK09K_Single_Vertical +Potentiometer_THT:Potentiometer_Alps_RK09L_Double_Horizontal +Potentiometer_THT:Potentiometer_Alps_RK09L_Double_Vertical +Potentiometer_THT:Potentiometer_Alps_RK09L_Single_Horizontal +Potentiometer_THT:Potentiometer_Alps_RK09L_Single_Vertical +Potentiometer_THT:Potentiometer_Alps_RK09Y11_Single_Horizontal +Potentiometer_THT:Potentiometer_Alps_RK163_Dual_Horizontal +Potentiometer_THT:Potentiometer_Alps_RK163_Single_Horizontal +Potentiometer_THT:Potentiometer_Bourns_20P_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3005_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3006P_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3006W_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3006Y_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3009P_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3009Y_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3266P_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3266W_Vertical +Potentiometer_THT:Potentiometer_Bourns_3266X_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3266Y_Vertical +Potentiometer_THT:Potentiometer_Bourns_3266Z_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3296P_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3296W_Vertical +Potentiometer_THT:Potentiometer_Bourns_3296X_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3296Y_Vertical +Potentiometer_THT:Potentiometer_Bourns_3296Z_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3299P_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3299W_Vertical +Potentiometer_THT:Potentiometer_Bourns_3299X_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3299Y_Vertical +Potentiometer_THT:Potentiometer_Bourns_3299Z_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3339H_Vertical +Potentiometer_THT:Potentiometer_Bourns_3339P_Vertical +Potentiometer_THT:Potentiometer_Bourns_3339P_Vertical_HandSoldering +Potentiometer_THT:Potentiometer_Bourns_3339S_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3339W_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3386C_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3386F_Vertical +Potentiometer_THT:Potentiometer_Bourns_3386P_Vertical +Potentiometer_THT:Potentiometer_Bourns_3386W_Horizontal +Potentiometer_THT:Potentiometer_Bourns_3386X_Horizontal +Potentiometer_THT:Potentiometer_Bourns_PTA1543_Single_Slide +Potentiometer_THT:Potentiometer_Bourns_PTA2043_Single_Slide +Potentiometer_THT:Potentiometer_Bourns_PTA3043_Single_Slide +Potentiometer_THT:Potentiometer_Bourns_PTA4543_Single_Slide +Potentiometer_THT:Potentiometer_Bourns_PTA6043_Single_Slide +Potentiometer_THT:Potentiometer_Bourns_PTV09A-1_Single_Vertical +Potentiometer_THT:Potentiometer_Bourns_PTV09A-2_Single_Horizontal +Potentiometer_THT:Potentiometer_Bourns_PTV112-4_Dual_Vertical +Potentiometer_THT:Potentiometer_Omeg_PC16BU_Horizontal +Potentiometer_THT:Potentiometer_Omeg_PC16BU_Vertical +Potentiometer_THT:Potentiometer_Piher_PC-16_Dual_Horizontal +Potentiometer_THT:Potentiometer_Piher_PC-16_Single_Horizontal +Potentiometer_THT:Potentiometer_Piher_PC-16_Single_Vertical +Potentiometer_THT:Potentiometer_Piher_PC-16_Triple_Horizontal +Potentiometer_THT:Potentiometer_Piher_PT-10-H01_Horizontal +Potentiometer_THT:Potentiometer_Piher_PT-10-H05_Horizontal +Potentiometer_THT:Potentiometer_Piher_PT-10-V05_Vertical +Potentiometer_THT:Potentiometer_Piher_PT-10-V10_Vertical +Potentiometer_THT:Potentiometer_Piher_PT-10-V10_Vertical_Hole +Potentiometer_THT:Potentiometer_Piher_PT-15-H01_Horizontal +Potentiometer_THT:Potentiometer_Piher_PT-15-H05_Horizontal +Potentiometer_THT:Potentiometer_Piher_PT-15-H06_Horizontal +Potentiometer_THT:Potentiometer_Piher_PT-15-H25_Horizontal +Potentiometer_THT:Potentiometer_Piher_PT-15-V02_Vertical +Potentiometer_THT:Potentiometer_Piher_PT-15-V02_Vertical_Hole +Potentiometer_THT:Potentiometer_Piher_PT-15-V15_Vertical +Potentiometer_THT:Potentiometer_Piher_PT-15-V15_Vertical_Hole +Potentiometer_THT:Potentiometer_Piher_PT-6-H_Horizontal +Potentiometer_THT:Potentiometer_Piher_PT-6-V_Vertical +Potentiometer_THT:Potentiometer_Piher_PT-6-V_Vertical_Hole +Potentiometer_THT:Potentiometer_Piher_T-16H_Double_Horizontal +Potentiometer_THT:Potentiometer_Piher_T-16H_Single_Horizontal +Potentiometer_THT:Potentiometer_Piher_T-16L_Single_Vertical_Hole +Potentiometer_THT:Potentiometer_Runtron_RM-063_Horizontal +Potentiometer_THT:Potentiometer_Runtron_RM-065_Vertical +Potentiometer_THT:Potentiometer_TT_P0915N +Potentiometer_THT:Potentiometer_Vishay_148-149_Dual_Horizontal +Potentiometer_THT:Potentiometer_Vishay_148-149_Single_Horizontal +Potentiometer_THT:Potentiometer_Vishay_148-149_Single_Vertical +Potentiometer_THT:Potentiometer_Vishay_148E-149E_Dual_Horizontal +Potentiometer_THT:Potentiometer_Vishay_148E-149E_Single_Horizontal +Potentiometer_THT:Potentiometer_Vishay_248BH-249BH_Single_Horizontal +Potentiometer_THT:Potentiometer_Vishay_248GJ-249GJ_Single_Horizontal +Potentiometer_THT:Potentiometer_Vishay_248GJ-249GJ_Single_Vertical +Potentiometer_THT:Potentiometer_Vishay_43_Horizontal +Potentiometer_THT:Potentiometer_Vishay_T7-YA_Single_Vertical +Potentiometer_THT:Potentiometer_Vishay_T73XW_Horizontal +Potentiometer_THT:Potentiometer_Vishay_T73XX_Horizontal +Potentiometer_THT:Potentiometer_Vishay_T73YP_Vertical +Potentiometer_THT:Potentiometer_Vishay_T93XA_Horizontal +Potentiometer_THT:Potentiometer_Vishay_T93YA_Vertical +Relay_SMD:Relay_2P2T_10x6mm_TE_IMxxG +Relay_SMD:Relay_DPDT_AXICOM_IMSeries_JLeg +Relay_SMD:Relay_DPDT_FRT5_SMD +Relay_SMD:Relay_DPDT_Kemet_EE2_NU +Relay_SMD:Relay_DPDT_Kemet_EE2_NUH +Relay_SMD:Relay_DPDT_Kemet_EE2_NUH_DoubleCoil +Relay_SMD:Relay_DPDT_Kemet_EE2_NUX_DoubleCoil +Relay_SMD:Relay_DPDT_Kemet_EE2_NUX_NKX +Relay_SMD:Relay_DPDT_Kemet_EE2_NU_DoubleCoil +Relay_SMD:Relay_DPDT_Omron_G6H-2F +Relay_SMD:Relay_DPDT_Omron_G6K-2F-Y +Relay_SMD:Relay_DPDT_Omron_G6K-2F +Relay_SMD:Relay_DPDT_Omron_G6K-2G-Y +Relay_SMD:Relay_DPDT_Omron_G6K-2G +Relay_SMD:Relay_DPDT_Omron_G6S-2F +Relay_SMD:Relay_DPDT_Omron_G6S-2G +Relay_SMD:Relay_DPDT_Omron_G6SK-2F +Relay_SMD:Relay_DPDT_Omron_G6SK-2G +Relay_SMD:Relay_Fujitsu_FTR-B3S +Relay_SMD:Relay_SPDT_AXICOM_HF3Series_50ohms_Pitch1.27mm +Relay_SMD:Relay_SPDT_AXICOM_HF3Series_75ohms_Pitch1.27mm +Relay_THT:Relay_1-Form-A_Schrack-RYII_RM5mm +Relay_THT:Relay_1-Form-B_Schrack-RYII_RM5mm +Relay_THT:Relay_1-Form-C_Schrack-RYII_RM3.2mm +Relay_THT:Relay_3PST_COTO_3650 +Relay_THT:Relay_3PST_COTO_3660 +Relay_THT:Relay_DPDT_AXICOM_IMSeries_Pitch3.2mm +Relay_THT:Relay_DPDT_AXICOM_IMSeries_Pitch5.08mm +Relay_THT:Relay_DPDT_Finder_30.22 +Relay_THT:Relay_DPDT_Finder_40.52 +Relay_THT:Relay_DPDT_Finder_40.62 +Relay_THT:Relay_DPDT_FRT5 +Relay_THT:Relay_DPDT_Fujitsu_FTR-F1C +Relay_THT:Relay_DPDT_Hongfa_HF115F-2Z-x4 +Relay_THT:Relay_DPDT_Kemet_EC2_NJ +Relay_THT:Relay_DPDT_Kemet_EC2_NJ_DoubleCoil +Relay_THT:Relay_DPDT_Kemet_EC2_NU +Relay_THT:Relay_DPDT_Kemet_EC2_NU_DoubleCoil +Relay_THT:Relay_DPDT_Omron_G2RL-2 +Relay_THT:Relay_DPDT_Omron_G5V-2 +Relay_THT:Relay_DPDT_Omron_G6A +Relay_THT:Relay_DPDT_Omron_G6AK +Relay_THT:Relay_DPDT_Omron_G6H-2 +Relay_THT:Relay_DPDT_Omron_G6K-2P-Y +Relay_THT:Relay_DPDT_Omron_G6K-2P +Relay_THT:Relay_DPDT_Omron_G6S-2 +Relay_THT:Relay_DPDT_Omron_G6SK-2 +Relay_THT:Relay_DPDT_Panasonic_JW2 +Relay_THT:Relay_DPDT_Schrack-RT2-FormC-Dual-Coil_RM5mm +Relay_THT:Relay_DPDT_Schrack-RT2-FormC_RM5mm +Relay_THT:Relay_DPST_COTO_3602 +Relay_THT:Relay_DPST_Fujitsu_FTR-F1A +Relay_THT:Relay_DPST_Omron_G2RL-2A +Relay_THT:Relay_DPST_Schrack-RT2-FormA_RM5mm +Relay_THT:Relay_NCR_HHG1D-1 +Relay_THT:Relay_Socket_3PDT_Omron_PLE11-0 +Relay_THT:Relay_Socket_4PDT_Omron_PY14-02 +Relay_THT:Relay_Socket_DPDT_Finder_96.12 +Relay_THT:Relay_Socket_DPDT_Omron_PLE08-0 +Relay_THT:Relay_SPDT_Finder_32.21-x000 +Relay_THT:Relay_SPDT_Finder_34.51_Horizontal +Relay_THT:Relay_SPDT_Finder_34.51_Vertical +Relay_THT:Relay_SPDT_Finder_36.11 +Relay_THT:Relay_SPDT_Finder_40.11 +Relay_THT:Relay_SPDT_Finder_40.31 +Relay_THT:Relay_SPDT_Finder_40.41 +Relay_THT:Relay_SPDT_Finder_40.51 +Relay_THT:Relay_SPDT_Finder_40.61 +Relay_THT:Relay_SPDT_Fujitsu_FTR-LYCA005x_FormC_Vertical +Relay_THT:Relay_SPDT_HJR-4102 +Relay_THT:Relay_SPDT_Hongfa_HF3F-L-xx-1ZL1T +Relay_THT:Relay_SPDT_Hongfa_HF3F-L-xx-1ZL2T-R +Relay_THT:Relay_SPDT_Hongfa_HF3F-L-xx-1ZL2T +Relay_THT:Relay_SPDT_Hongfa_JQC-3FF_0XX-1Z +Relay_THT:Relay_SPDT_HsinDa_Y14 +Relay_THT:Relay_SPDT_Omron-G5LE-1 +Relay_THT:Relay_SPDT_Omron-G5Q-1 +Relay_THT:Relay_SPDT_Omron_G2RL-1-E +Relay_THT:Relay_SPDT_Omron_G2RL-1 +Relay_THT:Relay_SPDT_Omron_G5V-1 +Relay_THT:Relay_SPDT_Omron_G6E +Relay_THT:Relay_SPDT_Omron_G6EK +Relay_THT:Relay_SPDT_Panasonic_DR-L +Relay_THT:Relay_SPDT_Panasonic_DR-L2 +Relay_THT:Relay_SPDT_Panasonic_DR +Relay_THT:Relay_SPDT_Panasonic_JW1_FormC +Relay_THT:Relay_SPDT_PotterBrumfield_T9AP5D52_12V30A +Relay_THT:Relay_SPDT_RAYEX-L90 +Relay_THT:Relay_SPDT_RAYEX-L90S +Relay_THT:Relay_SPDT_SANYOU_SRD_Series_Form_C +Relay_THT:Relay_SPDT_Schrack-RP-II-1-16A-FormC_RM5mm +Relay_THT:Relay_SPDT_Schrack-RP-II-1-FormC_RM3.5mm +Relay_THT:Relay_SPDT_Schrack-RP-II-1-FormC_RM5mm +Relay_THT:Relay_SPDT_Schrack-RT1-16A-FormC_RM5mm +Relay_THT:Relay_SPDT_Schrack-RT1-FormC_RM3.5mm +Relay_THT:Relay_SPDT_Schrack-RT1-FormC_RM5mm +Relay_THT:Relay_SPDT_StandexMeder_SIL_Form1C +Relay_THT:Relay_SPST-NO_Fujitsu_FTR-LYAA005x_FormA_Vertical +Relay_THT:Relay_SPST_Finder_32.21-x300 +Relay_THT:Relay_SPST_Hongfa_HF3F-L-xx-1HL1T +Relay_THT:Relay_SPST_Hongfa_HF3F-L-xx-1HL2T-R +Relay_THT:Relay_SPST_Hongfa_HF3F-L-xx-1HL2T +Relay_THT:Relay_SPST_Hongfa_JQC-3FF_0XX-1H +Relay_THT:Relay_SPST_Omron-G5Q-1A +Relay_THT:Relay_SPST_Omron_G2RL-1A-E +Relay_THT:Relay_SPST_Omron_G2RL-1A +Relay_THT:Relay_SPST_Omron_G5NB +Relay_THT:Relay_SPST_Omron_G5PZ +Relay_THT:Relay_SPST_Panasonic_ADW11 +Relay_THT:Relay_SPST_Panasonic_ALFG_FormA +Relay_THT:Relay_SPST_Panasonic_ALFG_FormA_CircularHoles +Relay_THT:Relay_SPST_Panasonic_JW1_FormA +Relay_THT:Relay_SPST_PotterBrumfield_T9AP1D52_12V30A +Relay_THT:Relay_SPST_RAYEX-L90A +Relay_THT:Relay_SPST_RAYEX-L90AS +Relay_THT:Relay_SPST_RAYEX-L90B +Relay_THT:Relay_SPST_RAYEX-L90BS +Relay_THT:Relay_SPST_SANYOU_SRD_Series_Form_A +Relay_THT:Relay_SPST_SANYOU_SRD_Series_Form_B +Relay_THT:Relay_SPST_Schrack-RP-II-1-16A-FormA_RM5mm +Relay_THT:Relay_SPST_Schrack-RP-II-1-FormA_RM3.5mm +Relay_THT:Relay_SPST_Schrack-RP-II-1-FormA_RM5mm +Relay_THT:Relay_SPST_Schrack-RP3SL-1coil_RM5mm +Relay_THT:Relay_SPST_Schrack-RP3SL_RM5mm +Relay_THT:Relay_SPST_Schrack-RT1-16A-FormA_RM5mm +Relay_THT:Relay_SPST_Schrack-RT1-FormA_RM3.5mm +Relay_THT:Relay_SPST_Schrack-RT1-FormA_RM5mm +Relay_THT:Relay_SPST_StandexMeder_MS_Form1AB +Relay_THT:Relay_SPST_StandexMeder_SIL_Form1A +Relay_THT:Relay_SPST_StandexMeder_SIL_Form1B +Relay_THT:Relay_SPST_TE_PCH-1xxx2M +Relay_THT:Relay_SPST_TE_PCN-1xxD3MHZ +Relay_THT:Relay_SPST_Zettler-AZSR131 +Relay_THT:Relay_StandexMeder_DIP_HighProfile +Relay_THT:Relay_StandexMeder_DIP_LowProfile +Relay_THT:Relay_StandexMeder_UMS +Relay_THT:Relay_Tyco_V23072_Sealed +Resistor_SMD:R_01005_0402Metric +Resistor_SMD:R_01005_0402Metric_Pad0.57x0.30mm_HandSolder +Resistor_SMD:R_0201_0603Metric +Resistor_SMD:R_0201_0603Metric_Pad0.64x0.40mm_HandSolder +Resistor_SMD:R_0402_1005Metric +Resistor_SMD:R_0402_1005Metric_Pad0.72x0.64mm_HandSolder +Resistor_SMD:R_0603_1608Metric +Resistor_SMD:R_0603_1608Metric_Pad0.98x0.95mm_HandSolder +Resistor_SMD:R_0612_1632Metric +Resistor_SMD:R_0612_1632Metric_Pad1.18x3.40mm_HandSolder +Resistor_SMD:R_0805_2012Metric +Resistor_SMD:R_0805_2012Metric_Pad1.20x1.40mm_HandSolder +Resistor_SMD:R_0815_2038Metric +Resistor_SMD:R_0815_2038Metric_Pad1.20x4.05mm_HandSolder +Resistor_SMD:R_1020_2550Metric +Resistor_SMD:R_1020_2550Metric_Pad1.33x5.20mm_HandSolder +Resistor_SMD:R_1206_3216Metric +Resistor_SMD:R_1206_3216Metric_Pad1.30x1.75mm_HandSolder +Resistor_SMD:R_1210_3225Metric +Resistor_SMD:R_1210_3225Metric_Pad1.30x2.65mm_HandSolder +Resistor_SMD:R_1218_3246Metric +Resistor_SMD:R_1218_3246Metric_Pad1.22x4.75mm_HandSolder +Resistor_SMD:R_1812_4532Metric +Resistor_SMD:R_1812_4532Metric_Pad1.30x3.40mm_HandSolder +Resistor_SMD:R_2010_5025Metric +Resistor_SMD:R_2010_5025Metric_Pad1.40x2.65mm_HandSolder +Resistor_SMD:R_2512_6332Metric +Resistor_SMD:R_2512_6332Metric_Pad1.40x3.35mm_HandSolder +Resistor_SMD:R_2816_7142Metric +Resistor_SMD:R_2816_7142Metric_Pad3.20x4.45mm_HandSolder +Resistor_SMD:R_4020_10251Metric +Resistor_SMD:R_4020_10251Metric_Pad1.65x5.30mm_HandSolder +Resistor_SMD:R_Array_Concave_2x0603 +Resistor_SMD:R_Array_Concave_4x0402 +Resistor_SMD:R_Array_Concave_4x0603 +Resistor_SMD:R_Array_Convex_2x0402 +Resistor_SMD:R_Array_Convex_2x0603 +Resistor_SMD:R_Array_Convex_2x0606 +Resistor_SMD:R_Array_Convex_2x1206 +Resistor_SMD:R_Array_Convex_4x0402 +Resistor_SMD:R_Array_Convex_4x0603 +Resistor_SMD:R_Array_Convex_4x0612 +Resistor_SMD:R_Array_Convex_4x1206 +Resistor_SMD:R_Array_Convex_5x0603 +Resistor_SMD:R_Array_Convex_5x1206 +Resistor_SMD:R_Array_Convex_8x0602 +Resistor_SMD:R_Cat16-2 +Resistor_SMD:R_Cat16-4 +Resistor_SMD:R_Cat16-8 +Resistor_SMD:R_MELF_MMB-0207 +Resistor_SMD:R_MicroMELF_MMU-0102 +Resistor_SMD:R_MiniMELF_MMA-0204 +Resistor_SMD:R_Shunt_Isabellenhuette_BVR4026 +Resistor_SMD:R_Shunt_Ohmite_LVK12 +Resistor_SMD:R_Shunt_Ohmite_LVK20 +Resistor_SMD:R_Shunt_Ohmite_LVK24 +Resistor_SMD:R_Shunt_Ohmite_LVK25 +Resistor_SMD:R_Shunt_Vishay_WSK2512_6332Metric_T1.19mm +Resistor_SMD:R_Shunt_Vishay_WSK2512_6332Metric_T2.21mm +Resistor_SMD:R_Shunt_Vishay_WSK2512_6332Metric_T2.66mm +Resistor_SMD:R_Shunt_Vishay_WSKW0612 +Resistor_SMD:R_Shunt_Vishay_WSR2_WSR3 +Resistor_SMD:R_Shunt_Vishay_WSR2_WSR3_KelvinConnection +Resistor_THT:R_Array_SIP10 +Resistor_THT:R_Array_SIP11 +Resistor_THT:R_Array_SIP12 +Resistor_THT:R_Array_SIP13 +Resistor_THT:R_Array_SIP14 +Resistor_THT:R_Array_SIP4 +Resistor_THT:R_Array_SIP5 +Resistor_THT:R_Array_SIP6 +Resistor_THT:R_Array_SIP7 +Resistor_THT:R_Array_SIP8 +Resistor_THT:R_Array_SIP9 +Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P1.90mm_Vertical +Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P2.54mm_Vertical +Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal +Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Vertical +Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P7.62mm_Horizontal +Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal +Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P15.24mm_Horizontal +Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P2.54mm_Vertical +Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P5.08mm_Vertical +Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P7.62mm_Horizontal +Resistor_THT:R_Axial_DIN0309_L9.0mm_D3.2mm_P12.70mm_Horizontal +Resistor_THT:R_Axial_DIN0309_L9.0mm_D3.2mm_P15.24mm_Horizontal +Resistor_THT:R_Axial_DIN0309_L9.0mm_D3.2mm_P2.54mm_Vertical +Resistor_THT:R_Axial_DIN0309_L9.0mm_D3.2mm_P20.32mm_Horizontal +Resistor_THT:R_Axial_DIN0309_L9.0mm_D3.2mm_P25.40mm_Horizontal +Resistor_THT:R_Axial_DIN0309_L9.0mm_D3.2mm_P5.08mm_Vertical +Resistor_THT:R_Axial_DIN0411_L9.9mm_D3.6mm_P12.70mm_Horizontal +Resistor_THT:R_Axial_DIN0411_L9.9mm_D3.6mm_P15.24mm_Horizontal +Resistor_THT:R_Axial_DIN0411_L9.9mm_D3.6mm_P20.32mm_Horizontal +Resistor_THT:R_Axial_DIN0411_L9.9mm_D3.6mm_P25.40mm_Horizontal +Resistor_THT:R_Axial_DIN0411_L9.9mm_D3.6mm_P5.08mm_Vertical +Resistor_THT:R_Axial_DIN0411_L9.9mm_D3.6mm_P7.62mm_Vertical +Resistor_THT:R_Axial_DIN0414_L11.9mm_D4.5mm_P15.24mm_Horizontal +Resistor_THT:R_Axial_DIN0414_L11.9mm_D4.5mm_P20.32mm_Horizontal +Resistor_THT:R_Axial_DIN0414_L11.9mm_D4.5mm_P25.40mm_Horizontal +Resistor_THT:R_Axial_DIN0414_L11.9mm_D4.5mm_P5.08mm_Vertical +Resistor_THT:R_Axial_DIN0414_L11.9mm_D4.5mm_P7.62mm_Vertical +Resistor_THT:R_Axial_DIN0516_L15.5mm_D5.0mm_P20.32mm_Horizontal +Resistor_THT:R_Axial_DIN0516_L15.5mm_D5.0mm_P25.40mm_Horizontal +Resistor_THT:R_Axial_DIN0516_L15.5mm_D5.0mm_P30.48mm_Horizontal +Resistor_THT:R_Axial_DIN0516_L15.5mm_D5.0mm_P5.08mm_Vertical +Resistor_THT:R_Axial_DIN0516_L15.5mm_D5.0mm_P7.62mm_Vertical +Resistor_THT:R_Axial_DIN0614_L14.3mm_D5.7mm_P15.24mm_Horizontal +Resistor_THT:R_Axial_DIN0614_L14.3mm_D5.7mm_P20.32mm_Horizontal +Resistor_THT:R_Axial_DIN0614_L14.3mm_D5.7mm_P25.40mm_Horizontal +Resistor_THT:R_Axial_DIN0614_L14.3mm_D5.7mm_P5.08mm_Vertical +Resistor_THT:R_Axial_DIN0614_L14.3mm_D5.7mm_P7.62mm_Vertical +Resistor_THT:R_Axial_DIN0617_L17.0mm_D6.0mm_P20.32mm_Horizontal +Resistor_THT:R_Axial_DIN0617_L17.0mm_D6.0mm_P25.40mm_Horizontal +Resistor_THT:R_Axial_DIN0617_L17.0mm_D6.0mm_P30.48mm_Horizontal +Resistor_THT:R_Axial_DIN0617_L17.0mm_D6.0mm_P5.08mm_Vertical +Resistor_THT:R_Axial_DIN0617_L17.0mm_D6.0mm_P7.62mm_Vertical +Resistor_THT:R_Axial_DIN0918_L18.0mm_D9.0mm_P22.86mm_Horizontal +Resistor_THT:R_Axial_DIN0918_L18.0mm_D9.0mm_P25.40mm_Horizontal +Resistor_THT:R_Axial_DIN0918_L18.0mm_D9.0mm_P30.48mm_Horizontal +Resistor_THT:R_Axial_DIN0918_L18.0mm_D9.0mm_P7.62mm_Vertical +Resistor_THT:R_Axial_DIN0922_L20.0mm_D9.0mm_P25.40mm_Horizontal +Resistor_THT:R_Axial_DIN0922_L20.0mm_D9.0mm_P30.48mm_Horizontal +Resistor_THT:R_Axial_DIN0922_L20.0mm_D9.0mm_P7.62mm_Vertical +Resistor_THT:R_Axial_Power_L20.0mm_W6.4mm_P22.40mm +Resistor_THT:R_Axial_Power_L20.0mm_W6.4mm_P25.40mm +Resistor_THT:R_Axial_Power_L20.0mm_W6.4mm_P30.48mm +Resistor_THT:R_Axial_Power_L20.0mm_W6.4mm_P5.08mm_Vertical +Resistor_THT:R_Axial_Power_L20.0mm_W6.4mm_P7.62mm_Vertical +Resistor_THT:R_Axial_Power_L25.0mm_W6.4mm_P27.94mm +Resistor_THT:R_Axial_Power_L25.0mm_W6.4mm_P30.48mm +Resistor_THT:R_Axial_Power_L25.0mm_W9.0mm_P10.16mm_Vertical +Resistor_THT:R_Axial_Power_L25.0mm_W9.0mm_P27.94mm +Resistor_THT:R_Axial_Power_L25.0mm_W9.0mm_P30.48mm +Resistor_THT:R_Axial_Power_L25.0mm_W9.0mm_P7.62mm_Vertical +Resistor_THT:R_Axial_Power_L38.0mm_W6.4mm_P40.64mm +Resistor_THT:R_Axial_Power_L38.0mm_W6.4mm_P45.72mm +Resistor_THT:R_Axial_Power_L38.0mm_W9.0mm_P40.64mm +Resistor_THT:R_Axial_Power_L38.0mm_W9.0mm_P45.72mm +Resistor_THT:R_Axial_Power_L48.0mm_W12.5mm_P10.16mm_Vertical +Resistor_THT:R_Axial_Power_L48.0mm_W12.5mm_P55.88mm +Resistor_THT:R_Axial_Power_L48.0mm_W12.5mm_P60.96mm +Resistor_THT:R_Axial_Power_L48.0mm_W12.5mm_P7.62mm_Vertical +Resistor_THT:R_Axial_Power_L50.0mm_W9.0mm_P55.88mm +Resistor_THT:R_Axial_Power_L50.0mm_W9.0mm_P60.96mm +Resistor_THT:R_Axial_Power_L60.0mm_W14.0mm_P10.16mm_Vertical +Resistor_THT:R_Axial_Power_L60.0mm_W14.0mm_P66.04mm +Resistor_THT:R_Axial_Power_L60.0mm_W14.0mm_P71.12mm +Resistor_THT:R_Axial_Power_L75.0mm_W9.0mm_P81.28mm +Resistor_THT:R_Axial_Power_L75.0mm_W9.0mm_P86.36mm +Resistor_THT:R_Axial_Shunt_L22.2mm_W8.0mm_PS14.30mm_P25.40mm +Resistor_THT:R_Axial_Shunt_L22.2mm_W9.5mm_PS14.30mm_P25.40mm +Resistor_THT:R_Axial_Shunt_L35.3mm_W9.5mm_PS25.40mm_P38.10mm +Resistor_THT:R_Axial_Shunt_L47.6mm_W12.7mm_PS34.93mm_P50.80mm +Resistor_THT:R_Axial_Shunt_L47.6mm_W9.5mm_PS34.93mm_P50.80mm +Resistor_THT:R_Bare_Metal_Element_L12.4mm_W4.8mm_P11.40mm +Resistor_THT:R_Bare_Metal_Element_L16.3mm_W4.8mm_P15.30mm +Resistor_THT:R_Bare_Metal_Element_L21.3mm_W4.8mm_P20.30mm +Resistor_THT:R_Box_L13.0mm_W4.0mm_P9.00mm +Resistor_THT:R_Box_L14.0mm_W5.0mm_P9.00mm +Resistor_THT:R_Box_L26.0mm_W5.0mm_P20.00mm +Resistor_THT:R_Box_L8.4mm_W2.5mm_P5.08mm +Resistor_THT:R_Radial_Power_L11.0mm_W7.0mm_P5.00mm +Resistor_THT:R_Radial_Power_L12.0mm_W8.0mm_P5.00mm +Resistor_THT:R_Radial_Power_L13.0mm_W9.0mm_P5.00mm +Resistor_THT:R_Radial_Power_L16.1mm_W9.0mm_P7.37mm +Resistor_THT:R_Radial_Power_L7.0mm_W8.0mm_Px2.40mm_Py2.30mm +Resistor_THT:R_Radial_Power_L9.0mm_W10.0mm_Px2.70mm_Py2.30mm +RF:Skyworks_SKY13575_639LF +RF:Skyworks_SKY65404-31 +RF_Antenna:Abracon_APAES868R8060C16-T +RF_Antenna:Abracon_PRO-OB-440 +RF_Antenna:Abracon_PRO-OB-471 +RF_Antenna:Antenova_SR4G013_GPS +RF_Antenna:Astrocast_AST50127-00 +RF_Antenna:AVX_M620720 +RF_Antenna:Coilcraft_MA5532-AE_RFID +RF_Antenna:Johanson_2450AT18x100 +RF_Antenna:Johanson_2450AT43F0100 +RF_Antenna:Molex_47948-0001_2.4Ghz +RF_Antenna:NiceRF_SW868-TH13_868Mhz +RF_Antenna:Pulse_W3000 +RF_Antenna:Pulse_W3011 +RF_Antenna:Texas_SWRA117D_2.4GHz_Left +RF_Antenna:Texas_SWRA117D_2.4GHz_Right +RF_Antenna:Texas_SWRA416_868MHz_915MHz +RF_Converter:Anaren_0805_2012Metric-6 +RF_Converter:Balun_Johanson_0896BM15A0001 +RF_Converter:Balun_Johanson_0900FM15K0039 +RF_Converter:Balun_Johanson_0900PC15J0013 +RF_Converter:Balun_Johanson_1.6x0.8mm +RF_Converter:Balun_Johanson_5400BL15B050E +RF_Converter:RF_Attenuator_Susumu_PAT1220 +RF_GPS:Linx_RXM-GPS +RF_GPS:OriginGPS_ORG1510 +RF_GPS:Quectel_L70-R +RF_GPS:Quectel_L76 +RF_GPS:Quectel_L80-R +RF_GPS:Quectel_L96 +RF_GPS:Sierra_XA11X0 +RF_GPS:Sierra_XM11X0 +RF_GPS:SIM28ML +RF_GPS:ublox_LEA +RF_GPS:ublox_MAX +RF_GPS:ublox_NEO +RF_GPS:ublox_SAM-M8Q +RF_GPS:ublox_SAM-M8Q_HandSolder +RF_GPS:ublox_ZED +RF_GPS:ublox_ZOE_M8 +RF_GSM:Quectel_BC66 +RF_GSM:Quectel_BC95 +RF_GSM:Quectel_BG95 +RF_GSM:Quectel_BG96 +RF_GSM:Quectel_M95 +RF_GSM:SIMCom_SIM800C +RF_GSM:SIMCom_SIM900 +RF_GSM:Telit_SE150A4 +RF_GSM:Telit_xL865 +RF_GSM:ublox_LENA-R8_LGA-100 +RF_GSM:ublox_SARA_LGA-96 +RF_Mini-Circuits:Mini-Circuits_BK377 +RF_Mini-Circuits:Mini-Circuits_BK377_LandPatternPL-005 +RF_Mini-Circuits:Mini-Circuits_CD541_H2.08mm +RF_Mini-Circuits:Mini-Circuits_CD542_H2.84mm +RF_Mini-Circuits:Mini-Circuits_CD542_LandPatternPL-052 +RF_Mini-Circuits:Mini-Circuits_CD542_LandPatternPL-094 +RF_Mini-Circuits:Mini-Circuits_CD636_H4.11mm +RF_Mini-Circuits:Mini-Circuits_CD636_LandPatternPL-035 +RF_Mini-Circuits:Mini-Circuits_CD637_H5.23mm +RF_Mini-Circuits:Mini-Circuits_CK605 +RF_Mini-Circuits:Mini-Circuits_CK605_LandPatternPL-012 +RF_Mini-Circuits:Mini-Circuits_DB1627 +RF_Mini-Circuits:Mini-Circuits_GP1212 +RF_Mini-Circuits:Mini-Circuits_GP1212_LandPatternPL-176 +RF_Mini-Circuits:Mini-Circuits_GP731 +RF_Mini-Circuits:Mini-Circuits_GP731_LandPatternPL-176 +RF_Mini-Circuits:Mini-Circuits_HF1139 +RF_Mini-Circuits:Mini-Circuits_HF1139_LandPatternPL-230 +RF_Mini-Circuits:Mini-Circuits_HQ1157 +RF_Mini-Circuits:Mini-Circuits_HZ1198 +RF_Mini-Circuits:Mini-Circuits_HZ1198_LandPatternPL-247 +RF_Mini-Circuits:Mini-Circuits_MMM168 +RF_Mini-Circuits:Mini-Circuits_MMM168_LandPatternPL-225 +RF_Mini-Circuits:Mini-Circuits_QQQ130_ClockwisePinNumbering +RF_Mini-Circuits:Mini-Circuits_QQQ130_LandPattern_PL-236_ClockwisePinNumbering +RF_Mini-Circuits:Mini-Circuits_TT1224_ClockwisePinNumbering +RF_Mini-Circuits:Mini-Circuits_TT1224_LandPatternPL-258_ClockwisePinNumbering +RF_Mini-Circuits:Mini-Circuits_TTT167 +RF_Mini-Circuits:Mini-Circuits_TTT167_LandPatternPL-079 +RF_Mini-Circuits:Mini-Circuits_YY161 +RF_Mini-Circuits:Mini-Circuits_YY161_LandPatternPL-049 +RF_Module:Ai-Thinker-Ra-01-LoRa +RF_Module:Astrocast_AST50147-00 +RF_Module:Atmel_ATSAMR21G18-MR210UA_NoRFPads +RF_Module:BLE112-A +RF_Module:BM78SPPS5xC2 +RF_Module:CMWX1ZZABZ +RF_Module:CYBLE-21Pin-10x10mm +RF_Module:DecaWave_DWM1001 +RF_Module:Digi_XBee_SMT +RF_Module:DWM1000 +RF_Module:E18-MS1-PCB +RF_Module:E73-2G4M04S +RF_Module:ESP-01 +RF_Module:ESP-07 +RF_Module:ESP-12E +RF_Module:ESP-WROOM-02 +RF_Module:ESP32-C3-DevKitM-1 +RF_Module:ESP32-C3-WROOM-02 +RF_Module:ESP32-C3-WROOM-02U +RF_Module:ESP32-C6-MINI-1 +RF_Module:ESP32-S2-MINI-1 +RF_Module:ESP32-S2-MINI-1U +RF_Module:ESP32-S2-WROVER +RF_Module:ESP32-S3-WROOM-1 +RF_Module:ESP32-S3-WROOM-1U +RF_Module:ESP32-S3-WROOM-2 +RF_Module:ESP32-WROOM-32 +RF_Module:ESP32-WROOM-32D +RF_Module:ESP32-WROOM-32E +RF_Module:ESP32-WROOM-32U +RF_Module:ESP32-WROOM-32UE +RF_Module:Garmin_M8-35_9.8x14.0mm_Layout6x6_P1.5mm +RF_Module:Heltec_HT-CT62 +RF_Module:HOPERF_RFM69HW +RF_Module:HOPERF_RFM9XW_SMD +RF_Module:HOPERF_RFM9XW_THT +RF_Module:IQRF_TRx2DA_KON-SIM-01 +RF_Module:IQRF_TRx2D_KON-SIM-01 +RF_Module:Jadak_Thingmagic_M6e-Nano +RF_Module:Laird_BL652 +RF_Module:MCU_Seeed_ESP32C3 +RF_Module:Microchip_BM83 +RF_Module:Microchip_RN4871 +RF_Module:MOD-nRF8001 +RF_Module:Modtronix_inAir9 +RF_Module:MonoWireless_TWE-L-WX +RF_Module:NINA-B111 +RF_Module:nRF24L01_Breakout +RF_Module:Particle_P1 +RF_Module:RAK3172 +RF_Module:RAK4200 +RF_Module:RAK811 +RF_Module:Raytac_MDBT42Q +RF_Module:Raytac_MDBT50Q +RF_Module:RFDigital_RFD77101 +RF_Module:RN2483 +RF_Module:RN42 +RF_Module:RN42N +RF_Module:ST-SiP-LGA-86-11x7.3mm +RF_Module:ST_SPBTLE +RF_Module:Taiyo-Yuden_EYSGJNZWY +RF_Module:TD1205 +RF_Module:TD1208 +RF_Module:WEMOS_C3_mini +RF_Module:WEMOS_D1_mini_light +RF_Module:ZETA-433-SO_SMD +RF_Module:ZETA-433-SO_THT +RF_Shielding:Laird_Technologies_97-2002_25.40x25.40mm +RF_Shielding:Laird_Technologies_97-2003_12.70x13.37mm +RF_Shielding:Laird_Technologies_BMI-S-101_13.66x12.70mm +RF_Shielding:Laird_Technologies_BMI-S-102_16.50x16.50mm +RF_Shielding:Laird_Technologies_BMI-S-103_26.21x26.21mm +RF_Shielding:Laird_Technologies_BMI-S-104_32.00x32.00mm +RF_Shielding:Laird_Technologies_BMI-S-105_38.10x25.40mm +RF_Shielding:Laird_Technologies_BMI-S-106_36.83x33.68mm +RF_Shielding:Laird_Technologies_BMI-S-107_44.37x44.37mm +RF_Shielding:Laird_Technologies_BMI-S-201-F_13.66x12.70mm +RF_Shielding:Laird_Technologies_BMI-S-202-F_16.50x16.50mm +RF_Shielding:Laird_Technologies_BMI-S-203-F_26.21x26.21mm +RF_Shielding:Laird_Technologies_BMI-S-204-F_32.00x32.00mm +RF_Shielding:Laird_Technologies_BMI-S-205-F_38.10x25.40mm +RF_Shielding:Laird_Technologies_BMI-S-206-F_36.83x33.68mm +RF_Shielding:Laird_Technologies_BMI-S-207-F_44.37x44.37mm +RF_Shielding:Laird_Technologies_BMI-S-208-F_39.60x39.60mm +RF_Shielding:Laird_Technologies_BMI-S-209-F_29.36x18.50mm +RF_Shielding:Laird_Technologies_BMI-S-210-F_44.00x30.50mm +RF_Shielding:Laird_Technologies_BMI-S-230-F_50.8x38.1mm +RF_Shielding:Wuerth_36103205_20x20mm +RF_Shielding:Wuerth_36103255_25x25mm +RF_Shielding:Wuerth_36103305_30x30mm +RF_Shielding:Wuerth_36103505_50x50mm +RF_Shielding:Wuerth_36103605_60x60mm +RF_Shielding:Wuerth_36503205_20x20mm +RF_Shielding:Wuerth_36503255_25x25mm +RF_Shielding:Wuerth_36503305_30x30mm +RF_Shielding:Wuerth_36503505_50x50mm +RF_Shielding:Wuerth_36503605_60x60mm +RF_WiFi:USR-C322 +Rotary_Encoder:RotaryEncoder_Alps_EC11E-Switch_Vertical_H20mm +Rotary_Encoder:RotaryEncoder_Alps_EC11E-Switch_Vertical_H20mm_CircularMountingHoles +Rotary_Encoder:RotaryEncoder_Alps_EC11E-Switch_Vertical_H20mm_MountingHoles +Rotary_Encoder:RotaryEncoder_Alps_EC11E_Vertical_H20mm +Rotary_Encoder:RotaryEncoder_Alps_EC11E_Vertical_H20mm_CircularMountingHoles +Rotary_Encoder:RotaryEncoder_Alps_EC12E-Switch_Vertical_H20mm +Rotary_Encoder:RotaryEncoder_Alps_EC12E-Switch_Vertical_H20mm_CircularMountingHoles +Rotary_Encoder:RotaryEncoder_Alps_EC12E_Vertical_H20mm +Rotary_Encoder:RotaryEncoder_Alps_EC12E_Vertical_H20mm_CircularMountingHoles +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEC09-2xxxF-Nxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEC09-2xxxF-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEC12R-2x17F-Nxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEC12R-2x17F-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEL12D-2x16F-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEL12D-2x18F-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEL12D-2x21F-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEL12D-2x25S-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEL12D-2x26F-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Horizontal_PEL12D-2x31F-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Vertical_PEC12R-3x17F-Nxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Vertical_PEC12R-3x17F-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Vertical_PEL12D-4x25S-Sxxxx +Rotary_Encoder:RotaryEncoder_Bourns_Vertical_PEL12D-4xxxF-Sxxxx +Sensor:Aosong_DHT11_5.5x12.0_P2.54mm +Sensor:ASAIR_AM2302_P2.54mm_Lead2.75mm_TabDown +Sensor:ASAIR_AM2302_P2.54mm_Vertical +Sensor:Avago_APDS-9960 +Sensor:LuminOX_LOX-O2 +Sensor:MQ-6 +Sensor:Rohm_RPR-0521RS +Sensor:Senseair_S8_Down +Sensor:Senseair_S8_Up +Sensor:Sensirion_SCD4x-1EP_10.1x10.1mm_P1.25mm_EP4.8x4.8mm +Sensor:Sensortech_MiCS_5x7mm_P1.25mm +Sensor:SHT1x +Sensor:SPEC_110-xxx_SMD-10Pin_20x20mm_P4.0mm +Sensor:TGS-5141 +Sensor:Winson_GM-402B_5x5mm_P1.27mm +Sensor_Audio:CUI_CMC-4013-SMT +Sensor_Audio:Infineon_PG-LLGA-5-1 +Sensor_Audio:Infineon_PG-LLGA-5-2 +Sensor_Audio:InvenSense_ICS-43434-6_3.5x2.65mm +Sensor_Audio:Knowles_LGA-5_3.5x2.65mm +Sensor_Audio:Knowles_LGA-6_4.72x3.76mm +Sensor_Audio:Knowles_SPH0645LM4H-6_3.5x2.65mm +Sensor_Audio:POM-2244P-C3310-2-R +Sensor_Audio:ST_HLGA-6_3.76x4.72mm_P1.65mm +Sensor_Current:AKM_CQ_7 +Sensor_Current:AKM_CQ_7S +Sensor_Current:AKM_CQ_VSOP-24_5.6x7.9mm_P0.65mm +Sensor_Current:AKM_CZ_SSOP-10_6.5x8.1mm_P0.95mm +Sensor_Current:Allegro_CB_PFF +Sensor_Current:Allegro_CB_PSF +Sensor_Current:Allegro_CB_PSS +Sensor_Current:Allegro_PSOF-7_4.8x6.4mm_P1.60mm +Sensor_Current:Allegro_QFN-12-10-1EP_3x3mm_P0.5mm +Sensor_Current:Allegro_QSOP-24_3.9x8.7mm_P0.635mm +Sensor_Current:Allegro_SIP-3 +Sensor_Current:Allegro_SIP-4 +Sensor_Current:Diodes_SIP-3_4.1x1.5mm_P1.27mm +Sensor_Current:Diodes_SIP-3_4.1x1.5mm_P2.65mm +Sensor_Current:Honeywell_CSLW +Sensor_Current:LEM_CKSR +Sensor_Current:LEM_HO40-NP +Sensor_Current:LEM_HO8-NP +Sensor_Current:LEM_HO8-NSM +Sensor_Current:LEM_HTFS +Sensor_Current:LEM_HX02-P +Sensor_Current:LEM_HX03-P-SP2 +Sensor_Current:LEM_HX04-P +Sensor_Current:LEM_HX05-NP +Sensor_Current:LEM_HX05-P-SP2 +Sensor_Current:LEM_HX06-P +Sensor_Current:LEM_HX10-NP +Sensor_Current:LEM_HX10-P-SP2 +Sensor_Current:LEM_HX15-NP +Sensor_Current:LEM_HX15-P-SP2 +Sensor_Current:LEM_HX20-P-SP2 +Sensor_Current:LEM_HX25-P-SP2 +Sensor_Current:LEM_HX50-P-SP2 +Sensor_Current:LEM_LA25-NP +Sensor_Current:LEM_LA25-P +Sensor_Current:LEM_LTSR-NP +Sensor_Distance:AMS_OLGA12 +Sensor_Distance:ST_VL53L1x +Sensor_Humidity:Sensirion_DFN-4-1EP_2x2mm_P1mm_EP0.7x1.6mm +Sensor_Humidity:Sensirion_DFN-4_1.5x1.5mm_P0.8mm_SHT4x_NoCentralPad +Sensor_Humidity:Sensirion_DFN-8-1EP_2.5x2.5mm_P0.5mm_EP1.1x1.7mm +Sensor_Motion:Analog_LGA-16_3.25x3mm_P0.5mm_LayoutBorder3x5y +Sensor_Motion:InvenSense_QFN-24_3x3mm_P0.4mm +Sensor_Motion:InvenSense_QFN-24_3x3mm_P0.4mm_NoMask +Sensor_Motion:InvenSense_QFN-24_4x4mm_P0.5mm +Sensor_Motion:InvenSense_QFN-24_4x4mm_P0.5mm_NoMask +Sensor_Pressure:CFSensor_XGZP6859D_7x7mm +Sensor_Pressure:CFSensor_XGZP6897x +Sensor_Pressure:CFSensor_XGZP6899x +Sensor_Pressure:Freescale_98ARH99066A +Sensor_Pressure:Freescale_98ARH99089A +Sensor_Pressure:Honeywell_40PCxxxG1A +Sensor_Pressure:TE_MS5525DSO-DBxxxyS +Sensor_Pressure:TE_MS5837-xxBA +Sensor_Voltage:LEM_LV25-P +Socket:3M_Textool_240-1288-00-0602J_2x20_P2.54mm +Socket:DIP_Socket-14_W4.3_W5.08_W7.62_W10.16_W10.9_3M_214-3339-00-0602J +Socket:DIP_Socket-16_W4.3_W5.08_W7.62_W10.16_W10.9_3M_216-3340-00-0602J +Socket:DIP_Socket-18_W4.3_W5.08_W7.62_W10.16_W10.9_3M_218-3341-00-0602J +Socket:DIP_Socket-20_W4.3_W5.08_W7.62_W10.16_W10.9_3M_220-3342-00-0602J +Socket:DIP_Socket-22_W6.9_W7.62_W10.16_W12.7_W13.5_3M_222-3343-00-0602J +Socket:DIP_Socket-24_W11.9_W12.7_W15.24_W17.78_W18.5_3M_224-1275-00-0602J +Socket:DIP_Socket-24_W4.3_W5.08_W7.62_W10.16_W10.9_3M_224-5248-00-0602J +Socket:DIP_Socket-28_W11.9_W12.7_W15.24_W17.78_W18.5_3M_228-1277-00-0602J +Socket:DIP_Socket-28_W6.9_W7.62_W10.16_W12.7_W13.5_3M_228-4817-00-0602J +Socket:DIP_Socket-32_W11.9_W12.7_W15.24_W17.78_W18.5_3M_232-1285-00-0602J +Socket:DIP_Socket-40_W11.9_W12.7_W15.24_W17.78_W18.5_3M_240-1280-00-0602J +Socket:DIP_Socket-40_W22.1_W22.86_W25.4_W27.94_W28.7_3M_240-3639-00-0602J +Socket:DIP_Socket-42_W11.9_W12.7_W15.24_W17.78_W18.5_3M_242-1281-00-0602J +Socket:Wells_648-0482211SA01 +Symbol:CE-Logo_11.2x8mm_SilkScreen +Symbol:CE-Logo_16.8x12mm_SilkScreen +Symbol:CE-Logo_28x20mm_SilkScreen +Symbol:CE-Logo_42x30mm_SilkScreen +Symbol:CE-Logo_56.1x40mm_SilkScreen +Symbol:CE-Logo_8.5x6mm_SilkScreen +Symbol:EasterEgg_EWG1308-2013_ClassA +Symbol:ESD-Logo_13.2x12mm_SilkScreen +Symbol:ESD-Logo_22x20mm_SilkScreen +Symbol:ESD-Logo_33x30mm_SilkScreen +Symbol:ESD-Logo_44.1x40mm_SilkScreen +Symbol:ESD-Logo_6.6x6mm_SilkScreen +Symbol:ESD-Logo_8.9x8mm_SilkScreen +Symbol:FCC-Logo_14.6x12mm_SilkScreen +Symbol:FCC-Logo_24.2x20mm_SilkScreen +Symbol:FCC-Logo_36.3x30mm_SilkScreen +Symbol:FCC-Logo_48.3x40mm_SilkScreen +Symbol:FCC-Logo_7.3x6mm_SilkScreen +Symbol:FCC-Logo_9.6x8mm_SilkScreen +Symbol:KiCad-Logo2_12mm_Copper +Symbol:KiCad-Logo2_12mm_SilkScreen +Symbol:KiCad-Logo2_20mm_Copper +Symbol:KiCad-Logo2_20mm_SilkScreen +Symbol:KiCad-Logo2_30mm_Copper +Symbol:KiCad-Logo2_30mm_SilkScreen +Symbol:KiCad-Logo2_40mm_Copper +Symbol:KiCad-Logo2_40mm_SilkScreen +Symbol:KiCad-Logo2_5mm_Copper +Symbol:KiCad-Logo2_5mm_SilkScreen +Symbol:KiCad-Logo2_6mm_Copper +Symbol:KiCad-Logo2_6mm_SilkScreen +Symbol:KiCad-Logo2_8mm_Copper +Symbol:KiCad-Logo2_8mm_SilkScreen +Symbol:KiCad-Logo_12mm_Copper +Symbol:KiCad-Logo_12mm_SilkScreen +Symbol:KiCad-Logo_20mm_Copper +Symbol:KiCad-Logo_20mm_SilkScreen +Symbol:KiCad-Logo_30mm_Copper +Symbol:KiCad-Logo_30mm_SilkScreen +Symbol:KiCad-Logo_40mm_Copper +Symbol:KiCad-Logo_40mm_SilkScreen +Symbol:KiCad-Logo_5mm_Copper +Symbol:KiCad-Logo_5mm_SilkScreen +Symbol:KiCad-Logo_6mm_Copper +Symbol:KiCad-Logo_6mm_SilkScreen +Symbol:KiCad-Logo_8mm_Copper +Symbol:KiCad-Logo_8mm_SilkScreen +Symbol:OSHW-Logo2_14.6x12mm_Copper +Symbol:OSHW-Logo2_14.6x12mm_SilkScreen +Symbol:OSHW-Logo2_24.3x20mm_Copper +Symbol:OSHW-Logo2_24.3x20mm_SilkScreen +Symbol:OSHW-Logo2_36.5x30mm_Copper +Symbol:OSHW-Logo2_36.5x30mm_SilkScreen +Symbol:OSHW-Logo2_48.7x40mm_Copper +Symbol:OSHW-Logo2_48.7x40mm_SilkScreen +Symbol:OSHW-Logo2_7.3x6mm_Copper +Symbol:OSHW-Logo2_7.3x6mm_SilkScreen +Symbol:OSHW-Logo2_9.8x8mm_Copper +Symbol:OSHW-Logo2_9.8x8mm_SilkScreen +Symbol:OSHW-Logo_11.4x12mm_Copper +Symbol:OSHW-Logo_11.4x12mm_SilkScreen +Symbol:OSHW-Logo_19x20mm_Copper +Symbol:OSHW-Logo_19x20mm_SilkScreen +Symbol:OSHW-Logo_28.5x30mm_Copper +Symbol:OSHW-Logo_28.5x30mm_SilkScreen +Symbol:OSHW-Logo_38.1x40mm_Copper +Symbol:OSHW-Logo_38.1x40mm_SilkScreen +Symbol:OSHW-Logo_5.7x6mm_Copper +Symbol:OSHW-Logo_5.7x6mm_SilkScreen +Symbol:OSHW-Logo_7.5x8mm_Copper +Symbol:OSHW-Logo_7.5x8mm_SilkScreen +Symbol:OSHW-Symbol_13.4x12mm_Copper +Symbol:OSHW-Symbol_13.4x12mm_SilkScreen +Symbol:OSHW-Symbol_22.3x20mm_Copper +Symbol:OSHW-Symbol_22.3x20mm_SilkScreen +Symbol:OSHW-Symbol_33.5x30mm_Copper +Symbol:OSHW-Symbol_33.5x30mm_SilkScreen +Symbol:OSHW-Symbol_44.5x40mm_Copper +Symbol:OSHW-Symbol_44.5x40mm_SilkScreen +Symbol:OSHW-Symbol_6.7x6mm_Copper +Symbol:OSHW-Symbol_6.7x6mm_SilkScreen +Symbol:OSHW-Symbol_8.9x8mm_Copper +Symbol:OSHW-Symbol_8.9x8mm_SilkScreen +Symbol:Polarity_Center_Negative_12mm_SilkScreen +Symbol:Polarity_Center_Negative_20mm_SilkScreen +Symbol:Polarity_Center_Negative_30mm_SilkScreen +Symbol:Polarity_Center_Negative_40mm_SilkScreen +Symbol:Polarity_Center_Negative_6mm_SilkScreen +Symbol:Polarity_Center_Negative_8mm_SilkScreen +Symbol:Polarity_Center_Positive_12mm_SilkScreen +Symbol:Polarity_Center_Positive_20mm_SilkScreen +Symbol:Polarity_Center_Positive_30mm_SilkScreen +Symbol:Polarity_Center_Positive_40mm_SilkScreen +Symbol:Polarity_Center_Positive_6mm_SilkScreen +Symbol:Polarity_Center_Positive_8mm_SilkScreen +Symbol:RoHS-Logo_12mm_SilkScreen +Symbol:RoHS-Logo_20mm_SilkScreen +Symbol:RoHS-Logo_30mm_SilkScreen +Symbol:RoHS-Logo_40mm_SilkScreen +Symbol:RoHS-Logo_6mm_SilkScreen +Symbol:RoHS-Logo_8mm_SilkScreen +Symbol:Smolhaj_Scale_0.1 +Symbol:Symbol_Attention_Triangle_17x15mm_Copper +Symbol:Symbol_Attention_Triangle_8x7mm_Copper +Symbol:Symbol_Barrel_Polarity +Symbol:Symbol_CC-Attribution_CopperTop_Big +Symbol:Symbol_CC-Attribution_CopperTop_Small +Symbol:Symbol_CC-Noncommercial_CopperTop_Big +Symbol:Symbol_CC-Noncommercial_CopperTop_Small +Symbol:Symbol_CC-PublicDomain_CopperTop_Big +Symbol:Symbol_CC-PublicDomain_CopperTop_Small +Symbol:Symbol_CC-PublicDomain_SilkScreenTop_Big +Symbol:Symbol_CC-ShareAlike_CopperTop_Big +Symbol:Symbol_CC-ShareAlike_CopperTop_Small +Symbol:Symbol_CreativeCommonsPublicDomain_CopperTop_Small +Symbol:Symbol_CreativeCommonsPublicDomain_SilkScreenTop_Small +Symbol:Symbol_CreativeCommons_CopperTop_Type1_Big +Symbol:Symbol_CreativeCommons_CopperTop_Type2_Big +Symbol:Symbol_CreativeCommons_CopperTop_Type2_Small +Symbol:Symbol_CreativeCommons_SilkScreenTop_Type2_Big +Symbol:Symbol_Danger_18x16mm_Copper +Symbol:Symbol_Danger_8x8mm_Copper +Symbol:Symbol_ESD-Logo-Text_CopperTop +Symbol:Symbol_ESD-Logo_CopperTop +Symbol:Symbol_GNU-GPL_CopperTop_Big +Symbol:Symbol_GNU-GPL_CopperTop_Small +Symbol:Symbol_GNU-Logo_CopperTop +Symbol:Symbol_GNU-Logo_SilkscreenTop +Symbol:Symbol_HighVoltage_NoTriangle_2x5mm_Copper +Symbol:Symbol_HighVoltage_NoTriangle_6x15mm_Copper +Symbol:Symbol_HighVoltage_Triangle_17x15mm_Copper +Symbol:Symbol_HighVoltage_Triangle_6x6mm_Copper +Symbol:Symbol_HighVoltage_Triangle_8x7mm_Copper +Symbol:UKCA-Logo_12x12mm_SilkScreen +Symbol:UKCA-Logo_20x20mm_SilkScreen +Symbol:UKCA-Logo_30x30mm_SilkScreen +Symbol:UKCA-Logo_40x40mm_SilkScreen +Symbol:UKCA-Logo_6x6mm_SilkScreen +Symbol:UKCA-Logo_8x8mm_SilkScreen +Symbol:WEEE-Logo_14x20mm_SilkScreen +Symbol:WEEE-Logo_21x30mm_SilkScreen +Symbol:WEEE-Logo_28.1x40mm_SilkScreen +Symbol:WEEE-Logo_4.2x6mm_SilkScreen +Symbol:WEEE-Logo_5.6x8mm_SilkScreen +Symbol:WEEE-Logo_8.4x12mm_SilkScreen +TerminalBlock:TerminalBlock_Altech_AK300-2_P5.00mm +TerminalBlock:TerminalBlock_Altech_AK300-3_P5.00mm +TerminalBlock:TerminalBlock_Altech_AK300-4_P5.00mm +TerminalBlock:TerminalBlock_bornier-2_P5.08mm +TerminalBlock:TerminalBlock_bornier-3_P5.08mm +TerminalBlock:TerminalBlock_bornier-4_P5.08mm +TerminalBlock:TerminalBlock_bornier-5_P5.08mm +TerminalBlock:TerminalBlock_bornier-6_P5.08mm +TerminalBlock:TerminalBlock_bornier-8_P5.08mm +TerminalBlock:TerminalBlock_Degson_DG246-3.81-03P +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-02P_1x02_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-03P_1x03_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-04P_1x04_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-05P_1x05_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-06P_1x06_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-07P_1x07_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-08P_1x08_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-09P_1x09_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-10P_1x10_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-11P_1x11_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-12P_1x12_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-13P_1x13_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-14P_1x14_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-15P_1x15_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-16P_1x16_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-17P_1x17_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-18P_1x18_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-19P_1x19_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-20P_1x20_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-21P_1x21_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-22P_1x22_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-23P_1x23_P5.00mm +TerminalBlock:TerminalBlock_MaiXu_MX126-5.0-24P_1x24_P5.00mm +TerminalBlock:TerminalBlock_Wuerth_691311400102_P7.62mm +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-10P_1x10_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-11P_1x11_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-12P_1x12_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-13P_1x13_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-14P_1x14_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-15P_1x15_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-16P_1x16_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-17P_1x17_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-18P_1x18_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-19P_1x19_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-20P_1x20_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-21P_1x21_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-22P_1x22_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-23P_1x23_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-2P_1x02_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-3P_1x03_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-4P_1x04_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-5P_1x05_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-6P_1x06_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-7P_1x07_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-8P_1x08_P2.54mm_Horizontal +TerminalBlock:TerminalBlock_Xinya_XY308-2.54-9P_1x09_P2.54mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x02_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x02_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x03_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x03_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x04_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x04_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x05_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x05_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x06_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x06_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x07_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x07_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x08_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x08_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x09_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x09_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x10_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x10_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x11_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x11_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x12_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x12_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x13_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x13_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x14_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x14_P3.50mm_Vertical +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x15_P3.50mm_Horizontal +TerminalBlock_4Ucon:TerminalBlock_4Ucon_1x15_P3.50mm_Vertical +TerminalBlock_Altech:Altech_AK100_1x02_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x03_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x04_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x05_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x06_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x07_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x08_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x09_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x10_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x11_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x12_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x13_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x14_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x15_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x16_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x17_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x18_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x19_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x20_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x21_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x22_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x23_P5.00mm +TerminalBlock_Altech:Altech_AK100_1x24_P5.00mm +TerminalBlock_Altech:Altech_AK300_1x02_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x03_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x04_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x05_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x06_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x07_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x08_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x09_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x10_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x11_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x12_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x13_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x14_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x15_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x16_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x17_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x18_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x19_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x20_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x21_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x22_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x23_P5.00mm_45-Degree +TerminalBlock_Altech:Altech_AK300_1x24_P5.00mm_45-Degree +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-02_1x02_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-03_1x03_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-04_1x04_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-05_1x05_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-06_1x06_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-07_1x07_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-08_1x08_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-09_1x09_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-10_1x10_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-11_1x11_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-12_1x12_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-13_1x13_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-14_1x14_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-15_1x15_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-16_1x16_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-17_1x17_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-18_1x18_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-19_1x19_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-20_1x20_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-21_1x21_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-22_1x22_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-23_1x23_P5.08mm_Horizontal +TerminalBlock_CUI:TerminalBlock_CUI_TB007-508-24_1x24_P5.08mm_Horizontal +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-02_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-03_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-04_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-05_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-06_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-07_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-08_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-09_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-10_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-11_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-12_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-13_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-14_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-15_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-16_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-17_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-18_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-19_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-20_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-21_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-22_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-23_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-24_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-25_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-26_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-27_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-28_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-29_P10.00mm +TerminalBlock_Dinkle:TerminalBlock_Dinkle_DT-55-B01X-30_P10.00mm +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_360271_1x01_Horizontal_ScrewM3.0_Boxed +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_360272_1x01_Horizontal_ScrewM2.6 +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_360273_1x01_Horizontal_ScrewM2.6_WireProtection +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_360291_1x01_Horizontal_ScrewM3.0_Boxed +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_360322_1x01_Horizontal_ScrewM3.0_WireProtection +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_360381_1x01_Horizontal_ScrewM3.0 +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_360410_1x01_Horizontal_ScrewM3.0 +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_360425_1x01_Horizontal_ScrewM4.0_Boxed +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type011_RT05502HBWC_1x02_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type011_RT05503HBWC_1x03_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type011_RT05504HBWC_1x04_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type011_RT05505HBWC_1x05_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type011_RT05506HBWC_1x06_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type055_RT01502HDWU_1x02_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type055_RT01503HDWU_1x03_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type055_RT01504HDWU_1x04_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type059_RT06302HBWC_1x02_P3.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type059_RT06303HBWC_1x03_P3.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type059_RT06304HBWC_1x04_P3.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type059_RT06305HBWC_1x05_P3.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type059_RT06306HBWC_1x06_P3.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type067_RT01902HDWC_1x02_P10.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type067_RT01903HDWC_1x03_P10.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type067_RT01904HDWC_1x04_P10.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type067_RT01905HDWC_1x05_P10.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type073_RT02602HBLU_1x02_P5.08mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type073_RT02603HBLU_1x03_P5.08mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type086_RT03402HBLC_1x02_P3.81mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type086_RT03403HBLC_1x03_P3.81mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type086_RT03404HBLC_1x04_P3.81mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type086_RT03405HBLC_1x05_P3.81mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type086_RT03406HBLC_1x06_P3.81mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type094_RT03502HBLU_1x02_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type094_RT03503HBLU_1x03_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type094_RT03504HBLU_1x04_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type094_RT03505HBLU_1x05_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type094_RT03506HBLU_1x06_P5.00mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type101_RT01602HBWC_1x02_P5.08mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type101_RT01603HBWC_1x03_P5.08mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type101_RT01604HBWC_1x04_P5.08mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type101_RT01605HBWC_1x05_P5.08mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type101_RT01606HBWC_1x06_P5.08mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type171_RT13702HBWC_1x02_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type171_RT13703HBWC_1x03_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type171_RT13704HBWC_1x04_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type171_RT13705HBWC_1x05_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type171_RT13706HBWC_1x06_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type175_RT02702HBLC_1x02_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type175_RT02703HBLC_1x03_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type175_RT02704HBLC_1x04_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type175_RT02705HBLC_1x05_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type175_RT02706HBLC_1x06_P7.50mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type205_RT04502UBLC_1x02_P5.00mm_45Degree +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type205_RT04503UBLC_1x03_P5.00mm_45Degree +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type205_RT04504UBLC_1x04_P5.00mm_45Degree +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type205_RT04505UBLC_1x05_P5.00mm_45Degree +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type205_RT04506UBLC_1x06_P5.00mm_45Degree +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type701_RT11L02HGLU_1x02_P6.35mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type701_RT11L03HGLU_1x03_P6.35mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type703_RT10N02HGLU_1x02_P9.52mm_Horizontal +TerminalBlock_MetzConnect:TerminalBlock_MetzConnect_Type703_RT10N03HGLU_1x03_P9.52mm_Horizontal +TerminalBlock_Philmore:TerminalBlock_Philmore_TB132_1x02_P5.00mm_Horizontal +TerminalBlock_Philmore:TerminalBlock_Philmore_TB133_1x03_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-10-5.08_1x10_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-10_1x10_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-11-5.08_1x11_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-11_1x11_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-12-5.08_1x12_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-12_1x12_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-13-5.08_1x13_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-13_1x13_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-14-5.08_1x14_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-14_1x14_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-15-5.08_1x15_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-15_1x15_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-16-5.08_1x16_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-16_1x16_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2-5.08_1x02_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2_1x02_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-3-5.08_1x03_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-3_1x03_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-4-5.08_1x04_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-4_1x04_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-5-5.08_1x05_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-5_1x05_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-6-5.08_1x06_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-6_1x06_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-7-5.08_1x07_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-7_1x07_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-8-5.08_1x08_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-8_1x08_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-9-5.08_1x09_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-9_1x09_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-10-5.08_1x10_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-11-5.08_1x11_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-12-5.08_1x12_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-13-5.08_1x13_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-14-5.08_1x14_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-15-5.08_1x15_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-16-5.08_1x16_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-2-5.08_1x02_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-3-5.08_1x03_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-4-5.08_1x04_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-5-5.08_1x05_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-6-5.08_1x06_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-7-5.08_1x07_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-8-5.08_1x08_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-3-9-5.08_1x09_P5.08mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-10-2.54_1x10_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-11-2.54_1x11_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-12-2.54_1x12_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-2-2.54_1x02_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-3-2.54_1x03_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-4-2.54_1x04_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-5-2.54_1x05_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-6-2.54_1x06_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-7-2.54_1x07_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-8-2.54_1x08_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-9-2.54_1x09_P2.54mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-10-3.5-H_1x10_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-10-5.0-H_1x10_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-11-3.5-H_1x11_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-11-5.0-H_1x11_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-12-3.5-H_1x12_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-12-5.0-H_1x12_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-13-3.5-H_1x13_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-13-5.0-H_1x13_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-14-3.5-H_1x14_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-14-5.0-H_1x14_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-15-3.5-H_1x15_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-15-5.0-H_1x15_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-16-3.5-H_1x16_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-16-5.0-H_1x16_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-2-3.5-H_1x02_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-2-5.0-H_1x02_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-3-3.5-H_1x03_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-3-5.0-H_1x03_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-4-3.5-H_1x04_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-4-5.0-H_1x04_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-5-3.5-H_1x05_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-5-5.0-H_1x05_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-6-3.5-H_1x06_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-6-5.0-H_1x06_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-7-3.5-H_1x07_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-7-5.0-H_1x07_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-8-3.5-H_1x08_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-8-5.0-H_1x08_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-9-3.5-H_1x09_P3.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PT-1,5-9-5.0-H_1x09_P5.00mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-2-2,5-V-SMD_1x02-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-2-2.5-H-THR_1x02_P2.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-2-2.5-V-THR_1x02_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-2-HV-2.5-SMD_1x02-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-3-2,5-V-SMD_1x03-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-3-2.5-H-THR_1x03_P2.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-3-2.5-V-THR_1x03_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-3-HV-2.5-SMD_1x03-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-4-2,5-V-SMD_1x04-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-4-2.5-H-THR_1x04_P2.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-4-2.5-V-THR_1x04_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-4-HV-2.5-SMD_1x04-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-5-2,5-V-SMD_1x05-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-5-2.5-H-THR_1x05_P2.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-5-2.5-V-THR_1x05_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-5-HV-2.5-SMD_1x05-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-6-2,5-V-SMD_1x06-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-6-2.5-H-THR_1x06_P2.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-6-2.5-V-THR_1x06_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-6-HV-2.5-SMD_1x06-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-7-2,5-V-SMD_1x07-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-7-2.5-H-THR_1x07_P2.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-7-2.5-V-THR_1x07_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-7-HV-2.5-SMD_1x07-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-8-2,5-V-SMD_1x08-1MP_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-8-2.5-H-THR_1x08_P2.50mm_Horizontal +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-8-2.5-V-THR_1x08_P2.50mm_Vertical +TerminalBlock_Phoenix:TerminalBlock_Phoenix_PTSM-0,5-8-HV-2.5-SMD_1x08-1MP_P2.50mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00001_1x02_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00002_1x03_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00003_1x04_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00004_1x05_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00005_1x06_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00006_1x07_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00007_1x08_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00008_1x09_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00009_1x10_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00010_1x11_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00011_1x12_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00012_1x02_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00013_1x03_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00014_1x04_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00015_1x05_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00016_1x06_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00017_1x07_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00018_1x08_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00019_1x09_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00020_1x10_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00021_1x11_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00022_1x12_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00023_1x02_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00024_1x03_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00025_1x04_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00026_1x05_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00027_1x06_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00028_1x07_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00029_1x08_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00030_1x09_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00031_1x10_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00032_1x11_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00033_1x12_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00045_1x02_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00046_1x03_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00047_1x04_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00048_1x05_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00049_1x06_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00050_1x07_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00051_1x08_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00052_1x09_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00053_1x10_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00054_1x11_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00055_1x12_P5.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00056_1x02_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00057_1x03_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00058_1x04_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00059_1x05_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00060_1x06_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00061_1x07_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00062_1x08_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00063_1x09_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00064_1x10_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00065_1x11_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00066_1x12_P5.00mm_45Degree +TerminalBlock_RND:TerminalBlock_RND_205-00067_1x02_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00068_1x03_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00069_1x04_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00070_1x05_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00071_1x06_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00072_1x07_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00073_1x08_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00074_1x09_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00075_1x10_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00076_1x11_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00077_1x12_P7.50mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00078_1x02_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00079_1x03_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00080_1x04_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00081_1x05_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00082_1x06_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00083_1x07_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00084_1x08_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00085_1x09_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00086_1x10_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00087_1x11_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00088_1x12_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00232_1x02_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00233_1x03_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00234_1x04_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00235_1x05_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00236_1x06_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00237_1x07_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00238_1x08_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00239_1x09_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00240_1x10_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00241_1x02_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00241_1x11_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00242_1x03_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00242_1x12_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00243_1x04_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00244_1x05_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00245_1x06_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00246_1x07_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00247_1x08_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00248_1x09_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00249_1x10_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00250_1x11_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00251_1x12_P10.16mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00276_1x02_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00277_1x03_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00278_1x04_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00279_1x05_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00280_1x06_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00281_1x07_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00282_1x08_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00283_1x09_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00284_1x10_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00285_1x11_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00286_1x12_P5.00mm_Vertical +TerminalBlock_RND:TerminalBlock_RND_205-00287_1x02_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00288_1x03_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00289_1x04_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00290_1x05_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00291_1x06_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00292_1x07_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00293_1x08_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00294_1x09_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00295_1x10_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00296_1x11_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00297_1x12_P5.08mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00298_1x02_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00299_1x03_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00300_1x04_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00301_1x05_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00302_1x06_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00303_1x07_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00304_1x08_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00305_1x09_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00306_1x10_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00307_1x11_P10.00mm_Horizontal +TerminalBlock_RND:TerminalBlock_RND_205-00308_1x12_P10.00mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_1-282834-0_1x10_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_1-282834-1_1x11_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_1-282834-2_1x12_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_282834-2_1x02_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_282834-3_1x03_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_282834-4_1x04_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_282834-5_1x05_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_282834-6_1x06_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_282834-7_1x07_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_282834-8_1x08_P2.54mm_Horizontal +TerminalBlock_TE-Connectivity:TerminalBlock_TE_282834-9_1x09_P2.54mm_Horizontal +TerminalBlock_WAGO:TerminalBlock_WAGO_233-502_2x02_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_233-503_2x03_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_233-504_2x04_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_233-505_2x05_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_233-506_2x06_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_233-507_2x07_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_233-508_2x08_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_233-509_2x09_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_233-510_2x10_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_233-512_2x12_P2.54mm +TerminalBlock_WAGO:TerminalBlock_WAGO_236-101_1x01_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-102_1x02_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-103_1x03_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-104_1x04_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-105_1x05_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-106_1x06_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-107_1x07_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-108_1x08_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-109_1x09_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-110_1x10_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-111_1x11_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-112_1x12_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-113_1x13_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-114_1x14_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-115_1x15_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-116_1x16_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-124_1x24_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-136_1x36_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-148_1x48_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-201_1x01_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-202_1x02_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-203_1x03_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-204_1x04_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-205_1x05_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-206_1x06_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-207_1x07_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-208_1x08_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-209_1x09_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-210_1x10_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-211_1x11_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-212_1x12_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-213_1x13_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-214_1x14_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-215_1x15_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-216_1x16_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-224_1x24_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-301_1x01_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-302_1x02_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-303_1x03_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-304_1x04_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-305_1x05_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-306_1x06_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-307_1x07_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-308_1x08_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-309_1x09_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-310_1x10_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-311_1x11_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-312_1x12_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-313_1x13_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-314_1x14_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-315_1x15_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-316_1x16_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-324_1x24_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-401_1x01_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-402_1x02_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-403_1x03_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-404_1x04_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-405_1x05_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-406_1x06_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-407_1x07_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-408_1x08_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-409_1x09_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-410_1x10_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-411_1x11_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-412_1x12_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-413_1x13_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-414_1x14_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-415_1x15_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-416_1x16_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-424_1x24_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-436_1x36_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-448_1x48_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-501_1x01_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-502_1x02_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-503_1x03_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-504_1x04_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-505_1x05_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-506_1x06_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-507_1x07_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-508_1x08_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-509_1x09_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-510_1x10_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-511_1x11_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-512_1x12_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-513_1x13_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-514_1x14_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-515_1x15_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-516_1x16_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-524_1x24_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-601_1x01_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-602_1x02_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-603_1x03_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-604_1x04_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-605_1x05_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-606_1x06_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-607_1x07_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-608_1x08_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-609_1x09_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-610_1x10_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-611_1x11_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-612_1x12_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-613_1x13_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-614_1x14_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-615_1x15_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-616_1x16_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_236-624_1x24_P10.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-101_1x01_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-102_1x02_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-103_1x03_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-104_1x04_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-105_1x05_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-106_1x06_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-107_1x07_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-108_1x08_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-109_1x09_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-110_1x10_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-111_1x11_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-112_1x12_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-113_1x13_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-114_1x14_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-115_1x15_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-116_1x16_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-124_1x24_P5.00mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-301_1x01_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-302_1x02_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-303_1x03_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-304_1x04_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-305_1x05_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-306_1x06_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-307_1x07_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-308_1x08_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-309_1x09_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-310_1x10_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-311_1x11_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-312_1x12_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-316_1x16_P7.50mm_45Degree +TerminalBlock_WAGO:TerminalBlock_WAGO_804-324_1x24_P7.50mm_45Degree +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRBU_74650073_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRBU_74650074_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRBU_74650094_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRBU_74650173_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRBU_74650174_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRBU_74650194_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRBU_74650195_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRBU_74655095_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRSH_74651173_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRSH_74651174_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRSH_74651175_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRSH_74651194_THR +TerminalBlock_Wuerth:Wuerth_REDCUBE-THR_WP-THRSH_74651195_THR +TestPoint:TestPoint_2Pads_Pitch2.54mm_Drill0.8mm +TestPoint:TestPoint_2Pads_Pitch5.08mm_Drill1.3mm +TestPoint:TestPoint_Bridge_Pitch2.0mm_Drill0.7mm +TestPoint:TestPoint_Bridge_Pitch2.54mm_Drill0.7mm +TestPoint:TestPoint_Bridge_Pitch2.54mm_Drill1.0mm +TestPoint:TestPoint_Bridge_Pitch2.54mm_Drill1.3mm +TestPoint:TestPoint_Bridge_Pitch3.81mm_Drill1.3mm +TestPoint:TestPoint_Bridge_Pitch5.08mm_Drill0.7mm +TestPoint:TestPoint_Bridge_Pitch5.08mm_Drill1.3mm +TestPoint:TestPoint_Bridge_Pitch6.35mm_Drill1.3mm +TestPoint:TestPoint_Bridge_Pitch7.62mm_Drill1.3mm +TestPoint:TestPoint_Keystone_5000-5004_Miniature +TestPoint:TestPoint_Keystone_5005-5009_Compact +TestPoint:TestPoint_Keystone_5010-5014_Multipurpose +TestPoint:TestPoint_Keystone_5015_Micro_Mini +TestPoint:TestPoint_Keystone_5019_Miniature +TestPoint:TestPoint_Loop_D1.80mm_Drill1.0mm_Beaded +TestPoint:TestPoint_Loop_D2.50mm_Drill1.0mm +TestPoint:TestPoint_Loop_D2.50mm_Drill1.0mm_LowProfile +TestPoint:TestPoint_Loop_D2.50mm_Drill1.85mm +TestPoint:TestPoint_Loop_D2.54mm_Drill1.5mm_Beaded +TestPoint:TestPoint_Loop_D2.60mm_Drill0.9mm_Beaded +TestPoint:TestPoint_Loop_D2.60mm_Drill1.4mm_Beaded +TestPoint:TestPoint_Loop_D2.60mm_Drill1.6mm_Beaded +TestPoint:TestPoint_Loop_D3.50mm_Drill0.9mm_Beaded +TestPoint:TestPoint_Loop_D3.50mm_Drill1.4mm_Beaded +TestPoint:TestPoint_Loop_D3.80mm_Drill2.0mm +TestPoint:TestPoint_Loop_D3.80mm_Drill2.5mm +TestPoint:TestPoint_Loop_D3.80mm_Drill2.8mm +TestPoint:TestPoint_Pad_1.0x1.0mm +TestPoint:TestPoint_Pad_1.5x1.5mm +TestPoint:TestPoint_Pad_2.0x2.0mm +TestPoint:TestPoint_Pad_2.5x2.5mm +TestPoint:TestPoint_Pad_3.0x3.0mm +TestPoint:TestPoint_Pad_4.0x4.0mm +TestPoint:TestPoint_Pad_D1.0mm +TestPoint:TestPoint_Pad_D1.5mm +TestPoint:TestPoint_Pad_D2.0mm +TestPoint:TestPoint_Pad_D2.5mm +TestPoint:TestPoint_Pad_D3.0mm +TestPoint:TestPoint_Pad_D4.0mm +TestPoint:TestPoint_Plated_Hole_D2.0mm +TestPoint:TestPoint_Plated_Hole_D3.0mm +TestPoint:TestPoint_Plated_Hole_D4.0mm +TestPoint:TestPoint_Plated_Hole_D5.0mm +TestPoint:TestPoint_THTPad_1.0x1.0mm_Drill0.5mm +TestPoint:TestPoint_THTPad_1.5x1.5mm_Drill0.7mm +TestPoint:TestPoint_THTPad_2.0x2.0mm_Drill1.0mm +TestPoint:TestPoint_THTPad_2.5x2.5mm_Drill1.2mm +TestPoint:TestPoint_THTPad_3.0x3.0mm_Drill1.5mm +TestPoint:TestPoint_THTPad_4.0x4.0mm_Drill2.0mm +TestPoint:TestPoint_THTPad_D1.0mm_Drill0.5mm +TestPoint:TestPoint_THTPad_D1.5mm_Drill0.7mm +TestPoint:TestPoint_THTPad_D2.0mm_Drill1.0mm +TestPoint:TestPoint_THTPad_D2.5mm_Drill1.2mm +TestPoint:TestPoint_THTPad_D3.0mm_Drill1.5mm +TestPoint:TestPoint_THTPad_D4.0mm_Drill2.0mm +Transformer_SMD:Pulse_P0926NL +Transformer_SMD:Pulse_PA1323NL +Transformer_SMD:Pulse_PA2001NL +Transformer_SMD:Pulse_PA2002NL-PA2008NL-PA2009NL +Transformer_SMD:Pulse_PA2004NL +Transformer_SMD:Pulse_PA2005NL +Transformer_SMD:Pulse_PA2006NL +Transformer_SMD:Pulse_PA2007NL +Transformer_SMD:Pulse_PA2777NL +Transformer_SMD:Pulse_PA3493NL +Transformer_SMD:Transformer_Coilcraft_CST1 +Transformer_SMD:Transformer_Coilcraft_CST2 +Transformer_SMD:Transformer_Coilcraft_CST2010 +Transformer_SMD:Transformer_CurrentSense_8.4x7.2mm +Transformer_SMD:Transformer_ED8_4-Lead_10.5x8mm_P5mm +Transformer_SMD:Transformer_Ethernet_Bel_S558-5999-T7-F +Transformer_SMD:Transformer_Ethernet_Bourns_PT61017PEL +Transformer_SMD:Transformer_Ethernet_Bourns_PT61020EL +Transformer_SMD:Transformer_Ethernet_Halo_N2_SO-16_7.11x12.7mm +Transformer_SMD:Transformer_Ethernet_Halo_N5_SO-16_7.11x12.7mm +Transformer_SMD:Transformer_Ethernet_Halo_N6_SO-16_7.11x14.73mm +Transformer_SMD:Transformer_Ethernet_HALO_TG111-MSC13 +Transformer_SMD:Transformer_Ethernet_Wuerth_749013011A +Transformer_SMD:Transformer_Ethernet_YDS_30F-51NL_SO-24_7.1x15.1mm +Transformer_SMD:Transformer_MACOM_SM-22 +Transformer_SMD:Transformer_MiniCircuits_AT224-1A +Transformer_SMD:Transformer_Murata_78250JC +Transformer_SMD:Transformer_NF_ETAL_P2781 +Transformer_SMD:Transformer_NF_ETAL_P2781_HandSoldering +Transformer_SMD:Transformer_NF_ETAL_P3000 +Transformer_SMD:Transformer_NF_ETAL_P3000_HandSoldering +Transformer_SMD:Transformer_NF_ETAL_P3181 +Transformer_SMD:Transformer_NF_ETAL_P3181_HandSoldering +Transformer_SMD:Transformer_NF_ETAL_P3188 +Transformer_SMD:Transformer_NF_ETAL_P3188_HandSoldering +Transformer_SMD:Transformer_NF_ETAL_P3191 +Transformer_SMD:Transformer_NF_ETAL_P3191_HandSoldering +Transformer_SMD:Transformer_Pulse_H1100NL +Transformer_SMD:Transformer_Wuerth_750315371 +Transformer_SMD:Transformer_Wurth_WE-AGDT-EP7 +Transformer_THT:Autotransformer_Toroid_1Tap_Horizontal_D10.5mm_Amidon-T37 +Transformer_THT:Autotransformer_Toroid_1Tap_Horizontal_D12.5mm_Amidon-T44 +Transformer_THT:Autotransformer_Toroid_1Tap_Horizontal_D14.0mm_Amidon-T50 +Transformer_THT:Autotransformer_Toroid_1Tap_Horizontal_D9.0mm_Amidon-T30 +Transformer_THT:Autotransformer_ZS1052-AC +Transformer_THT:Transformer_37x44 +Transformer_THT:Transformer_Breve_TEZ-22x24 +Transformer_THT:Transformer_Breve_TEZ-28x33 +Transformer_THT:Transformer_Breve_TEZ-35x42 +Transformer_THT:Transformer_Breve_TEZ-38x45 +Transformer_THT:Transformer_Breve_TEZ-44x52 +Transformer_THT:Transformer_Breve_TEZ-47x57 +Transformer_THT:Transformer_CHK_EI30-2VA_1xSec +Transformer_THT:Transformer_CHK_EI30-2VA_2xSec +Transformer_THT:Transformer_CHK_EI30-2VA_Neutral +Transformer_THT:Transformer_CHK_EI38-3VA_1xSec +Transformer_THT:Transformer_CHK_EI38-3VA_2xSec +Transformer_THT:Transformer_CHK_EI38-3VA_Neutral +Transformer_THT:Transformer_CHK_EI42-5VA_1xSec +Transformer_THT:Transformer_CHK_EI42-5VA_2xSec +Transformer_THT:Transformer_CHK_EI42-5VA_Neutral +Transformer_THT:Transformer_CHK_EI48-10VA_1xSec +Transformer_THT:Transformer_CHK_EI48-10VA_2xSec +Transformer_THT:Transformer_CHK_EI48-10VA_Neutral +Transformer_THT:Transformer_CHK_EI48-8VA_1xSec +Transformer_THT:Transformer_CHK_EI48-8VA_2xSec +Transformer_THT:Transformer_CHK_EI48-8VA_Neutral +Transformer_THT:Transformer_CHK_EI54-12VA_1xSec +Transformer_THT:Transformer_CHK_EI54-12VA_2xSec +Transformer_THT:Transformer_CHK_EI54-12VA_Neutral +Transformer_THT:Transformer_CHK_EI54-16VA_1xSec +Transformer_THT:Transformer_CHK_EI54-16VA_2xSec +Transformer_THT:Transformer_CHK_EI54-16VA_Neutral +Transformer_THT:Transformer_CHK_UI30-4VA_Flat +Transformer_THT:Transformer_CHK_UI39-10VA_Flat +Transformer_THT:Transformer_Coilcraft_Q4434-B_Rhombus-T1311 +Transformer_THT:Transformer_EPCOS_B66359A1013T_Horizontal +Transformer_THT:Transformer_EPCOS_B66359J1014T_Vertical +Transformer_THT:Transformer_Microphone_Lundahl_LL1538 +Transformer_THT:Transformer_Microphone_Lundahl_LL1587 +Transformer_THT:Transformer_Myrra_74040_Horizontal +Transformer_THT:Transformer_Myrra_EF20_7408x +Transformer_THT:Transformer_Myrra_EI30-5_44000_Horizontal +Transformer_THT:Transformer_NF_ETAL_1-1_P1200 +Transformer_THT:Transformer_NF_ETAL_P1165 +Transformer_THT:Transformer_NF_ETAL_P3324 +Transformer_THT:Transformer_NF_ETAL_P3356 +Transformer_THT:Transformer_Toroid_Horizontal_D10.5mm_Amidon-T37 +Transformer_THT:Transformer_Toroid_Horizontal_D12.5mm_Amidon-T44 +Transformer_THT:Transformer_Toroid_Horizontal_D14.0mm_Amidon-T50 +Transformer_THT:Transformer_Toroid_Horizontal_D18.0mm +Transformer_THT:Transformer_Toroid_Horizontal_D9.0mm_Amidon-T30 +Transformer_THT:Transformer_Toroid_Tapped_Horizontal_D10.5mm_Amidon-T37 +Transformer_THT:Transformer_Toroid_Tapped_Horizontal_D12.5mm_Amidon-T44 +Transformer_THT:Transformer_Toroid_Tapped_Horizontal_D14.0mm_Amidon-T50 +Transformer_THT:Transformer_Toroid_Tapped_Horizontal_D9.0mm_Amidon-T30 +Transformer_THT:Transformer_Triad_VPP16-310 +Transformer_THT:Transformer_Wuerth_750343373 +Transformer_THT:Transformer_Wuerth_760871131 +Transformer_THT:Transformer_Zeming_ZMCT103C +Transformer_THT:Transformer_Zeming_ZMPT101K +Transistor_Power:GaN_Systems_GaNPX-3_5x6.6mm_Drain2.93x0.6mm +Transistor_Power:GaN_Systems_GaNPX-3_5x6.6mm_Drain3.76x0.6mm +Transistor_Power:GaN_Systems_GaNPX-4_7x8.4mm +Transistor_Power_Module:Infineon_AG-ECONO2 +Transistor_Power_Module:Infineon_AG-ECONO3 +Transistor_Power_Module:Infineon_AG-ECONO3B +Transistor_Power_Module:Infineon_EasyPACK-1B +Transistor_Power_Module:Infineon_EasyPACK-1B_PressFIT +Transistor_Power_Module:Infineon_EasyPIM-1B +Transistor_Power_Module:Infineon_EasyPIM-2B +Transistor_Power_Module:Littelfuse_Package_H_XBN2MM +Transistor_Power_Module:Littelfuse_Package_H_XN2MM +Transistor_Power_Module:Littelfuse_Package_W_XBN2MM +Transistor_Power_Module:Littelfuse_Package_W_XN2MM +Transistor_Power_Module:ST_ACEPACK-2-CIB +Transistor_Power_Module:ST_ACEPACK-2-CIB_PressFIT +Transistor_Power_Module:ST_SDIP-25L +Valve:Valve_ECC-83-1 +Valve:Valve_ECC-83-2 +Valve:Valve_EURO +Valve:Valve_Glimm +Valve:Valve_Mini_G +Valve:Valve_Mini_P +Valve:Valve_Mini_Pentode_Linear +Valve:Valve_Noval_G +Valve:Valve_Noval_P +Valve:Valve_Octal +Varistor:RV_Disc_D12mm_W3.9mm_P7.5mm +Varistor:RV_Disc_D12mm_W4.2mm_P7.5mm +Varistor:RV_Disc_D12mm_W4.3mm_P7.5mm +Varistor:RV_Disc_D12mm_W4.4mm_P7.5mm +Varistor:RV_Disc_D12mm_W4.5mm_P7.5mm +Varistor:RV_Disc_D12mm_W4.6mm_P7.5mm +Varistor:RV_Disc_D12mm_W4.7mm_P7.5mm +Varistor:RV_Disc_D12mm_W4.8mm_P7.5mm +Varistor:RV_Disc_D12mm_W4mm_P7.5mm +Varistor:RV_Disc_D12mm_W5.1mm_P7.5mm +Varistor:RV_Disc_D12mm_W5.4mm_P7.5mm +Varistor:RV_Disc_D12mm_W5.8mm_P7.5mm +Varistor:RV_Disc_D12mm_W5mm_P7.5mm +Varistor:RV_Disc_D12mm_W6.1mm_P7.5mm +Varistor:RV_Disc_D12mm_W6.2mm_P7.5mm +Varistor:RV_Disc_D12mm_W6.3mm_P7.5mm +Varistor:RV_Disc_D12mm_W6.7mm_P7.5mm +Varistor:RV_Disc_D12mm_W7.1mm_P7.5mm +Varistor:RV_Disc_D12mm_W7.5mm_P7.5mm +Varistor:RV_Disc_D12mm_W7.9mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W11mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W3.9mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W4.2mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W4.3mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W4.4mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W4.5mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W4.6mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W4.7mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W4.8mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W4.9mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W4mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W5.2mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W5.4mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W5.9mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W5mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W6.1mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W6.3mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W6.4mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W6.8mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W7.2mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W7.5mm_P7.5mm +Varistor:RV_Disc_D15.5mm_W8mm_P7.5mm +Varistor:RV_Disc_D16.5mm_W6.7mm_P7.5mm +Varistor:RV_Disc_D21.5mm_W11.4mm_P10mm +Varistor:RV_Disc_D21.5mm_W4.3mm_P10mm +Varistor:RV_Disc_D21.5mm_W4.4mm_P10mm +Varistor:RV_Disc_D21.5mm_W4.5mm_P10mm +Varistor:RV_Disc_D21.5mm_W4.6mm_P10mm +Varistor:RV_Disc_D21.5mm_W4.7mm_P10mm +Varistor:RV_Disc_D21.5mm_W4.8mm_P10mm +Varistor:RV_Disc_D21.5mm_W4.9mm_P10mm +Varistor:RV_Disc_D21.5mm_W5.1mm_P10mm +Varistor:RV_Disc_D21.5mm_W5.3mm_P10mm +Varistor:RV_Disc_D21.5mm_W5.4mm_P10mm +Varistor:RV_Disc_D21.5mm_W5.6mm_P10mm +Varistor:RV_Disc_D21.5mm_W5.8mm_P10mm +Varistor:RV_Disc_D21.5mm_W5mm_P10mm +Varistor:RV_Disc_D21.5mm_W6.1mm_P7.5mm +Varistor:RV_Disc_D21.5mm_W6.3mm_P10mm +Varistor:RV_Disc_D21.5mm_W6.5mm_P10mm +Varistor:RV_Disc_D21.5mm_W6.7mm_P10mm +Varistor:RV_Disc_D21.5mm_W6.8mm_P10mm +Varistor:RV_Disc_D21.5mm_W7.1mm_P10mm +Varistor:RV_Disc_D21.5mm_W7.5mm_P10mm +Varistor:RV_Disc_D21.5mm_W7.9mm_P10mm +Varistor:RV_Disc_D21.5mm_W8.4mm_P10mm +Varistor:RV_Disc_D7mm_W3.4mm_P5mm +Varistor:RV_Disc_D7mm_W3.5mm_P5mm +Varistor:RV_Disc_D7mm_W3.6mm_P5mm +Varistor:RV_Disc_D7mm_W3.7mm_P5mm +Varistor:RV_Disc_D7mm_W3.8mm_P5mm +Varistor:RV_Disc_D7mm_W3.9mm_P5mm +Varistor:RV_Disc_D7mm_W4.2mm_P5mm +Varistor:RV_Disc_D7mm_W4.3mm_P5mm +Varistor:RV_Disc_D7mm_W4.5mm_P5mm +Varistor:RV_Disc_D7mm_W4.8mm_P5mm +Varistor:RV_Disc_D7mm_W4.9mm_P5mm +Varistor:RV_Disc_D7mm_W4mm_P5mm +Varistor:RV_Disc_D7mm_W5.1mm_P5mm +Varistor:RV_Disc_D7mm_W5.4mm_P5mm +Varistor:RV_Disc_D7mm_W5.5mm_P5mm +Varistor:RV_Disc_D7mm_W5.7mm_P5mm +Varistor:RV_Disc_D9mm_W3.3mm_P5mm +Varistor:RV_Disc_D9mm_W3.4mm_P5mm +Varistor:RV_Disc_D9mm_W3.5mm_P5mm +Varistor:RV_Disc_D9mm_W3.6mm_P5mm +Varistor:RV_Disc_D9mm_W3.7mm_P5mm +Varistor:RV_Disc_D9mm_W3.8mm_P5mm +Varistor:RV_Disc_D9mm_W3.9mm_P5mm +Varistor:RV_Disc_D9mm_W4.1mm_P5mm +Varistor:RV_Disc_D9mm_W4.2mm_P5mm +Varistor:RV_Disc_D9mm_W4.4mm_P5mm +Varistor:RV_Disc_D9mm_W4.5mm_P5mm +Varistor:RV_Disc_D9mm_W4.8mm_P5mm +Varistor:RV_Disc_D9mm_W4mm_P5mm +Varistor:RV_Disc_D9mm_W5.2mm_P5mm +Varistor:RV_Disc_D9mm_W5.4mm_P5mm +Varistor:RV_Disc_D9mm_W5.5mm_P5mm +Varistor:RV_Disc_D9mm_W5.7mm_P5mm +Varistor:RV_Disc_D9mm_W6.1mm_P5mm +Varistor:RV_Rect_V25S440P_L26.5mm_W8.2mm_P12.7mm +Varistor:Varistor_Panasonic_VF diff --git a/public/kicad/symbols.txt b/public/kicad/symbols.txt new file mode 100644 index 00000000..1cee1692 --- /dev/null +++ b/public/kicad/symbols.txt @@ -0,0 +1,21807 @@ +# This file contains all the KiCad symbols available in the official library +# Generated by symbols.sh +# on Sun Feb 16 21:42:01 CET 2025 +4xxx:14528 +4xxx:14529 +4xxx:14538 +4xxx:4001 +4xxx:4002 +4xxx:4009 +4xxx:4010 +4xxx:40106 +4xxx:4011 +4xxx:4012 +4xxx:4013 +4xxx:4016 +4xxx:4017 +4xxx:4020 +4xxx:4021 +4xxx:4022 +4xxx:4023 +4xxx:4025 +4xxx:4027 +4xxx:4028 +4xxx:4029 +4xxx:4040 +4xxx:4046 +4xxx:4047 +4xxx:4049 +4xxx:4050 +4xxx:4051 +4xxx:4052 +4xxx:4053 +4xxx:4056 +4xxx:4060 +4xxx:4066 +4xxx:4069 +4xxx:4070 +4xxx:4071 +4xxx:4072 +4xxx:4073 +4xxx:4075 +4xxx:4077 +4xxx:4081 +4xxx:4098 +4xxx:4504 +4xxx:4510 +4xxx:4518 +4xxx:4520 +4xxx:4528 +4xxx:4538 +4xxx:4543 +4xxx:CD4033B +4xxx:HEF4093B +4xxx:HEF4094B +4xxx_IEEE:4001 +4xxx_IEEE:4002 +4xxx_IEEE:4006 +4xxx_IEEE:4008 +4xxx_IEEE:4009 +4xxx_IEEE:4010 +4xxx_IEEE:40104 +4xxx_IEEE:40106 +4xxx_IEEE:4011 +4xxx_IEEE:40110 +4xxx_IEEE:4012 +4xxx_IEEE:4013 +4xxx_IEEE:4014 +4xxx_IEEE:4015 +4xxx_IEEE:4016 +4xxx_IEEE:40160 +4xxx_IEEE:40161 +4xxx_IEEE:40162 +4xxx_IEEE:40163 +4xxx_IEEE:4017 +4xxx_IEEE:40174 +4xxx_IEEE:40175 +4xxx_IEEE:4018 +4xxx_IEEE:4019 +4xxx_IEEE:40192 +4xxx_IEEE:40193 +4xxx_IEEE:40194 +4xxx_IEEE:4020 +4xxx_IEEE:4021 +4xxx_IEEE:4022 +4xxx_IEEE:4023 +4xxx_IEEE:4024 +4xxx_IEEE:40240 +4xxx_IEEE:40244 +4xxx_IEEE:40245 +4xxx_IEEE:4025 +4xxx_IEEE:4027 +4xxx_IEEE:4028 +4xxx_IEEE:4029 +4xxx_IEEE:4030 +4xxx_IEEE:40373 +4xxx_IEEE:40374 +4xxx_IEEE:4040 +4xxx_IEEE:4041 +4xxx_IEEE:4042 +4xxx_IEEE:4043 +4xxx_IEEE:4044 +4xxx_IEEE:4046 +4xxx_IEEE:4048 +4xxx_IEEE:4049 +4xxx_IEEE:4050 +4xxx_IEEE:4051 +4xxx_IEEE:4052 +4xxx_IEEE:4053 +4xxx_IEEE:4060 +4xxx_IEEE:4066 +4xxx_IEEE:4068 +4xxx_IEEE:4069 +4xxx_IEEE:4070 +4xxx_IEEE:4071 +4xxx_IEEE:4072 +4xxx_IEEE:4073 +4xxx_IEEE:4075 +4xxx_IEEE:4077 +4xxx_IEEE:4078 +4xxx_IEEE:4081 +4xxx_IEEE:4082 +4xxx_IEEE:4093 +4xxx_IEEE:4095 +4xxx_IEEE:4096 +4xxx_IEEE:4099 +4xxx_IEEE:4104 +4xxx_IEEE:4160 +4xxx_IEEE:4161 +4xxx_IEEE:4162 +4xxx_IEEE:4163 +4xxx_IEEE:4174 +4xxx_IEEE:4175 +4xxx_IEEE:4502 +4xxx_IEEE:4504 +4xxx_IEEE:4507 +4xxx_IEEE:4508 +4xxx_IEEE:4510 +4xxx_IEEE:4511 +4xxx_IEEE:4512 +4xxx_IEEE:4514 +4xxx_IEEE:4515 +4xxx_IEEE:4518 +4xxx_IEEE:4520 +4xxx_IEEE:4528 +4xxx_IEEE:4529 +4xxx_IEEE:4530 +4xxx_IEEE:4538 +4xxx_IEEE:4539 +4xxx_IEEE:4543 +4xxx_IEEE:4555 +4xxx_IEEE:4556 +4xxx_IEEE:4584 +4xxx_IEEE:4585 +74xGxx:74AHC1G00 +74xGxx:74AHC1G02 +74xGxx:74AHC1G04 +74xGxx:74AHC1G08 +74xGxx:74AHC1G125 +74xGxx:74AHC1G126 +74xGxx:74AHC1G14 +74xGxx:74AHC1G32 +74xGxx:74AHC1G4210 +74xGxx:74AHC1G86 +74xGxx:74AHC1GU04 +74xGxx:74AHC2G00 +74xGxx:74AHCT1G00 +74xGxx:74AHCT1G02 +74xGxx:74AHCT1G04 +74xGxx:74AHCT1G08 +74xGxx:74AHCT1G125 +74xGxx:74AHCT1G126 +74xGxx:74AHCT1G14 +74xGxx:74AHCT1G32 +74xGxx:74AHCT1G86 +74xGxx:74AHCT1GU04 +74xGxx:74AHCT2G00 +74xGxx:74AUC1G00 +74xGxx:74AUC1G02 +74xGxx:74AUC1G04 +74xGxx:74AUC1G06 +74xGxx:74AUC1G07 +74xGxx:74AUC1G08 +74xGxx:74AUC1G125 +74xGxx:74AUC1G126 +74xGxx:74AUC1G14 +74xGxx:74AUC1G17 +74xGxx:74AUC1G18 +74xGxx:74AUC1G19 +74xGxx:74AUC1G240 +74xGxx:74AUC1G32 +74xGxx:74AUC1G66 +74xGxx:74AUC1G74 +74xGxx:74AUC1G79 +74xGxx:74AUC1G80 +74xGxx:74AUC1G86 +74xGxx:74AUC1GU04 +74xGxx:74AUC2G00 +74xGxx:74AUC2G02 +74xGxx:74AUC2G04 +74xGxx:74AUC2G06 +74xGxx:74AUC2G07 +74xGxx:74AUC2G08 +74xGxx:74AUC2G125 +74xGxx:74AUC2G126 +74xGxx:74AUC2G240 +74xGxx:74AUC2G241 +74xGxx:74AUC2G32 +74xGxx:74AUC2G34 +74xGxx:74AUC2G53 +74xGxx:74AUC2G66 +74xGxx:74AUC2G79 +74xGxx:74AUC2G80 +74xGxx:74AUC2G86 +74xGxx:74AUC2GU04 +74xGxx:74AUP1G00 +74xGxx:74AUP1G02 +74xGxx:74AUP1G04 +74xGxx:74AUP1G06 +74xGxx:74AUP1G07 +74xGxx:74AUP1G08 +74xGxx:74AUP1G125 +74xGxx:74AUP1G126 +74xGxx:74AUP1G14 +74xGxx:74AUP1G17 +74xGxx:74AUP1G240 +74xGxx:74AUP1G32 +74xGxx:74AUP1G34 +74xGxx:74AUP1G57 +74xGxx:74AUP1G58 +74xGxx:74AUP1G74 +74xGxx:74AUP1G79 +74xGxx:74AUP1G80 +74xGxx:74AUP1G97 +74xGxx:74AUP1G98 +74xGxx:74AUP1G99 +74xGxx:74AUP1GU04 +74xGxx:74CB3T1G125 +74xGxx:74CBT1G125 +74xGxx:74CBT1G384 +74xGxx:74CBTD1G125 +74xGxx:74CBTD1G384 +74xGxx:74CBTLV1G125 +74xGxx:74LVC1G00 +74xGxx:74LVC1G02 +74xGxx:74LVC1G04 +74xGxx:74LVC1G06 +74xGxx:74LVC1G07 +74xGxx:74LVC1G08 +74xGxx:74LVC1G0832 +74xGxx:74LVC1G10 +74xGxx:74LVC1G11 +74xGxx:74LVC1G123 +74xGxx:74LVC1G125 +74xGxx:74LVC1G126 +74xGxx:74LVC1G139 +74xGxx:74LVC1G14 +74xGxx:74LVC1G17 +74xGxx:74LVC1G175 +74xGxx:74LVC1G18 +74xGxx:74LVC1G19 +74xGxx:74LVC1G240 +74xGxx:74LVC1G27 +74xGxx:74LVC1G29 +74xGxx:74LVC1G3157 +74xGxx:74LVC1G32 +74xGxx:74LVC1G3208 +74xGxx:74LVC1G332 +74xGxx:74LVC1G34 +74xGxx:74LVC1G373 +74xGxx:74LVC1G374 +74xGxx:74LVC1G38 +74xGxx:74LVC1G386 +74xGxx:74LVC1G57 +74xGxx:74LVC1G58 +74xGxx:74LVC1G66 +74xGxx:74LVC1G79 +74xGxx:74LVC1G80 +74xGxx:74LVC1G86 +74xGxx:74LVC1G97 +74xGxx:74LVC1G98 +74xGxx:74LVC1G99 +74xGxx:74LVC1GU04 +74xGxx:74LVC1GU04DRL +74xGxx:74LVC2G00 +74xGxx:74LVC2G02 +74xGxx:74LVC2G04 +74xGxx:74LVC2G06 +74xGxx:74LVC2G07 +74xGxx:74LVC2G08 +74xGxx:74LVC2G125 +74xGxx:74LVC2G126 +74xGxx:74LVC2G14 +74xGxx:74LVC2G157 +74xGxx:74LVC2G17 +74xGxx:74LVC2G240 +74xGxx:74LVC2G241 +74xGxx:74LVC2G32 +74xGxx:74LVC2G34 +74xGxx:74LVC2G38 +74xGxx:74LVC2G53 +74xGxx:74LVC2G66 +74xGxx:74LVC2G74 +74xGxx:74LVC2G79 +74xGxx:74LVC2G80 +74xGxx:74LVC2G86 +74xGxx:74LVC2GU04 +74xGxx:74LVC3G04 +74xGxx:74LVC3G06 +74xGxx:74LVC3G07 +74xGxx:74LVC3G14 +74xGxx:74LVC3G17 +74xGxx:74LVC3G34 +74xGxx:74LVC3GU04 +74xGxx:Inverter_Schmitt_Dual +74xGxx:NC7SVU04P5X +74xGxx:NC7SZ125M5X +74xGxx:NC7SZ125P5X +74xGxx:SN74LVC1G00DBV +74xGxx:SN74LVC1G00DCK +74xGxx:SN74LVC1G00DRL +74xGxx:SN74LVC1G125DBV +74xGxx:SN74LVC1G125DCK +74xGxx:SN74LVC1G125DRL +74xGxx:SN74LVC1G14DBV +74xGxx:SN74LVC1G14DRL +74xGxx:SN74LVC2G14DBV +74xGxx:TC7PZ14FU +74xx:7400 +74xx:7402 +74xx:74469 +74xx:7454 +74xx:74AHC04 +74xx:74AHC240 +74xx:74AHC244 +74xx:74AHC273 +74xx:74AHC373 +74xx:74AHC374 +74xx:74AHC541 +74xx:74AHC595 +74xx:74AHCT04 +74xx:74AHCT123 +74xx:74AHCT125 +74xx:74AHCT240 +74xx:74AHCT244 +74xx:74AHCT273 +74xx:74AHCT373 +74xx:74AHCT374 +74xx:74AHCT541 +74xx:74AHCT595 +74xx:74ALVC164245 +74xx:74CB3Q16210DGG +74xx:74CB3Q16210DGV +74xx:74CB3Q16210DL +74xx:74CB3T16210DGG +74xx:74CB3T16210DGV +74xx:74CBT16210CDGG +74xx:74CBT16210CDGV +74xx:74CBT16210CDL +74xx:74CBT3861 +74xx:74CBTD16210DGG +74xx:74CBTD16210DGV +74xx:74CBTD16210DL +74xx:74CBTD3861 +74xx:74CBTLV16212 +74xx:74CBTLV3257 +74xx:74CBTLV3861 +74xx:74HC00 +74xx:74HC02 +74xx:74HC04 +74xx:74HC123 +74xx:74HC137 +74xx:74HC138 +74xx:74HC14 +74xx:74HC164 +74xx:74HC165 +74xx:74HC173 +74xx:74HC192 +74xx:74HC193 +74xx:74HC237 +74xx:74HC238 +74xx:74HC240 +74xx:74HC244 +74xx:74HC245 +74xx:74HC273 +74xx:74HC373 +74xx:74HC374 +74xx:74HC4024 +74xx:74HC4051 +74xx:74HC4060 +74xx:74HC590 +74xx:74HC590A +74xx:74HC594 +74xx:74HC595 +74xx:74HC596 +74xx:74HC688 +74xx:74HC7014 +74xx:74HC74 +74xx:74HC85 +74xx:74HC86 +74xx:74HCT00 +74xx:74HCT02 +74xx:74HCT04 +74xx:74HCT123 +74xx:74HCT137 +74xx:74HCT138 +74xx:74HCT164 +74xx:74HCT173 +74xx:74HCT193 +74xx:74HCT237 +74xx:74HCT238 +74xx:74HCT240 +74xx:74HCT244 +74xx:74HCT273 +74xx:74HCT373 +74xx:74HCT374 +74xx:74HCT4051 +74xx:74HCT541 +74xx:74HCT574 +74xx:74HCT595 +74xx:74HCT596 +74xx:74HCT688 +74xx:74HCT74 +74xx:74HCT85 +74xx:74LCX07 +74xx:74LS00 +74xx:74LS01 +74xx:74LS02 +74xx:74LS03 +74xx:74LS04 +74xx:74LS05 +74xx:74LS06 +74xx:74LS06N +74xx:74LS07 +74xx:74LS08 +74xx:74LS09 +74xx:74LS10 +74xx:74LS107 +74xx:74LS109 +74xx:74LS11 +74xx:74LS112 +74xx:74LS113 +74xx:74LS114 +74xx:74LS12 +74xx:74LS121 +74xx:74LS122 +74xx:74LS123 +74xx:74LS125 +74xx:74LS126 +74xx:74LS13 +74xx:74LS132 +74xx:74LS133 +74xx:74LS136 +74xx:74LS137 +74xx:74LS138 +74xx:74LS139 +74xx:74LS14 +74xx:74LS145 +74xx:74LS147 +74xx:74LS148 +74xx:74LS15 +74xx:74LS151 +74xx:74LS153 +74xx:74LS154 +74xx:74LS155 +74xx:74LS156 +74xx:74LS157 +74xx:74LS158 +74xx:74LS160 +74xx:74LS161 +74xx:74LS162 +74xx:74LS163 +74xx:74LS165 +74xx:74LS166 +74xx:74LS168 +74xx:74LS169 +74xx:74LS170 +74xx:74LS173 +74xx:74LS174 +74xx:74LS175 +74xx:74LS181 +74xx:74LS182 +74xx:74LS190 +74xx:74LS191 +74xx:74LS192 +74xx:74LS193 +74xx:74LS194 +74xx:74LS195 +74xx:74LS196 +74xx:74LS197 +74xx:74LS20 +74xx:74LS21 +74xx:74LS22 +74xx:74LS221 +74xx:74LS240 +74xx:74LS240_Split +74xx:74LS241 +74xx:74LS241_Split +74xx:74LS242 +74xx:74LS243 +74xx:74LS244 +74xx:74LS244_Split +74xx:74LS245 +74xx:74LS246 +74xx:74LS247 +74xx:74LS248 +74xx:74LS249 +74xx:74LS251 +74xx:74LS253 +74xx:74LS256 +74xx:74LS257 +74xx:74LS258 +74xx:74LS259 +74xx:74LS26 +74xx:74LS27 +74xx:74LS273 +74xx:74LS279 +74xx:74LS28 +74xx:74LS280 +74xx:74LS283 +74xx:74LS290 +74xx:74LS293 +74xx:74LS295 +74xx:74LS298 +74xx:74LS299 +74xx:74LS30 +74xx:74LS32 +74xx:74LS322 +74xx:74LS323 +74xx:74LS33 +74xx:74LS348 +74xx:74LS352 +74xx:74LS353 +74xx:74LS365 +74xx:74LS366 +74xx:74LS367 +74xx:74LS368 +74xx:74LS37 +74xx:74LS373 +74xx:74LS374 +74xx:74LS375 +74xx:74LS377 +74xx:74LS378 +74xx:74LS379 +74xx:74LS38 +74xx:74LS385 +74xx:74LS386 +74xx:74LS390 +74xx:74LS393 +74xx:74LS395 +74xx:74LS398 +74xx:74LS399 +74xx:74LS40 +74xx:74LS42 +74xx:74LS46 +74xx:74LS47 +74xx:74LS48 +74xx:74LS49 +74xx:74LS51 +74xx:74LS540 +74xx:74LS541 +74xx:74LS54N +74xx:74LS55 +74xx:74LS573 +74xx:74LS574 +74xx:74LS590 +74xx:74LS595 +74xx:74LS596 +74xx:74LS629 +74xx:74LS670 +74xx:74LS688 +74xx:74LS73 +74xx:74LS74 +74xx:74LS75 +74xx:74LS76 +74xx:74LS77 +74xx:74LS78 +74xx:74LS83 +74xx:74LS85 +74xx:74LS86 +74xx:74LS90 +74xx:74LS91 +74xx:74LS92 +74xx:74LS93 +74xx:74LS95 +74xx:74LV14 +74xx:74LV8154 +74xx:74LVC125 +74xx:74VHC9164FT +74xx:CD74AC238 +74xx:CD74HC4067M +74xx:CD74HC4067SM +74xx:MC74LCX16245DT +74xx:MM74C923 +74xx:SN74ALVC164245DGG +74xx:SN74ALVC164245DL +74xx:SN74AVC16827DGGR +74xx:SN74CB3Q3384ADBQ +74xx:SN74CB3Q3384APW +74xx:SN74LS07 +74xx:SN74LS07N +74xx:SN74LV4T125 +74xx_IEEE:7400 +74xx_IEEE:7401 +74xx_IEEE:7402 +74xx_IEEE:7403 +74xx_IEEE:7404 +74xx_IEEE:7405 +74xx_IEEE:7406 +74xx_IEEE:7407 +74xx_IEEE:7408 +74xx_IEEE:7409 +74xx_IEEE:7410 +74xx_IEEE:7411 +74xx_IEEE:7412 +74xx_IEEE:74125 +74xx_IEEE:74126 +74xx_IEEE:74128 +74xx_IEEE:7413 +74xx_IEEE:74132 +74xx_IEEE:74136 +74xx_IEEE:7414 +74xx_IEEE:74141 +74xx_IEEE:74145 +74xx_IEEE:74147 +74xx_IEEE:74148 +74xx_IEEE:74151 +74xx_IEEE:74153 +74xx_IEEE:74154 +74xx_IEEE:74155 +74xx_IEEE:74156 +74xx_IEEE:74157 +74xx_IEEE:74158 +74xx_IEEE:74159 +74xx_IEEE:7416 +74xx_IEEE:74164 +74xx_IEEE:74165 +74xx_IEEE:74166 +74xx_IEEE:7417 +74xx_IEEE:74173 +74xx_IEEE:74176 +74xx_IEEE:74196 +74xx_IEEE:7420 +74xx_IEEE:7421 +74xx_IEEE:7422 +74xx_IEEE:74246 +74xx_IEEE:74247 +74xx_IEEE:74248 +74xx_IEEE:74249 +74xx_IEEE:7425 +74xx_IEEE:74251 +74xx_IEEE:74253 +74xx_IEEE:7426 +74xx_IEEE:7427 +74xx_IEEE:74278 +74xx_IEEE:7428 +74xx_IEEE:74293 +74xx_IEEE:7430 +74xx_IEEE:7432 +74xx_IEEE:7433 +74xx_IEEE:7437 +74xx_IEEE:7438 +74xx_IEEE:7439 +74xx_IEEE:7440 +74xx_IEEE:7442 +74xx_IEEE:74425 +74xx_IEEE:74426 +74xx_IEEE:7443 +74xx_IEEE:7444 +74xx_IEEE:7445 +74xx_IEEE:7446 +74xx_IEEE:7447 +74xx_IEEE:7448 +74xx_IEEE:7451 +74xx_IEEE:7454 +74xx_IEEE:7483 +74xx_IEEE:7485 +74xx_IEEE:7486 +74xx_IEEE:7490 +74xx_IEEE:7491 +74xx_IEEE:7492 +74xx_IEEE:7493 +74xx_IEEE:7495 +74xx_IEEE:7496 +74xx_IEEE:74HC237 +74xx_IEEE:74HC238 +74xx_IEEE:74HC36 +74xx_IEEE:74HC804 +74xx_IEEE:74HC805 +74xx_IEEE:74HC808 +74xx_IEEE:74HC832 +74xx_IEEE:74LS133 +74xx_IEEE:74LS137 +74xx_IEEE:74LS138 +74xx_IEEE:74LS139 +74xx_IEEE:74LS15 +74xx_IEEE:74LS152 +74xx_IEEE:74LS160 +74xx_IEEE:74LS161 +74xx_IEEE:74LS162 +74xx_IEEE:74LS163 +74xx_IEEE:74LS168 +74xx_IEEE:74LS169 +74xx_IEEE:74LS170 +74xx_IEEE:74LS177 +74xx_IEEE:74LS18 +74xx_IEEE:74LS19 +74xx_IEEE:74LS190 +74xx_IEEE:74LS191 +74xx_IEEE:74LS192 +74xx_IEEE:74LS193 +74xx_IEEE:74LS194 +74xx_IEEE:74LS195 +74xx_IEEE:74LS197 +74xx_IEEE:74LS239 +74xx_IEEE:74LS24 +74xx_IEEE:74LS240 +74xx_IEEE:74LS241 +74xx_IEEE:74LS242 +74xx_IEEE:74LS243 +74xx_IEEE:74LS244 +74xx_IEEE:74LS245 +74xx_IEEE:74LS257 +74xx_IEEE:74LS258 +74xx_IEEE:74LS266 +74xx_IEEE:74LS280 +74xx_IEEE:74LS283 +74xx_IEEE:74LS290 +74xx_IEEE:74LS295 +74xx_IEEE:74LS298 +74xx_IEEE:74LS299 +74xx_IEEE:74LS323 +74xx_IEEE:74LS347 +74xx_IEEE:74LS348 +74xx_IEEE:74LS352 +74xx_IEEE:74LS353 +74xx_IEEE:74LS365 +74xx_IEEE:74LS366 +74xx_IEEE:74LS367 +74xx_IEEE:74LS368 +74xx_IEEE:74LS386 +74xx_IEEE:74LS390 +74xx_IEEE:74LS395 +74xx_IEEE:74LS396 +74xx_IEEE:74LS398 +74xx_IEEE:74LS399 +74xx_IEEE:74LS445 +74xx_IEEE:74LS447 +74xx_IEEE:74LS465 +74xx_IEEE:74LS466 +74xx_IEEE:74LS467 +74xx_IEEE:74LS468 +74xx_IEEE:74LS49 +74xx_IEEE:74LS540 +74xx_IEEE:74LS541 +74xx_IEEE:74LS55 +74xx_IEEE:74LS56 +74xx_IEEE:74LS57 +74xx_IEEE:74LS590 +74xx_IEEE:74LS591 +74xx_IEEE:74LS594 +74xx_IEEE:74LS595 +74xx_IEEE:74LS596 +74xx_IEEE:74LS597 +74xx_IEEE:74LS599 +74xx_IEEE:74LS620 +74xx_IEEE:74LS621 +74xx_IEEE:74LS622 +74xx_IEEE:74LS623 +74xx_IEEE:74LS638 +74xx_IEEE:74LS639 +74xx_IEEE:74LS640 +74xx_IEEE:74LS641 +74xx_IEEE:74LS642 +74xx_IEEE:74LS645 +74xx_IEEE:74LS668 +74xx_IEEE:74LS669 +74xx_IEEE:74LS670 +74xx_IEEE:74LS682 +74xx_IEEE:74LS683 +74xx_IEEE:74LS684 +74xx_IEEE:74LS685 +74xx_IEEE:74LS686 +74xx_IEEE:74LS687 +74xx_IEEE:74LS688 +74xx_IEEE:74LS689 +74xx_IEEE:74S140 +Amplifier_Audio:IR4301 +Amplifier_Audio:IR4302 +Amplifier_Audio:IR4311 +Amplifier_Audio:IR4312 +Amplifier_Audio:IR4321 +Amplifier_Audio:IR4322 +Amplifier_Audio:IRS2052M +Amplifier_Audio:IRS2092 +Amplifier_Audio:IRS2092S +Amplifier_Audio:IRS2093M +Amplifier_Audio:IRS20957S +Amplifier_Audio:IRS20965S +Amplifier_Audio:IRS2452AM +Amplifier_Audio:IS31AP4991-GRLS2 +Amplifier_Audio:IS31AP4991-SLS2 +Amplifier_Audio:LM1875 +Amplifier_Audio:LM1876 +Amplifier_Audio:LM1877 +Amplifier_Audio:LM2876 +Amplifier_Audio:LM380N +Amplifier_Audio:LM380N-8 +Amplifier_Audio:LM384 +Amplifier_Audio:LM386 +Amplifier_Audio:LM3886 +Amplifier_Audio:LM4752TS +Amplifier_Audio:LM4755TS +Amplifier_Audio:LM4766 +Amplifier_Audio:LM4810 +Amplifier_Audio:LM4811 +Amplifier_Audio:LM4950TA +Amplifier_Audio:LM4950TS +Amplifier_Audio:LM4990ITL +Amplifier_Audio:LM4990LD +Amplifier_Audio:LM4990MH +Amplifier_Audio:LM4990MM +Amplifier_Audio:LME49600 +Amplifier_Audio:MA12040 +Amplifier_Audio:MA12040P +Amplifier_Audio:MA12070 +Amplifier_Audio:MA12070P +Amplifier_Audio:MAX9701xTG +Amplifier_Audio:MAX9715xTE+ +Amplifier_Audio:MAX9744 +Amplifier_Audio:MAX9814 +Amplifier_Audio:MAX98306xDT +Amplifier_Audio:MAX98396EWB+ +Amplifier_Audio:MAX9850xTI +Amplifier_Audio:OPA1622 +Amplifier_Audio:PAM8301 +Amplifier_Audio:PAM8302AAD +Amplifier_Audio:PAM8302AAS +Amplifier_Audio:PAM8302AAY +Amplifier_Audio:PAM8403D +Amplifier_Audio:PAM8406D +Amplifier_Audio:SSM2017P +Amplifier_Audio:SSM2018 +Amplifier_Audio:SSM2120 +Amplifier_Audio:SSM2122 +Amplifier_Audio:SSM2165 +Amplifier_Audio:SSM2167 +Amplifier_Audio:SSM2211CP +Amplifier_Audio:SSM2211S +Amplifier_Audio:STK433_Sanyo +Amplifier_Audio:STK435_Sanyo +Amplifier_Audio:STK436_Sanyo +Amplifier_Audio:STK437_Sanyo +Amplifier_Audio:STK439_Sanyo +Amplifier_Audio:STK441_Sanyo +Amplifier_Audio:STK443_Sanyo +Amplifier_Audio:Si8241BB +Amplifier_Audio:Si8241CB +Amplifier_Audio:Si8244BB +Amplifier_Audio:Si8244CB +Amplifier_Audio:TAS5825MRHB +Amplifier_Audio:TDA1308 +Amplifier_Audio:TDA2003 +Amplifier_Audio:TDA2005 +Amplifier_Audio:TDA2030 +Amplifier_Audio:TDA2050 +Amplifier_Audio:TDA7052A +Amplifier_Audio:TDA7264 +Amplifier_Audio:TDA7265 +Amplifier_Audio:TDA7265B +Amplifier_Audio:TDA7266 +Amplifier_Audio:TDA7266D +Amplifier_Audio:TDA7266M +Amplifier_Audio:TDA7266P +Amplifier_Audio:TDA7269A +Amplifier_Audio:TDA7292 +Amplifier_Audio:TDA7293 +Amplifier_Audio:TDA7294 +Amplifier_Audio:TDA7295 +Amplifier_Audio:TDA7296 +Amplifier_Audio:TDA7297 +Amplifier_Audio:TDA7496 +Amplifier_Audio:TFA9879HN +Amplifier_Audio:THAT151xx08 +Amplifier_Audio:THAT2180 +Amplifier_Audio:THAT2181 +Amplifier_Audio:TPA3251 +Amplifier_Audio:TPA6110A2DGN +Amplifier_Audio:TPA6132A2RTE +Amplifier_Audio:TPA6203A1DGN +Amplifier_Audio:TPA6203A1DRB +Amplifier_Buffer:BUF602xD +Amplifier_Buffer:BUF602xDBV +Amplifier_Buffer:BUF634AxD +Amplifier_Buffer:BUF634AxDDA +Amplifier_Buffer:BUF634AxDRB +Amplifier_Buffer:BUF634U +Amplifier_Buffer:EL2001CN +Amplifier_Buffer:LH0002H +Amplifier_Buffer:LM6321H +Amplifier_Buffer:LM6321M +Amplifier_Buffer:LM6321N +Amplifier_Current:AD8202 +Amplifier_Current:AD8203 +Amplifier_Current:AD8205 +Amplifier_Current:AD8206 +Amplifier_Current:AD8208 +Amplifier_Current:AD8209 +Amplifier_Current:AD8210 +Amplifier_Current:AD8211 +Amplifier_Current:AD8212 +Amplifier_Current:AD8213 +Amplifier_Current:AD8215 +Amplifier_Current:AD8216 +Amplifier_Current:AD8217 +Amplifier_Current:AD8218xCP +Amplifier_Current:AD8218xRM +Amplifier_Current:AD8219 +Amplifier_Current:AD8417 +Amplifier_Current:AD8418 +Amplifier_Current:BQ500100DCK +Amplifier_Current:INA138 +Amplifier_Current:INA139 +Amplifier_Current:INA168 +Amplifier_Current:INA169 +Amplifier_Current:INA180A1 +Amplifier_Current:INA180A2 +Amplifier_Current:INA180A3 +Amplifier_Current:INA180A4 +Amplifier_Current:INA180B1 +Amplifier_Current:INA180B2 +Amplifier_Current:INA180B3 +Amplifier_Current:INA180B4 +Amplifier_Current:INA181 +Amplifier_Current:INA185 +Amplifier_Current:INA193 +Amplifier_Current:INA194 +Amplifier_Current:INA195 +Amplifier_Current:INA196 +Amplifier_Current:INA197 +Amplifier_Current:INA198 +Amplifier_Current:INA199xxDCK +Amplifier_Current:INA200D +Amplifier_Current:INA200DGK +Amplifier_Current:INA201D +Amplifier_Current:INA201DGK +Amplifier_Current:INA202D +Amplifier_Current:INA202DGK +Amplifier_Current:INA225 +Amplifier_Current:INA240A1D +Amplifier_Current:INA240A1PW +Amplifier_Current:INA240A2D +Amplifier_Current:INA240A2PW +Amplifier_Current:INA240A3D +Amplifier_Current:INA240A3PW +Amplifier_Current:INA240A4D +Amplifier_Current:INA240A4PW +Amplifier_Current:INA241A1xD +Amplifier_Current:INA241A1xDDF +Amplifier_Current:INA241A1xDGK +Amplifier_Current:INA241A2xD +Amplifier_Current:INA241A2xDDF +Amplifier_Current:INA241A2xDGK +Amplifier_Current:INA241A3xD +Amplifier_Current:INA241A3xDDF +Amplifier_Current:INA241A3xDGK +Amplifier_Current:INA241A4xD +Amplifier_Current:INA241A4xDDF +Amplifier_Current:INA241A4xDGK +Amplifier_Current:INA241A5xD +Amplifier_Current:INA241A5xDDF +Amplifier_Current:INA241A5xDGK +Amplifier_Current:INA241B1xD +Amplifier_Current:INA241B1xDDF +Amplifier_Current:INA241B1xDGK +Amplifier_Current:INA241B2xD +Amplifier_Current:INA241B2xDDF +Amplifier_Current:INA241B2xDGK +Amplifier_Current:INA241B3xD +Amplifier_Current:INA241B3xDDF +Amplifier_Current:INA241B3xDGK +Amplifier_Current:INA241B4xD +Amplifier_Current:INA241B4xDDF +Amplifier_Current:INA241B4xDGK +Amplifier_Current:INA241B5xD +Amplifier_Current:INA241B5xDDF +Amplifier_Current:INA241B5xDGK +Amplifier_Current:INA253 +Amplifier_Current:INA281A1 +Amplifier_Current:INA281A2 +Amplifier_Current:INA281A3 +Amplifier_Current:INA281A4 +Amplifier_Current:INA281A5 +Amplifier_Current:INA282 +Amplifier_Current:INA283 +Amplifier_Current:INA284 +Amplifier_Current:INA285 +Amplifier_Current:INA286 +Amplifier_Current:INA293A1 +Amplifier_Current:INA293A2 +Amplifier_Current:INA293A3 +Amplifier_Current:INA293A4 +Amplifier_Current:INA293A5 +Amplifier_Current:INA293B1 +Amplifier_Current:INA293B2 +Amplifier_Current:INA293B3 +Amplifier_Current:INA293B4 +Amplifier_Current:INA293B5 +Amplifier_Current:INA4180A1 +Amplifier_Current:INA4180A2 +Amplifier_Current:INA4180A3 +Amplifier_Current:INA4180A4 +Amplifier_Current:LMP8640 +Amplifier_Current:LT6106 +Amplifier_Current:LTC6102HVxDD +Amplifier_Current:LTC6102HVxMS8 +Amplifier_Current:LTC6102xDD +Amplifier_Current:LTC6102xDD-1 +Amplifier_Current:LTC6102xMS8 +Amplifier_Current:LTC6102xMS8-1 +Amplifier_Current:MAX4080F +Amplifier_Current:MAX4080S +Amplifier_Current:MAX4080T +Amplifier_Current:MAX4081F +Amplifier_Current:MAX4081S +Amplifier_Current:MAX4081T +Amplifier_Current:MAX471 +Amplifier_Current:MAX472 +Amplifier_Current:NCS210 +Amplifier_Current:NCS211 +Amplifier_Current:NCS213 +Amplifier_Current:NCS214 +Amplifier_Current:NCV210 +Amplifier_Current:NCV211 +Amplifier_Current:NCV213 +Amplifier_Current:NCV214 +Amplifier_Current:ZXCT1009F +Amplifier_Current:ZXCT1009T8 +Amplifier_Current:ZXCT1010 +Amplifier_Current:ZXCT1107 +Amplifier_Current:ZXCT1109 +Amplifier_Current:ZXCT1110 +Amplifier_Difference:AD628 +Amplifier_Difference:AD8207 +Amplifier_Difference:AD8276 +Amplifier_Difference:AD8475ACPZ +Amplifier_Difference:AD8475xRMZ +Amplifier_Difference:ADA4938-1 +Amplifier_Difference:ADA4940-1xCP +Amplifier_Difference:ADA4940-2 +Amplifier_Difference:AMC1100DWV +Amplifier_Difference:AMC1200BDWV +Amplifier_Difference:AMC1300BDWV +Amplifier_Difference:AMC1300DWV +Amplifier_Difference:INA105KP +Amplifier_Difference:INA105KU +Amplifier_Difference:LM733CH +Amplifier_Difference:LM733CN +Amplifier_Difference:LM733H +Amplifier_Difference:LTC1992-x-xMS8 +Amplifier_Difference:THS4521ID +Amplifier_Difference:THS4521IDGK +Amplifier_Difference:THS4551xRGT +Amplifier_Instrumentation:AD620 +Amplifier_Instrumentation:AD623 +Amplifier_Instrumentation:AD623AN +Amplifier_Instrumentation:AD623ANZ +Amplifier_Instrumentation:AD623AR +Amplifier_Instrumentation:AD623ARM +Amplifier_Instrumentation:AD623ARMZ +Amplifier_Instrumentation:AD623ARZ +Amplifier_Instrumentation:AD623BN +Amplifier_Instrumentation:AD623BNZ +Amplifier_Instrumentation:AD623BR +Amplifier_Instrumentation:AD623BRZ +Amplifier_Instrumentation:AD8230 +Amplifier_Instrumentation:AD8231 +Amplifier_Instrumentation:AD8236 +Amplifier_Instrumentation:AD8236ARMZ +Amplifier_Instrumentation:AD8421 +Amplifier_Instrumentation:AD8421ARMZ +Amplifier_Instrumentation:AD8421ARZ +Amplifier_Instrumentation:AD8421BRMZ +Amplifier_Instrumentation:AD8421BRZ +Amplifier_Instrumentation:AD8422 +Amplifier_Instrumentation:AD8422ARMZ +Amplifier_Instrumentation:AD8422ARZ +Amplifier_Instrumentation:AD8422BRMZ +Amplifier_Instrumentation:AD8422BRZ +Amplifier_Instrumentation:AD8429 +Amplifier_Instrumentation:AD8429ARZ +Amplifier_Instrumentation:AD8429BRZ +Amplifier_Instrumentation:INA128 +Amplifier_Instrumentation:INA129 +Amplifier_Instrumentation:INA326 +Amplifier_Instrumentation:INA327 +Amplifier_Instrumentation:INA333xxDGK +Amplifier_Instrumentation:INA333xxDRG +Amplifier_Instrumentation:INA849D +Amplifier_Instrumentation:INA849DGK +Amplifier_Instrumentation:LTC1100xN8 +Amplifier_Instrumentation:LTC1100xSW +Amplifier_Operational:AD797 +Amplifier_Operational:AD8001AN +Amplifier_Operational:AD8001AR +Amplifier_Operational:AD8015 +Amplifier_Operational:AD8021AR +Amplifier_Operational:AD8021ARM +Amplifier_Operational:AD817 +Amplifier_Operational:AD8603 +Amplifier_Operational:AD8606ARM +Amplifier_Operational:AD8606ARZ +Amplifier_Operational:AD8610xR +Amplifier_Operational:AD8610xRM +Amplifier_Operational:AD8620 +Amplifier_Operational:AD8620xRM +Amplifier_Operational:AD8655 +Amplifier_Operational:AD8656 +Amplifier_Operational:AD8676xR +Amplifier_Operational:ADA4075-2 +Amplifier_Operational:ADA4077-1xR +Amplifier_Operational:ADA4077-1xRM +Amplifier_Operational:ADA4084-4xCP +Amplifier_Operational:ADA4099-1xUJ +Amplifier_Operational:ADA4099-2xCP +Amplifier_Operational:ADA4099-2xR +Amplifier_Operational:ADA4099-2xRM +Amplifier_Operational:ADA4522-1 +Amplifier_Operational:ADA4522-2 +Amplifier_Operational:ADA4522-4 +Amplifier_Operational:ADA4530-1 +Amplifier_Operational:ADA4610-1xR +Amplifier_Operational:ADA4610-1xRJ +Amplifier_Operational:ADA4610-2xCP +Amplifier_Operational:ADA4610-2xR +Amplifier_Operational:ADA4610-2xRM +Amplifier_Operational:ADA4610-4xCP +Amplifier_Operational:ADA4610-4xR +Amplifier_Operational:ADA4622-2xCP +Amplifier_Operational:ADA4622-4xCP +Amplifier_Operational:ADA4625-1ARDZ +Amplifier_Operational:ADA4625-2ARDZ +Amplifier_Operational:ADA4807-1 +Amplifier_Operational:ADA4807-2ACP +Amplifier_Operational:ADA4807-2ARM +Amplifier_Operational:ADA4807-4ARUZ +Amplifier_Operational:ADA4817-1ACP +Amplifier_Operational:ADA4817-1ARD +Amplifier_Operational:ADA4817-2ACP +Amplifier_Operational:ADA4841-1YRJ +Amplifier_Operational:ADA4870ARRZ +Amplifier_Operational:ADA4898-1YRDZ +Amplifier_Operational:ADA4898-2 +Amplifier_Operational:AS13704 +Amplifier_Operational:CA3080 +Amplifier_Operational:CA3080A +Amplifier_Operational:CA3130 +Amplifier_Operational:CA3140 +Amplifier_Operational:HMC799LP3E +Amplifier_Operational:L272 +Amplifier_Operational:L272D +Amplifier_Operational:L272M +Amplifier_Operational:LF155 +Amplifier_Operational:LF156 +Amplifier_Operational:LF256 +Amplifier_Operational:LF257 +Amplifier_Operational:LF351D +Amplifier_Operational:LF351N +Amplifier_Operational:LF355 +Amplifier_Operational:LF356 +Amplifier_Operational:LF357 +Amplifier_Operational:LM101 +Amplifier_Operational:LM13600 +Amplifier_Operational:LM13700 +Amplifier_Operational:LM201 +Amplifier_Operational:LM2902 +Amplifier_Operational:LM2904 +Amplifier_Operational:LM301 +Amplifier_Operational:LM318H +Amplifier_Operational:LM318J +Amplifier_Operational:LM318M +Amplifier_Operational:LM318N +Amplifier_Operational:LM321 +Amplifier_Operational:LM324 +Amplifier_Operational:LM324A +Amplifier_Operational:LM358 +Amplifier_Operational:LM358_DFN +Amplifier_Operational:LM4250 +Amplifier_Operational:LM4562 +Amplifier_Operational:LM6142xIx +Amplifier_Operational:LM6144xIx +Amplifier_Operational:LM6171D +Amplifier_Operational:LM6171xxN +Amplifier_Operational:LM6172 +Amplifier_Operational:LM6361 +Amplifier_Operational:LM675 +Amplifier_Operational:LM7171xIM +Amplifier_Operational:LM7171xIN +Amplifier_Operational:LM7332 +Amplifier_Operational:LM741 +Amplifier_Operational:LM8261 +Amplifier_Operational:LMC6062 +Amplifier_Operational:LMC6082 +Amplifier_Operational:LMC6482 +Amplifier_Operational:LMC6484 +Amplifier_Operational:LMH6551MA +Amplifier_Operational:LMH6551MM +Amplifier_Operational:LMH6609MA +Amplifier_Operational:LMH6609MF +Amplifier_Operational:LMH6611 +Amplifier_Operational:LMH6702MA +Amplifier_Operational:LMH6702MF +Amplifier_Operational:LMH6733 +Amplifier_Operational:LMV321 +Amplifier_Operational:LMV324 +Amplifier_Operational:LMV358 +Amplifier_Operational:LMV601 +Amplifier_Operational:LOG114AxRGV +Amplifier_Operational:LPV811DBV +Amplifier_Operational:LPV812DGK +Amplifier_Operational:LT1012 +Amplifier_Operational:LT1363 +Amplifier_Operational:LT1492 +Amplifier_Operational:LT1493 +Amplifier_Operational:LT6015xS5 +Amplifier_Operational:LT6230xS6 +Amplifier_Operational:LT6234 +Amplifier_Operational:LT6237 +Amplifier_Operational:LTC1151CN8 +Amplifier_Operational:LTC1151CSW +Amplifier_Operational:LTC1152 +Amplifier_Operational:LTC6081xDD +Amplifier_Operational:LTC6081xMS8 +Amplifier_Operational:LTC6082xDHC +Amplifier_Operational:LTC6082xGN +Amplifier_Operational:LTC6228xDC +Amplifier_Operational:LTC6228xS6 +Amplifier_Operational:LTC6228xS8 +Amplifier_Operational:LTC6229xDD +Amplifier_Operational:LTC6229xMS8E +Amplifier_Operational:LTC6253xMS8 +Amplifier_Operational:LTC6268xS6-10 +Amplifier_Operational:LTC6268xS8-10 +Amplifier_Operational:LTC6269xDD +Amplifier_Operational:LTC6269xMS8E +Amplifier_Operational:LTC6362xDD +Amplifier_Operational:LTC6362xMS8 +Amplifier_Operational:MAX4238ASA +Amplifier_Operational:MAX4238AUT +Amplifier_Operational:MAX4239ASA +Amplifier_Operational:MAX4239AUT +Amplifier_Operational:MAX4395ESD +Amplifier_Operational:MAX4395EUD +Amplifier_Operational:MC33078 +Amplifier_Operational:MC33079 +Amplifier_Operational:MC33172 +Amplifier_Operational:MC33174 +Amplifier_Operational:MC33178 +Amplifier_Operational:MC33179 +Amplifier_Operational:MCP6001-OT +Amplifier_Operational:MCP6001R +Amplifier_Operational:MCP6001U +Amplifier_Operational:MCP6001x-LT +Amplifier_Operational:MCP6002-xMC +Amplifier_Operational:MCP6002-xMS +Amplifier_Operational:MCP6002-xP +Amplifier_Operational:MCP6002-xSN +Amplifier_Operational:MCP6004 +Amplifier_Operational:MCP601-xOT +Amplifier_Operational:MCP601-xP +Amplifier_Operational:MCP601-xSN +Amplifier_Operational:MCP601-xST +Amplifier_Operational:MCP601R +Amplifier_Operational:MCP602 +Amplifier_Operational:MCP6022 +Amplifier_Operational:MCP603-xCH +Amplifier_Operational:MCP603-xP +Amplifier_Operational:MCP603-xSN +Amplifier_Operational:MCP603-xST +Amplifier_Operational:MCP604 +Amplifier_Operational:MCP6401RT-xOT +Amplifier_Operational:MCP6401T-xLT +Amplifier_Operational:MCP6401T-xOT +Amplifier_Operational:MCP6401UT-xOT +Amplifier_Operational:MCP6L01Rx-xOT +Amplifier_Operational:MCP6L01Ux-xOT +Amplifier_Operational:MCP6L01x-xLT +Amplifier_Operational:MCP6L01x-xOT +Amplifier_Operational:MCP6L02x-xMS +Amplifier_Operational:MCP6L02x-xSN +Amplifier_Operational:MCP6L04-xST +Amplifier_Operational:MCP6L04x-xSL +Amplifier_Operational:MCP6L91RT-EOT +Amplifier_Operational:MCP6L91T-EOT +Amplifier_Operational:MCP6L92 +Amplifier_Operational:MCP6L94 +Amplifier_Operational:MCP6V67EMS +Amplifier_Operational:MCP6V67xMNY +Amplifier_Operational:NCS20071SN +Amplifier_Operational:NCS20071XV +Amplifier_Operational:NCS20072D +Amplifier_Operational:NCS20072DM +Amplifier_Operational:NCS20072DTB +Amplifier_Operational:NCS20074D +Amplifier_Operational:NCS20074DTB +Amplifier_Operational:NCS2325D +Amplifier_Operational:NCS2325DM +Amplifier_Operational:NCS325 +Amplifier_Operational:NCS4325 +Amplifier_Operational:NE5532 +Amplifier_Operational:NE5534 +Amplifier_Operational:NJM2043 +Amplifier_Operational:NJM2114 +Amplifier_Operational:NJM4556A +Amplifier_Operational:NJM4558 +Amplifier_Operational:NJM4559 +Amplifier_Operational:NJM4560 +Amplifier_Operational:NJM4580 +Amplifier_Operational:NJM5532 +Amplifier_Operational:OP07 +Amplifier_Operational:OP1177AR +Amplifier_Operational:OP1177ARM +Amplifier_Operational:OP179GRT +Amplifier_Operational:OP179GS +Amplifier_Operational:OP249 +Amplifier_Operational:OP249GS +Amplifier_Operational:OP275 +Amplifier_Operational:OP279 +Amplifier_Operational:OP77 +Amplifier_Operational:OPA121KM +Amplifier_Operational:OPA121KP +Amplifier_Operational:OPA121KU +Amplifier_Operational:OPA134 +Amplifier_Operational:OPA1602 +Amplifier_Operational:OPA1604 +Amplifier_Operational:OPA1612AxD +Amplifier_Operational:OPA1641 +Amplifier_Operational:OPA1655D +Amplifier_Operational:OPA1655DBV +Amplifier_Operational:OPA1656ID +Amplifier_Operational:OPA1678 +Amplifier_Operational:OPA1679 +Amplifier_Operational:OPA1692xD +Amplifier_Operational:OPA1692xDGK +Amplifier_Operational:OPA188xxD +Amplifier_Operational:OPA188xxDBV +Amplifier_Operational:OPA196xD +Amplifier_Operational:OPA196xDBV +Amplifier_Operational:OPA196xDGK +Amplifier_Operational:OPA197xD +Amplifier_Operational:OPA197xDBV +Amplifier_Operational:OPA197xDGK +Amplifier_Operational:OPA2134 +Amplifier_Operational:OPA2156xD +Amplifier_Operational:OPA2156xDGK +Amplifier_Operational:OPA2196xD +Amplifier_Operational:OPA2196xDGK +Amplifier_Operational:OPA2197xD +Amplifier_Operational:OPA2197xDGK +Amplifier_Operational:OPA2277 +Amplifier_Operational:OPA2325 +Amplifier_Operational:OPA2333xxD +Amplifier_Operational:OPA2333xxDGK +Amplifier_Operational:OPA2333xxDRB +Amplifier_Operational:OPA2340 +Amplifier_Operational:OPA2356xxD +Amplifier_Operational:OPA2356xxDGK +Amplifier_Operational:OPA2376xxD +Amplifier_Operational:OPA2376xxDGK +Amplifier_Operational:OPA2376xxYZD +Amplifier_Operational:OPA2604AP +Amplifier_Operational:OPA2691 +Amplifier_Operational:OPA2691-14 +Amplifier_Operational:OPA2695xD +Amplifier_Operational:OPA2695xRGT +Amplifier_Operational:OPA2890ID +Amplifier_Operational:OPA2890IDGS +Amplifier_Operational:OPA2994xD +Amplifier_Operational:OPA310SxDBV +Amplifier_Operational:OPA310SxDCK +Amplifier_Operational:OPA310xDBV +Amplifier_Operational:OPA310xDCK +Amplifier_Operational:OPA330xxD +Amplifier_Operational:OPA330xxDBV +Amplifier_Operational:OPA330xxDCK +Amplifier_Operational:OPA330xxYFF +Amplifier_Operational:OPA333xxD +Amplifier_Operational:OPA333xxDBV +Amplifier_Operational:OPA333xxDCK +Amplifier_Operational:OPA336Nx +Amplifier_Operational:OPA336Ux +Amplifier_Operational:OPA340NA +Amplifier_Operational:OPA340P +Amplifier_Operational:OPA340UA +Amplifier_Operational:OPA355NA +Amplifier_Operational:OPA356xxD +Amplifier_Operational:OPA356xxDBV +Amplifier_Operational:OPA365xxD +Amplifier_Operational:OPA365xxDBV +Amplifier_Operational:OPA376xxD +Amplifier_Operational:OPA376xxDBV +Amplifier_Operational:OPA376xxDCK +Amplifier_Operational:OPA4134 +Amplifier_Operational:OPA4196xD +Amplifier_Operational:OPA4196xPW +Amplifier_Operational:OPA4197xD +Amplifier_Operational:OPA4197xPW +Amplifier_Operational:OPA4340EA +Amplifier_Operational:OPA4340UA +Amplifier_Operational:OPA4376 +Amplifier_Operational:OPA551P +Amplifier_Operational:OPA551U +Amplifier_Operational:OPA552P +Amplifier_Operational:OPA552U +Amplifier_Operational:OPA569DWP +Amplifier_Operational:OPA690xD +Amplifier_Operational:OPA690xDBV +Amplifier_Operational:OPA810xD +Amplifier_Operational:OPA810xDBV +Amplifier_Operational:OPA810xDCK +Amplifier_Operational:OPA818xDRG +Amplifier_Operational:OPA842xD +Amplifier_Operational:OPA842xDBV +Amplifier_Operational:OPA843xD +Amplifier_Operational:OPA843xDBV +Amplifier_Operational:OPA846xD +Amplifier_Operational:OPA846xDBV +Amplifier_Operational:OPA847xD +Amplifier_Operational:OPA847xDBV +Amplifier_Operational:OPA855xDSG +Amplifier_Operational:OPA858xDSG +Amplifier_Operational:OPA859xDSG +Amplifier_Operational:OPA890xD +Amplifier_Operational:OPA890xDBV +Amplifier_Operational:RC4558 +Amplifier_Operational:RC4560 +Amplifier_Operational:RC4580 +Amplifier_Operational:SA5532 +Amplifier_Operational:SA5534 +Amplifier_Operational:THS3491xDDA +Amplifier_Operational:THS4631D +Amplifier_Operational:THS4631DDA +Amplifier_Operational:THS4631DGN +Amplifier_Operational:TL061 +Amplifier_Operational:TL062 +Amplifier_Operational:TL064 +Amplifier_Operational:TL071 +Amplifier_Operational:TL072 +Amplifier_Operational:TL074 +Amplifier_Operational:TL081 +Amplifier_Operational:TL082 +Amplifier_Operational:TL084 +Amplifier_Operational:TLC272 +Amplifier_Operational:TLC274 +Amplifier_Operational:TLC277 +Amplifier_Operational:TLC279 +Amplifier_Operational:TLC27M2xD +Amplifier_Operational:TLC27M2xPS +Amplifier_Operational:TLC27M2xPW +Amplifier_Operational:TLC27M7xD +Amplifier_Operational:TLC27M7xPS +Amplifier_Operational:TLE2141ACD +Amplifier_Operational:TLE2141ACP +Amplifier_Operational:TLE2141AID +Amplifier_Operational:TLE2141AIP +Amplifier_Operational:TLE2141CD +Amplifier_Operational:TLE2141CP +Amplifier_Operational:TLE2141ID +Amplifier_Operational:TLE2141IP +Amplifier_Operational:TLE2141MD +Amplifier_Operational:TLV172IDCK +Amplifier_Operational:TLV2371D +Amplifier_Operational:TLV2371DBV +Amplifier_Operational:TLV2371P +Amplifier_Operational:TLV2372 +Amplifier_Operational:TLV6001DCK +Amplifier_Operational:TLV9001IDCK +Amplifier_Operational:TLV9004xRUCR +Amplifier_Operational:TLV9061xDBV +Amplifier_Operational:TLV9061xDCK +Amplifier_Operational:TLV9061xDPW +Amplifier_Operational:TLV9062 +Amplifier_Operational:TLV9062xD +Amplifier_Operational:TLV9062xDSG +Amplifier_Operational:TLV9064 +Amplifier_Operational:TLV9064xRTE +Amplifier_Operational:TLV9301xDBV +Amplifier_Operational:TLV9301xDCK +Amplifier_Operational:TLV9302xD +Amplifier_Operational:TLV9302xDDF +Amplifier_Operational:TLV9302xDGK +Amplifier_Operational:TLV9302xPW +Amplifier_Operational:TLV9304xD +Amplifier_Operational:TLV9304xPW +Amplifier_Operational:TS881xCx +Amplifier_Operational:TS881xLx +Amplifier_Operational:TS912 +Amplifier_Operational:TSV524xIQ4T +Amplifier_Operational:TSV911IDT +Amplifier_Operational:TSV911RILT +Amplifier_Operational:TSV911xxLx +Amplifier_Operational:TSV912IDT +Amplifier_Operational:TSV912IQ2T +Amplifier_Operational:TSV912IST +Amplifier_Operational:TSV914 +Amplifier_Operational:TSV991AILT +Amplifier_Operational:TSV991AIQ1T +Amplifier_Operational:TSV994 +Amplifier_Video:AD813 +Amplifier_Video:MAX453 +Amplifier_Video:THS7374 +Analog:AD5593R +Analog:AD630ARZ +Analog:AD637xQ +Analog:AD637xRZ +Analog:AD654JN +Analog:AD654JR +Analog:LF398H +Analog:LF398_DIP8 +Analog:LF398_SOIC14 +Analog:LF398_SOIC8 +Analog:LM231N +Analog:LM331N +Analog:LTC1966 +Analog:LTC1967 +Analog:LTC1968 +Analog:MLX90314xDF +Analog:MLX90320xFR +Analog:MPY634KP +Analog:MPY634KU +Analog:PGA112 +Analog:PGA113 +Analog_ADC:AD40xxBCPZ +Analog_ADC:AD40xxBRMZ +Analog_ADC:AD574A +Analog_ADC:AD6644 +Analog_ADC:AD6645 +Analog_ADC:AD7171 +Analog_ADC:AD7298 +Analog_ADC:AD7321 +Analog_ADC:AD7322 +Analog_ADC:AD7323 +Analog_ADC:AD7324 +Analog_ADC:AD7327 +Analog_ADC:AD7328 +Analog_ADC:AD7329 +Analog_ADC:AD7606 +Analog_ADC:AD7606-4 +Analog_ADC:AD7606-6 +Analog_ADC:AD7616 +Analog_ADC:AD7682BCP +Analog_ADC:AD7689xCP +Analog_ADC:AD7699BCP +Analog_ADC:AD7722 +Analog_ADC:AD7745 +Analog_ADC:AD7746 +Analog_ADC:AD7794 +Analog_ADC:AD7795 +Analog_ADC:AD7819 +Analog_ADC:AD7949BCP +Analog_ADC:AD9280ARS +Analog_ADC:AD9283 +Analog_ADC:ADC0800 +Analog_ADC:ADC08060 +Analog_ADC:ADC081C021CIMM +Analog_ADC:ADC0832 +Analog_ADC:ADC101C021CIMK +Analog_ADC:ADC101C021CIMM +Analog_ADC:ADC1173 +Analog_ADC:ADC121C021CIMM +Analog_ADC:ADC1283 +Analog_ADC:ADC128D818 +Analog_ADC:ADS1013IDGS +Analog_ADC:ADS1014IDGS +Analog_ADC:ADS1015IDGS +Analog_ADC:ADS1018IDGS +Analog_ADC:ADS1110 +Analog_ADC:ADS1113IDGS +Analog_ADC:ADS1114IDGS +Analog_ADC:ADS1115IDGS +Analog_ADC:ADS1118IDGS +Analog_ADC:ADS1120-PW +Analog_ADC:ADS1120-RVA +Analog_ADC:ADS1220xPW +Analog_ADC:ADS1232IPW +Analog_ADC:ADS1234IPW +Analog_ADC:ADS1243 +Analog_ADC:ADS1251 +Analog_ADC:ADS127L01IPBS +Analog_ADC:ADS1298xPAG +Analog_ADC:ADS7029 +Analog_ADC:ADS7039 +Analog_ADC:ADS7040xDCU +Analog_ADC:ADS7041xDCU +Analog_ADC:ADS7042xDCU +Analog_ADC:ADS7043xDCU +Analog_ADC:ADS7044xDCU +Analog_ADC:ADS7049 +Analog_ADC:ADS7828 +Analog_ADC:ADS7866 +Analog_ADC:ADS7867 +Analog_ADC:ADS7868 +Analog_ADC:ADS8681RUM +Analog_ADC:ADS8684 +Analog_ADC:ADS8685RUM +Analog_ADC:ADS8688 +Analog_ADC:ADS8689RUM +Analog_ADC:AMC3336 +Analog_ADC:CA3300 +Analog_ADC:HX711 +Analog_ADC:ICL7106CPL +Analog_ADC:ICL7107CPL +Analog_ADC:INA234AxYBJ +Analog_ADC:LTC1406CGN +Analog_ADC:LTC1406IGN +Analog_ADC:LTC1594CS +Analog_ADC:LTC1594IS +Analog_ADC:LTC1598CG +Analog_ADC:LTC1598IG +Analog_ADC:LTC1742 +Analog_ADC:LTC1744 +Analog_ADC:LTC1746 +Analog_ADC:LTC1748 +Analog_ADC:LTC1864 +Analog_ADC:LTC1864L +Analog_ADC:LTC1865-MS +Analog_ADC:LTC1865-S8 +Analog_ADC:LTC1865L-MS +Analog_ADC:LTC1865L-S8 +Analog_ADC:LTC2282xUP +Analog_ADC:LTC2284xUP +Analog_ADC:LTC2290xUP +Analog_ADC:LTC2291xUP +Analog_ADC:LTC2292xUP +Analog_ADC:LTC2293xUP +Analog_ADC:LTC2294xUP +Analog_ADC:LTC2295xUP +Analog_ADC:LTC2296xUP +Analog_ADC:LTC2297xUP +Analog_ADC:LTC2298xUP +Analog_ADC:LTC2299xUP +Analog_ADC:LTC2309xF +Analog_ADC:LTC2309xUF +Analog_ADC:LTC2311-16 +Analog_ADC:LTC2325-16 +Analog_ADC:LTC2358-16 +Analog_ADC:LTC2358-18 +Analog_ADC:LTC2451xDDB +Analog_ADC:LTC2451xTS8 +Analog_ADC:LTC2508CDKD-32 +Analog_ADC:LTC2508IDKD-32 +Analog_ADC:MAX1112 +Analog_ADC:MAX11120xTI +Analog_ADC:MAX11121xTI +Analog_ADC:MAX11122xTI +Analog_ADC:MAX11123xTI +Analog_ADC:MAX11124xTI +Analog_ADC:MAX11125xTI +Analog_ADC:MAX11126xTI +Analog_ADC:MAX11127xTI +Analog_ADC:MAX11128xTI +Analog_ADC:MAX1113 +Analog_ADC:MAX11612 +Analog_ADC:MAX11613 +Analog_ADC:MAX11614 +Analog_ADC:MAX11615 +Analog_ADC:MAX11616 +Analog_ADC:MAX11617 +Analog_ADC:MAX1248 +Analog_ADC:MAX1249 +Analog_ADC:MAX1274 +Analog_ADC:MAX1275 +Analog_ADC:MCP3002 +Analog_ADC:MCP3004 +Analog_ADC:MCP3008 +Analog_ADC:MCP3201 +Analog_ADC:MCP3202 +Analog_ADC:MCP3204 +Analog_ADC:MCP3208 +Analog_ADC:MCP3221 +Analog_ADC:MCP3301 +Analog_ADC:MCP3421A0T-ECH +Analog_ADC:MCP3422Axx-xMS +Analog_ADC:MCP3422Axx-xSN +Analog_ADC:MCP3423x-xUN +Analog_ADC:MCP3424x-xSL +Analog_ADC:MCP3424x-xST +Analog_ADC:MCP3425Axx-xCH +Analog_ADC:MCP3426Axx-xMC +Analog_ADC:MCP3426Axx-xMS +Analog_ADC:MCP3426Axx-xSN +Analog_ADC:MCP3427x-xMF +Analog_ADC:MCP3427x-xUN +Analog_ADC:MCP3428x-xSL +Analog_ADC:MCP3428x-xST +Analog_ADC:MCP3550-50-EMS +Analog_ADC:MCP3550-60-ESN +Analog_ADC:MCP3551-EMS +Analog_ADC:MCP3553-ESN +Analog_DAC:AD390JD +Analog_DAC:AD390KD +Analog_DAC:AD558JN +Analog_DAC:AD558JP +Analog_DAC:AD558KN +Analog_DAC:AD558KP +Analog_DAC:AD5687BCPZ +Analog_DAC:AD5687BRUZ +Analog_DAC:AD5687RBCPZ +Analog_DAC:AD5687RBRUZ +Analog_DAC:AD5689BCPZ +Analog_DAC:AD5689BRUZ +Analog_DAC:AD5689RxCPZ +Analog_DAC:AD5689RxRUZ +Analog_DAC:AD5691RxRM +Analog_DAC:AD5692RxRM +Analog_DAC:AD5693RxRM +Analog_DAC:AD5697RBCPZ +Analog_DAC:AD5697RBRUZ +Analog_DAC:AD5781xRUZ +Analog_DAC:AD5791xRUZ +Analog_DAC:AD7224KN +Analog_DAC:AD7224KP +Analog_DAC:AD7224KR-1 +Analog_DAC:AD7224KR-18 +Analog_DAC:AD7224LN +Analog_DAC:AD7224LP +Analog_DAC:AD7224LR-1 +Analog_DAC:AD7224LR-18 +Analog_DAC:AD7225BRS +Analog_DAC:AD7225CRS +Analog_DAC:AD7225KN +Analog_DAC:AD7225KP +Analog_DAC:AD7225KR +Analog_DAC:AD7225LN +Analog_DAC:AD7225LP +Analog_DAC:AD7225LR +Analog_DAC:AD7226BRSZ +Analog_DAC:AD7226KN +Analog_DAC:AD7226KP +Analog_DAC:AD7226KR +Analog_DAC:AD7228ABN +Analog_DAC:AD7228ABP +Analog_DAC:AD7228ABR +Analog_DAC:AD7228ACN +Analog_DAC:AD7228ACP +Analog_DAC:AD7228ACR +Analog_DAC:AD7304 +Analog_DAC:AD7305 +Analog_DAC:AD7390 +Analog_DAC:AD7391 +Analog_DAC:AD7533JN +Analog_DAC:AD7533JP +Analog_DAC:AD7533KN +Analog_DAC:AD7533KP +Analog_DAC:AD7533KR +Analog_DAC:AD7533LN +Analog_DAC:AD775 +Analog_DAC:AD9106BCP +Analog_DAC:AD9142 +Analog_DAC:AD9744 +Analog_DAC:ADS7830 +Analog_DAC:CS434x-xZZ +Analog_DAC:DAC08 +Analog_DAC:DAC0808_DIP +Analog_DAC:DAC0808_SOIC +Analog_DAC:DAC081C081CIMK +Analog_DAC:DAC1006LCN +Analog_DAC:DAC1006LCWM +Analog_DAC:DAC1007LCN +Analog_DAC:DAC1008LCN +Analog_DAC:DAC101C081CIMK +Analog_DAC:DAC121C081CIMK +Analog_DAC:DAC1220E +Analog_DAC:DAC5311xDCK +Analog_DAC:DAC5578xPW +Analog_DAC:DAC5578xRGE +Analog_DAC:DAC60502 +Analog_DAC:DAC60504 +Analog_DAC:DAC6311xDCK +Analog_DAC:DAC6578xPW +Analog_DAC:DAC6578xRGE +Analog_DAC:DAC70502 +Analog_DAC:DAC70504 +Analog_DAC:DAC7311xDCK +Analog_DAC:DAC7513_DCN +Analog_DAC:DAC7565 +Analog_DAC:DAC7578xPW +Analog_DAC:DAC7578xRGE +Analog_DAC:DAC7750xRHA +Analog_DAC:DAC80502 +Analog_DAC:DAC80504 +Analog_DAC:DAC8165 +Analog_DAC:DAC8501E +Analog_DAC:DAC8531E +Analog_DAC:DAC8531IDRB +Analog_DAC:DAC8550IxDGK +Analog_DAC:DAC8551IxDGK +Analog_DAC:DAC8552 +Analog_DAC:DAC8560IxDGK +Analog_DAC:DAC8565 +Analog_DAC:DAC8571IDGK +Analog_DAC:DAC8750xRHA +Analog_DAC:LTC1257 +Analog_DAC:LTC1446 +Analog_DAC:LTC1446L +Analog_DAC:LTC1664CGN +Analog_DAC:LTC1664CN +Analog_DAC:LTC1664IGN +Analog_DAC:LTC1664IN +Analog_DAC:MAX5138 +Analog_DAC:MAX5139 +Analog_DAC:MAX5215 +Analog_DAC:MAX5217 +Analog_DAC:MAX5717xSD +Analog_DAC:MAX5719xSD +Analog_DAC:MAX5741 +Analog_DAC:MAX5813 +Analog_DAC:MAX5813WLP +Analog_DAC:MAX5814 +Analog_DAC:MAX5814WLP +Analog_DAC:MAX5815 +Analog_DAC:MAX5815WLP +Analog_DAC:MC1408_DIP +Analog_DAC:MC1408_SOIC +Analog_DAC:MCP4725xxx-xCH +Analog_DAC:MCP4728 +Analog_DAC:MCP4801 +Analog_DAC:MCP4801-EMC +Analog_DAC:MCP4802 +Analog_DAC:MCP4811 +Analog_DAC:MCP4811-EMC +Analog_DAC:MCP4812 +Analog_DAC:MCP4821 +Analog_DAC:MCP4821-EMC +Analog_DAC:MCP4822 +Analog_DAC:MCP4901 +Analog_DAC:MCP4901-EMC +Analog_DAC:MCP4902 +Analog_DAC:MCP4911 +Analog_DAC:MCP4911-EMC +Analog_DAC:MCP4912 +Analog_DAC:MCP4921 +Analog_DAC:MCP4921-EMC +Analog_DAC:MCP4921-EMS +Analog_DAC:MCP4921-EP +Analog_DAC:MCP4921-ESN +Analog_DAC:MCP4922 +Analog_DAC:MCP4922-EP +Analog_DAC:MCP4922-ESL +Analog_DAC:MCP4922-EST +Analog_DAC:THS5641AxDW +Analog_DAC:THS5641AxPW +Analog_DAC:TLV5627CD +Analog_DAC:TLV5627CPW +Analog_Switch:ADG1207BCPZ +Analog_Switch:ADG1408YRUZ +Analog_Switch:ADG1414BRU +Analog_Switch:ADG1607xCP +Analog_Switch:ADG417BN +Analog_Switch:ADG417BR +Analog_Switch:ADG419BN +Analog_Switch:ADG419BR +Analog_Switch:ADG419BRM +Analog_Switch:ADG633YCP +Analog_Switch:ADG633YRU +Analog_Switch:ADG658YCP +Analog_Switch:ADG707BRU +Analog_Switch:ADG715 +Analog_Switch:ADG728 +Analog_Switch:ADG729 +Analog_Switch:ADG733BRQ +Analog_Switch:ADG733BRU +Analog_Switch:ADG734 +Analog_Switch:ADG758CPZ +Analog_Switch:ADG824BCP +Analog_Switch:ADG884xCP +Analog_Switch:ADG884xRM +Analog_Switch:CBTL02043A +Analog_Switch:CBTL02043B +Analog_Switch:CD4051B +Analog_Switch:CD4052B +Analog_Switch:CD4053B +Analog_Switch:CD4066BE +Analog_Switch:CD4066BM +Analog_Switch:CD4066BNS +Analog_Switch:CD4066BPW +Analog_Switch:CD4097B +Analog_Switch:DG308AxJ +Analog_Switch:DG308AxY +Analog_Switch:DG309xJ +Analog_Switch:DG309xY +Analog_Switch:DG411xJ +Analog_Switch:DG411xUE +Analog_Switch:DG411xY +Analog_Switch:DG412xJ +Analog_Switch:DG412xUE +Analog_Switch:DG412xY +Analog_Switch:DG413xJ +Analog_Switch:DG413xUE +Analog_Switch:DG413xY +Analog_Switch:DG417LDJ +Analog_Switch:DG417LDJ_Maxim +Analog_Switch:DG417LDY +Analog_Switch:DG417LDY_Maxim +Analog_Switch:DG417LEUA +Analog_Switch:DG417LEUA_Maxim +Analog_Switch:DG417xJ +Analog_Switch:DG417xY +Analog_Switch:DG418LDJ +Analog_Switch:DG418LDJ_Maxim +Analog_Switch:DG418LDY +Analog_Switch:DG418LDY_Maxim +Analog_Switch:DG418LEUA +Analog_Switch:DG418LEUA_Maxim +Analog_Switch:DG418xJ +Analog_Switch:DG418xY +Analog_Switch:DG419LDJ +Analog_Switch:DG419LDJ_Maxim +Analog_Switch:DG419LDY +Analog_Switch:DG419LDY_Maxim +Analog_Switch:DG419LEUA +Analog_Switch:DG419LEUA_Maxim +Analog_Switch:DG419xJ +Analog_Switch:DG419xY +Analog_Switch:DG441xJ +Analog_Switch:DG441xY +Analog_Switch:DG442xJ +Analog_Switch:DG442xY +Analog_Switch:DG884DN +Analog_Switch:DG9421DV +Analog_Switch:DG9422DV +Analog_Switch:FSA3157L6X +Analog_Switch:FSA3157P6X +Analog_Switch:HEF4066BT +Analog_Switch:HI524 +Analog_Switch:MAX14662 +Analog_Switch:MAX14759 +Analog_Switch:MAX14761 +Analog_Switch:MAX14778 +Analog_Switch:MAX312CPE +Analog_Switch:MAX312CSE +Analog_Switch:MAX312CUE +Analog_Switch:MAX313CPE +Analog_Switch:MAX313CSE +Analog_Switch:MAX313CUE +Analog_Switch:MAX314CPE +Analog_Switch:MAX314CSE +Analog_Switch:MAX314CUE +Analog_Switch:MAX317xPA +Analog_Switch:MAX317xSA +Analog_Switch:MAX318xPA +Analog_Switch:MAX318xSA +Analog_Switch:MAX319xPA +Analog_Switch:MAX319xSA +Analog_Switch:MAX323CPA +Analog_Switch:MAX323CSA +Analog_Switch:MAX323CUA +Analog_Switch:MAX324CPA +Analog_Switch:MAX324CSA +Analog_Switch:MAX324CUA +Analog_Switch:MAX325CPA +Analog_Switch:MAX325CSA +Analog_Switch:MAX325CUA +Analog_Switch:MAX333 +Analog_Switch:MAX333A +Analog_Switch:MAX394 +Analog_Switch:MAX40200ANS +Analog_Switch:MAX40200AUK +Analog_Switch:NC7SB3157L6X +Analog_Switch:NC7SB3157P6X +Analog_Switch:NX3L4051HR +Analog_Switch:NX3L4051PW +Analog_Switch:SN74CBT3253 +Analog_Switch:TMUX1101DBV +Analog_Switch:TMUX1101DCK +Analog_Switch:TMUX1102DBV +Analog_Switch:TMUX1102DCK +Analog_Switch:TMUX1108PW +Analog_Switch:TMUX154EDGS +Analog_Switch:TMUX154ERSW +Analog_Switch:TS3A24159DGS +Analog_Switch:TS3A24159DRC +Analog_Switch:TS3A24159YZP +Analog_Switch:TS3A27518EPW +Analog_Switch:TS3A27518ERTW +Analog_Switch:TS3A5017RGY +Analog_Switch:TS3A5017RSV +Analog_Switch:TS3A5223RSW +Analog_Switch:TS3DS10224RUK +Analog_Switch:TS3L501ERUA +Analog_Switch:TS5A23159DGS +Analog_Switch:TS5A23159RSE +Analog_Switch:TS5A3159ADBVR +Analog_Switch:TS5A3159ADCK +Analog_Switch:TS5A3159AYZPR +Analog_Switch:TS5A3159DBV +Analog_Switch:TS5A3159DCK +Analog_Switch:TS5A3160DBV +Analog_Switch:TS5A3160DCK +Analog_Switch:TS5A3166DBVR +Analog_Switch:TS5A3166DCKR +Analog_Switch:TS5A63157DBV +Audio:AD1853 +Audio:AD1855 +Audio:AD1955 +Audio:ADAU1978xBCP +Audio:ADAU1979xBCP +Audio:AK5392VS +Audio:AK5393VS +Audio:AK5394AVS +Audio:AK5720VT +Audio:AK7742EQ +Audio:AS3310 +Audio:AS3320 +Audio:AS3320F +Audio:AS3330 +Audio:AS3330F +Audio:AS3340 +Audio:AS3345 +Audio:AS3345F +Audio:AS3360 +Audio:CS4245 +Audio:CS4265 +Audio:CS4270 +Audio:CS4272 +Audio:CS4334 +Audio:CS4344 +Audio:CS4345 +Audio:CS4348 +Audio:CS43L21 +Audio:CS5343 +Audio:CS5344 +Audio:CS5361 +Audio:CS8406 +Audio:CS8414 +Audio:CS8416-xNZ +Audio:CS8416-xSZ +Audio:CS8416-xZZ +Audio:CS8420 +Audio:DSD1794A +Audio:ISD25120P +Audio:ISD25120S +Audio:ISD2560E +Audio:ISD2560P +Audio:ISD2560S +Audio:ISD2575E +Audio:ISD2575P +Audio:ISD2575S +Audio:ISD2590E +Audio:ISD2590P +Audio:ISD2590S +Audio:MAX98357A +Audio:MAX98357B +Audio:MN3005 +Audio:MN3007 +Audio:MN3207 +Audio:MSGEQ7 +Audio:PCM1754DBQ +Audio:PCM1780 +Audio:PCM1792A +Audio:PCM1794A +Audio:PCM2902 +Audio:PCM3060 +Audio:PCM5100 +Audio:PCM5100A +Audio:PCM5101 +Audio:PCM5101A +Audio:PCM5102 +Audio:PCM5102A +Audio:PCM5121PW +Audio:PCM5122PW +Audio:PGA2310PA +Audio:PGA2310UA +Audio:PGA2500 +Audio:PGA4311 +Audio:PT2258 +Audio:PT2258-S +Audio:PT2399 +Audio:RD5106A +Audio:RD5107A +Audio:RE46C317 +Audio:RE46C318 +Audio:SAD1024 +Audio:SAD512 +Audio:SGTL5000XNAA3 +Audio:SGTL5000XNLA3 +Audio:SPN1001 +Audio:SRC4392xPFB +Audio:SSI2144 +Audio:SSI2164 +Audio:TDA1022 +Audio:THAT1580 +Audio:THAT1583 +Audio:THAT5171 +Audio:THAT5173 +Audio:THAT5263 +Audio:THAT6261 +Audio:THAT6262 +Audio:THAT6263 +Audio:TLV320AIC23BPW +Audio:TLV320AIC23BRHD +Audio:TLV320AIC23BxQE +Audio:TLV320AIC3100 +Audio:TPA5050 +Audio:UDA1334ATS +Audio:WM8731CLSEFL +Audio:WM8731CSEFL +Audio:WM8731SEDS +Audio:YM2149 +Battery_Management:ADP5063 +Battery_Management:ADP5090ACP +Battery_Management:ADP5091 +Battery_Management:ADP5092 +Battery_Management:AP9101CK +Battery_Management:AP9101CK6 +Battery_Management:APW7261 +Battery_Management:AS8506C +Battery_Management:BQ2003 +Battery_Management:BQ21040DBV +Battery_Management:BQ24004 +Battery_Management:BQ24005 +Battery_Management:BQ24006 +Battery_Management:BQ24012 +Battery_Management:BQ24013 +Battery_Management:BQ24072RGT +Battery_Management:BQ24073RGT +Battery_Management:BQ24074RGT +Battery_Management:BQ24075RGT +Battery_Management:BQ24079RGT +Battery_Management:BQ24090DGQ +Battery_Management:BQ24133RGY +Battery_Management:BQ24166RGE +Battery_Management:BQ24167RGE +Battery_Management:BQ24610 +Battery_Management:BQ24617 +Battery_Management:BQ24650 +Battery_Management:BQ2501x +Battery_Management:BQ25040 +Battery_Management:BQ25173DSG +Battery_Management:BQ25504 +Battery_Management:BQ25570 +Battery_Management:BQ25601 +Battery_Management:BQ25886RGE +Battery_Management:BQ25887 +Battery_Management:BQ25895RTW +Battery_Management:BQ27441-G1 +Battery_Management:BQ27441DRZR-G1A +Battery_Management:BQ27441DRZR-G1B +Battery_Management:BQ27441DRZT-G1A +Battery_Management:BQ27441DRZT-G1B +Battery_Management:BQ27750 +Battery_Management:BQ297xy +Battery_Management:BQ51050BRHL +Battery_Management:BQ51050BYFP +Battery_Management:BQ51051BRHL +Battery_Management:BQ51051BYFP +Battery_Management:BQ51052BYFP +Battery_Management:BQ76200PW +Battery_Management:BQ76920PW +Battery_Management:BQ76930DBT +Battery_Management:BQ76940DBT +Battery_Management:BQ78350DBT +Battery_Management:BQ78350DBT-R1 +Battery_Management:DS2745U +Battery_Management:DW01A +Battery_Management:LC709203FQH-01TWG +Battery_Management:LC709203FQH-02TWG +Battery_Management:LC709203FQH-03TWG +Battery_Management:LC709203FQH-04TWG +Battery_Management:LGS5500EP +Battery_Management:LP3947 +Battery_Management:LT3652EDD +Battery_Management:LT3652EMSE +Battery_Management:LT3652IDD +Battery_Management:LT3652IMSE +Battery_Management:LTC2942 +Battery_Management:LTC2942-1 +Battery_Management:LTC2959 +Battery_Management:LTC3553 +Battery_Management:LTC3555 +Battery_Management:LTC3555-1 +Battery_Management:LTC3555-3 +Battery_Management:LTC4001 +Battery_Management:LTC4001-1 +Battery_Management:LTC4002EDD-4.2 +Battery_Management:LTC4002EDD-8.4 +Battery_Management:LTC4002ES8-4.2 +Battery_Management:LTC4002ES8-8.4 +Battery_Management:LTC4007 +Battery_Management:LTC4011CFE +Battery_Management:LTC4054ES5-4.2 +Battery_Management:LTC4054XES5-4.2 +Battery_Management:LTC4055 +Battery_Management:LTC4055-1 +Battery_Management:LTC4060EDHC +Battery_Management:LTC4060EFE +Battery_Management:LTC4067EDE +Battery_Management:LTC4156 +Battery_Management:LTC6803-2 +Battery_Management:LTC6803-4 +Battery_Management:LTC6804-1 +Battery_Management:MAX1647 +Battery_Management:MAX1648 +Battery_Management:MAX17261xxTD +Battery_Management:MAX17261xxWL +Battery_Management:MAX17263xxTE +Battery_Management:MAX1811 +Battery_Management:MAX1873REEE +Battery_Management:MAX1873SEEE +Battery_Management:MAX1873TEEE +Battery_Management:MAX712CPE +Battery_Management:MAX712CSE +Battery_Management:MAX712EPE +Battery_Management:MAX712ESE +Battery_Management:MAX712MJE +Battery_Management:MAX713CPE +Battery_Management:MAX713CSE +Battery_Management:MAX713EPE +Battery_Management:MAX713ESE +Battery_Management:MAX713MJE +Battery_Management:MC34673 +Battery_Management:MCP73811T-420I-OT +Battery_Management:MCP73811T-435I-OT +Battery_Management:MCP73812T-420I-OT +Battery_Management:MCP73812T-435I-OT +Battery_Management:MCP73831-2-MC +Battery_Management:MCP73831-2-OT +Battery_Management:MCP73831-3-MC +Battery_Management:MCP73831-3-OT +Battery_Management:MCP73831-4-MC +Battery_Management:MCP73831-4-OT +Battery_Management:MCP73831-5-MC +Battery_Management:MCP73831-5-OT +Battery_Management:MCP73832-2-MC +Battery_Management:MCP73832-2-OT +Battery_Management:MCP73832-3-MC +Battery_Management:MCP73832-3-OT +Battery_Management:MCP73832-4-MC +Battery_Management:MCP73832-4-OT +Battery_Management:MCP73832-5-MC +Battery_Management:MCP73832-5-OT +Battery_Management:MCP73833-xxx-MF +Battery_Management:MCP73833-xxx-UN +Battery_Management:MCP73871 +Battery_Management:MCP73871-1AA +Battery_Management:MCP73871-1CA +Battery_Management:MCP73871-1CC +Battery_Management:MCP73871-2AA +Battery_Management:MCP73871-2CA +Battery_Management:MCP73871-2CC +Battery_Management:MCP73871-3CA +Battery_Management:MCP73871-3CC +Battery_Management:MCP73871-4CA +Battery_Management:MCP73871-4CC +Battery_Management:SLM6800 +Battery_Management:TP4056-42-ESOP8 +Battery_Management:TP4057 +Buffer:CDCV304 +Buffer:PI6C5946002ZH +Comparator:AD8561 +Comparator:ADCMP350 +Comparator:ADCMP354 +Comparator:ADCMP356 +Comparator:LM2901 +Comparator:LM2903 +Comparator:LM311 +Comparator:LM319 +Comparator:LM319H +Comparator:LM339 +Comparator:LM393 +Comparator:LM397 +Comparator:LMH7324 +Comparator:LMV331 +Comparator:LMV339 +Comparator:LMV393 +Comparator:LMV7219M5 +Comparator:LMV7219M7 +Comparator:LMV7271 +Comparator:LMV7272 +Comparator:LMV7275 +Comparator:LP2901D +Comparator:LT1011 +Comparator:LT1016 +Comparator:LT1116 +Comparator:LT1711xMS8 +Comparator:LTC6752xMS8-2 +Comparator:LTC6752xS5 +Comparator:LTC6752xSC6-1 +Comparator:LTC6752xSC6-4 +Comparator:LTC6752xUD-3 +Comparator:LTC6754xSC6 +Comparator:LTC6754xUD +Comparator:MAX9031AU +Comparator:MAX9031AX +Comparator:MAX941xPA +Comparator:MAX941xSA +Comparator:MAX941xUA +Comparator:MCP6561-OT +Comparator:MCP6561R +Comparator:MCP6561U +Comparator:MCP6561x-LT +Comparator:MCP6562 +Comparator:MCP6566 +Comparator:MCP6566R +Comparator:MCP6566U +Comparator:MCP6567 +Comparator:MCP6569 +Comparator:MCP65R41 +Comparator:MCP65R46 +Comparator:MIC845H +Comparator:MIC845L +Comparator:MIC845N +Comparator:TL3116 +Comparator:TL331 +Comparator:TLV3501AID +Comparator:TLV3501AIDBV +Comparator:TLV7031DBV +Comparator:TLV7041DBV +Comparator:TLV7041DCK +Comparator:TLV7041SDCK +Connector:4P2C +Connector:4P2C_Shielded +Connector:4P4C +Connector:4P4C_Shielded +Connector:6P2C +Connector:6P2C_Shielded +Connector:6P4C +Connector:6P4C_Shielded +Connector:6P6C +Connector:6P6C_Shielded +Connector:8P4C +Connector:8P4C_Shielded +Connector:8P8C +Connector:8P8C_LED +Connector:8P8C_LED_Shielded +Connector:8P8C_LED_Shielded_x2 +Connector:8P8C_Shielded +Connector:ATX-20 +Connector:ATX-24 +Connector:AVR-ISP-10 +Connector:AVR-ISP-6 +Connector:AVR-JTAG-10 +Connector:AVR-PDI-6 +Connector:AVR-TPI-6 +Connector:AVR-UPDI-6 +Connector:Barrel_Jack +Connector:Barrel_Jack_MountingPin +Connector:Barrel_Jack_Switch +Connector:Barrel_Jack_Switch_MountingPin +Connector:Barrel_Jack_Switch_Pin3Ring +Connector:Bus_ISA_16bit +Connector:Bus_ISA_8bit +Connector:Bus_M.2_Socket_A +Connector:Bus_M.2_Socket_B +Connector:Bus_M.2_Socket_E +Connector:Bus_M.2_Socket_M +Connector:Bus_PCI_32bit_5V +Connector:Bus_PCI_32bit_Universal +Connector:Bus_PCI_Express_Mini +Connector:Bus_PCI_Express_x1 +Connector:Bus_PCI_Express_x16 +Connector:Bus_PCI_Express_x4 +Connector:Bus_PCI_Express_x8 +Connector:CUI_PD-30 +Connector:CUI_PD-30S +Connector:CoaxialSwitch_Testpoint +Connector:Conn_01x01_Pin +Connector:Conn_01x01_Socket +Connector:Conn_01x02_Pin +Connector:Conn_01x02_Socket +Connector:Conn_01x03_Pin +Connector:Conn_01x03_Socket +Connector:Conn_01x04_Pin +Connector:Conn_01x04_Socket +Connector:Conn_01x05_Pin +Connector:Conn_01x05_Socket +Connector:Conn_01x06_Pin +Connector:Conn_01x06_Socket +Connector:Conn_01x07_Pin +Connector:Conn_01x07_Socket +Connector:Conn_01x08_Pin +Connector:Conn_01x08_Socket +Connector:Conn_01x09_Pin +Connector:Conn_01x09_Socket +Connector:Conn_01x10_Pin +Connector:Conn_01x10_Socket +Connector:Conn_01x11_Pin +Connector:Conn_01x11_Socket +Connector:Conn_01x12_Pin +Connector:Conn_01x12_Socket +Connector:Conn_01x13_Pin +Connector:Conn_01x13_Socket +Connector:Conn_01x14_Pin +Connector:Conn_01x14_Socket +Connector:Conn_01x15_Pin +Connector:Conn_01x15_Socket +Connector:Conn_01x16_Pin +Connector:Conn_01x16_Socket +Connector:Conn_01x17_Pin +Connector:Conn_01x17_Socket +Connector:Conn_01x18_Pin +Connector:Conn_01x18_Socket +Connector:Conn_01x19_Pin +Connector:Conn_01x19_Socket +Connector:Conn_01x20_Pin +Connector:Conn_01x20_Socket +Connector:Conn_01x21_Pin +Connector:Conn_01x21_Socket +Connector:Conn_01x22_Pin +Connector:Conn_01x22_Socket +Connector:Conn_01x23_Pin +Connector:Conn_01x23_Socket +Connector:Conn_01x24_Pin +Connector:Conn_01x24_Socket +Connector:Conn_01x25_Pin +Connector:Conn_01x25_Socket +Connector:Conn_01x26_Pin +Connector:Conn_01x26_Socket +Connector:Conn_01x27_Pin +Connector:Conn_01x27_Socket +Connector:Conn_01x28_Pin +Connector:Conn_01x28_Socket +Connector:Conn_01x29_Pin +Connector:Conn_01x29_Socket +Connector:Conn_01x30_Pin +Connector:Conn_01x30_Socket +Connector:Conn_01x31_Pin +Connector:Conn_01x31_Socket +Connector:Conn_01x32_Pin +Connector:Conn_01x32_Socket +Connector:Conn_01x33_Pin +Connector:Conn_01x33_Socket +Connector:Conn_01x34_Pin +Connector:Conn_01x34_Socket +Connector:Conn_01x35_Pin +Connector:Conn_01x35_Socket +Connector:Conn_01x36_Pin +Connector:Conn_01x36_Socket +Connector:Conn_01x37_Pin +Connector:Conn_01x37_Socket +Connector:Conn_01x38_Pin +Connector:Conn_01x38_Socket +Connector:Conn_01x39_Pin +Connector:Conn_01x39_Socket +Connector:Conn_01x40_Pin +Connector:Conn_01x40_Socket +Connector:Conn_01x41_Pin +Connector:Conn_01x41_Socket +Connector:Conn_01x42_Pin +Connector:Conn_01x42_Socket +Connector:Conn_01x43_Pin +Connector:Conn_01x43_Socket +Connector:Conn_01x44_Pin +Connector:Conn_01x44_Socket +Connector:Conn_01x45_Pin +Connector:Conn_01x45_Socket +Connector:Conn_01x46_Pin +Connector:Conn_01x46_Socket +Connector:Conn_01x47_Pin +Connector:Conn_01x47_Socket +Connector:Conn_01x48_Pin +Connector:Conn_01x48_Socket +Connector:Conn_01x49_Pin +Connector:Conn_01x49_Socket +Connector:Conn_01x50_Pin +Connector:Conn_01x50_Socket +Connector:Conn_01x51_Pin +Connector:Conn_01x51_Socket +Connector:Conn_01x52_Pin +Connector:Conn_01x52_Socket +Connector:Conn_01x53_Pin +Connector:Conn_01x53_Socket +Connector:Conn_01x54_Pin +Connector:Conn_01x54_Socket +Connector:Conn_01x55_Pin +Connector:Conn_01x55_Socket +Connector:Conn_01x56_Pin +Connector:Conn_01x56_Socket +Connector:Conn_01x57_Pin +Connector:Conn_01x57_Socket +Connector:Conn_01x58_Pin +Connector:Conn_01x58_Socket +Connector:Conn_01x59_Pin +Connector:Conn_01x59_Socket +Connector:Conn_01x60_Pin +Connector:Conn_01x60_Socket +Connector:Conn_15X4 +Connector:Conn_ARM_Cortex_Debug_ETM_20 +Connector:Conn_ARM_JTAG_SWD_10 +Connector:Conn_ARM_JTAG_SWD_20 +Connector:Conn_ARM_SWD_TagConnect_TC2030 +Connector:Conn_ARM_SWD_TagConnect_TC2030-NL +Connector:Conn_Coaxial +Connector:Conn_Coaxial_Power +Connector:Conn_Coaxial_Small +Connector:Conn_Coaxial_x2 +Connector:Conn_Coaxial_x2_Isolated +Connector:Conn_PIC_ICSP_ICD +Connector:Conn_Plug_2P +Connector:Conn_Plug_3P_Protected +Connector:Conn_Receptacle_2P +Connector:Conn_Receptacle_3P_Protected +Connector:Conn_ST_STDC14 +Connector:Conn_Shielded_Pair +Connector:Conn_Triaxial +Connector:Conn_Triaxial_Same_Side +Connector:DA15_Pins +Connector:DA15_Pins_MountingHoles +Connector:DA15_Socket +Connector:DA15_Socket_MountingHoles +Connector:DB25_Pins +Connector:DB25_Pins_MountingHoles +Connector:DB25_Socket +Connector:DB25_Socket_MountingHoles +Connector:DC37_Pins +Connector:DC37_Pins_MountingHoles +Connector:DC37_Socket +Connector:DC37_Socket_MountingHoles +Connector:DE15_Pins_HighDensity +Connector:DE15_Pins_HighDensity_MountingHoles +Connector:DE15_Socket_HighDensity +Connector:DE15_Socket_HighDensity_MountingHoles +Connector:DE9_Pins +Connector:DE9_Pins_MountingHoles +Connector:DE9_Socket +Connector:DE9_Socket_MountingHoles +Connector:DIN-3 +Connector:DIN-4 +Connector:DIN-5 +Connector:DIN-5_180degree +Connector:DIN-6 +Connector:DIN-7 +Connector:DIN-7_CenterPin7 +Connector:DIN-8 +Connector:DIN41612_01x32_A +Connector:DIN41612_02x05_AB_EvenPins +Connector:DIN41612_02x05_AC_EvenPins +Connector:DIN41612_02x05_AE_EvenPins +Connector:DIN41612_02x05_ZB_EvenPins +Connector:DIN41612_02x08_AB_EvenPins +Connector:DIN41612_02x08_AC_EvenPins +Connector:DIN41612_02x08_AE_EvenPins +Connector:DIN41612_02x08_ZB_EvenPins +Connector:DIN41612_02x10_AB +Connector:DIN41612_02x10_AC +Connector:DIN41612_02x10_AE +Connector:DIN41612_02x10_ZB +Connector:DIN41612_02x16_AB +Connector:DIN41612_02x16_AB_EvenPins +Connector:DIN41612_02x16_AC +Connector:DIN41612_02x16_AC_EvenPins +Connector:DIN41612_02x16_AE +Connector:DIN41612_02x16_AE_EvenPins +Connector:DIN41612_02x16_ZB +Connector:DIN41612_02x16_ZB_EvenPins +Connector:DIN41612_02x32_AB +Connector:DIN41612_02x32_AC +Connector:DIN41612_02x32_AE +Connector:DIN41612_02x32_ZB +Connector:DVI-D_Dual_Link +Connector:DVI-I_Dual_Link +Connector:ExpressCard +Connector:HDMI_A +Connector:HDMI_A_1.4 +Connector:HDMI_B +Connector:HDMI_C_1.3 +Connector:HDMI_C_1.4 +Connector:HDMI_D_1.4 +Connector:HDMI_E +Connector:IEC61076-2_M8_A-coding_01x03_Plug_Shielded +Connector:IEC61076-2_M8_A-coding_01x03_Receptacle_Shielded +Connector:IEC61076-2_M8_A-coding_01x04_Plug_Shielded +Connector:IEC61076-2_M8_A-coding_01x04_Receptacle_Shielded +Connector:IEC_60320_C13_Plug +Connector:IEC_60320_C14_Receptacle +Connector:IEC_60320_C5_Plug +Connector:IEC_60320_C6_Receptacle +Connector:IEC_60320_C7_Plug +Connector:IEC_60320_C8_Receptacle +Connector:IEEE1394a +Connector:JAE_SIM_Card_SF72S006 +Connector:Jack-DC +Connector:LEMO2 +Connector:LEMO4 +Connector:LEMO5 +Connector:LEMO6 +Connector:MXM3.0 +Connector:Micro_SD_Card +Connector:Micro_SD_Card_Det1 +Connector:Micro_SD_Card_Det2 +Connector:Micro_SD_Card_Det_Hirose_DM3AT +Connector:Microsemi_FlashPro-JTAG-10 +Connector:Mini-DIN-3 +Connector:Mini-DIN-4 +Connector:Mini-DIN-5 +Connector:Mini-DIN-6 +Connector:Mini-DIN-7 +Connector:Mini-DIN-8 +Connector:RJ10 +Connector:RJ10_Shielded +Connector:RJ11 +Connector:RJ11_Shielded +Connector:RJ12 +Connector:RJ12_Shielded +Connector:RJ13 +Connector:RJ13_Shielded +Connector:RJ14 +Connector:RJ14_Shielded +Connector:RJ18 +Connector:RJ18_Shielded +Connector:RJ22 +Connector:RJ22_Shielded +Connector:RJ25 +Connector:RJ25_Shielded +Connector:RJ31 +Connector:RJ31_Shielded +Connector:RJ32 +Connector:RJ32_Shielded +Connector:RJ33 +Connector:RJ33_Shielded +Connector:RJ34 +Connector:RJ34_Shielded +Connector:RJ35 +Connector:RJ35_Shielded +Connector:RJ38 +Connector:RJ38_Shielded +Connector:RJ41 +Connector:RJ41_Shielded +Connector:RJ45 +Connector:RJ45_Abracon_ARJP11A-MASA-B-A-EMU2 +Connector:RJ45_Amphenol_RJMG1BD3B8K1ANR +Connector:RJ45_Bel_SI-60062-F +Connector:RJ45_Bel_V895-1001-AW +Connector:RJ45_Halo_HFJ11-x2450E-LxxRL +Connector:RJ45_Halo_HFJ11-x2450ERL +Connector:RJ45_Halo_HFJ11-x2450HRL +Connector:RJ45_Hanrun_HR911105A_Horizontal +Connector:RJ45_JK00177 +Connector:RJ45_JK0654219 +Connector:RJ45_Kycon_G7LX-A88S7-BP-GY +Connector:RJ45_LED +Connector:RJ45_LED_Shielded +Connector:RJ45_LED_Shielded_x2 +Connector:RJ45_Pulse_JXD6-0001NL +Connector:RJ45_RB1-125B8G1A +Connector:RJ45_Shielded +Connector:RJ45_Wuerth_74980111211 +Connector:RJ45_Wuerth_7499010121A +Connector:RJ45_Wuerth_7499010211A +Connector:RJ45_Wuerth_7499151120 +Connector:RJ48 +Connector:RJ48_Shielded +Connector:RJ49 +Connector:RJ49_Shielded +Connector:RJ61 +Connector:RJ61_Shielded +Connector:RJ9 +Connector:RJ9_Shielded +Connector:Raspberry_Pi_4 +Connector:SCART-F +Connector:SD_Card_Device +Connector:SD_Card_Receptacle +Connector:SIM_Card +Connector:SIM_Card_Shielded +Connector:SODIMM-200 +Connector:SODIMM-200_Split +Connector:Samtec_ASP-134486-01 +Connector:Samtec_ASP-134602-01 +Connector:Screw_Terminal_01x01 +Connector:Screw_Terminal_01x02 +Connector:Screw_Terminal_01x03 +Connector:Screw_Terminal_01x04 +Connector:Screw_Terminal_01x05 +Connector:Screw_Terminal_01x06 +Connector:Screw_Terminal_01x07 +Connector:Screw_Terminal_01x08 +Connector:Screw_Terminal_01x09 +Connector:Screw_Terminal_01x10 +Connector:Screw_Terminal_01x11 +Connector:Screw_Terminal_01x12 +Connector:Screw_Terminal_01x13 +Connector:Screw_Terminal_01x14 +Connector:Screw_Terminal_01x15 +Connector:Screw_Terminal_01x16 +Connector:Screw_Terminal_01x17 +Connector:Screw_Terminal_01x18 +Connector:Screw_Terminal_01x19 +Connector:Screw_Terminal_01x20 +Connector:TC2030 +Connector:TC2050 +Connector:TC2070 +Connector:TestPoint +Connector:TestPoint_2Pole +Connector:TestPoint_Alt +Connector:TestPoint_Flag +Connector:TestPoint_Probe +Connector:TestPoint_Small +Connector:UEXT_Host +Connector:UEXT_Slave +Connector:USB3_A +Connector:USB3_A_Stacked +Connector:USB3_B +Connector:USB3_B_Micro +Connector:USB_A +Connector:USB_A_Stacked +Connector:USB_B +Connector:USB_B_Micro +Connector:USB_B_Mini +Connector:USB_C_Plug +Connector:USB_C_Plug_USB2.0 +Connector:USB_C_Receptacle +Connector:USB_C_Receptacle_PowerOnly_24P +Connector:USB_C_Receptacle_PowerOnly_6P +Connector:USB_C_Receptacle_USB2.0_14P +Connector:USB_C_Receptacle_USB2.0_16P +Connector:USB_OTG +Connector_Audio:AudioJack2 +Connector_Audio:AudioJack2_Dual_Ground_Switch +Connector_Audio:AudioJack2_Dual_Switch +Connector_Audio:AudioJack2_Ground +Connector_Audio:AudioJack2_Ground_Switch +Connector_Audio:AudioJack2_Ground_SwitchT +Connector_Audio:AudioJack2_Switch +Connector_Audio:AudioJack2_SwitchT +Connector_Audio:AudioJack3 +Connector_Audio:AudioJack3_Dual_Ground_Switch +Connector_Audio:AudioJack3_Dual_Switch +Connector_Audio:AudioJack3_Ground +Connector_Audio:AudioJack3_Ground_Switch +Connector_Audio:AudioJack3_Ground_SwitchTR +Connector_Audio:AudioJack3_Switch +Connector_Audio:AudioJack3_SwitchT +Connector_Audio:AudioJack3_SwitchTR +Connector_Audio:AudioJack4 +Connector_Audio:AudioJack4_Ground +Connector_Audio:AudioJack4_Ground_SwitchTR1 +Connector_Audio:AudioJack4_SwitchT1 +Connector_Audio:AudioJack4_SwitchTR1 +Connector_Audio:AudioJack5 +Connector_Audio:AudioJack5_Ground +Connector_Audio:AudioPlug2 +Connector_Audio:AudioPlug3 +Connector_Audio:AudioPlug4 +Connector_Audio:NC3FAAH +Connector_Audio:NC3FAAH-0 +Connector_Audio:NC3FAAH1 +Connector_Audio:NC3FAAH1-0 +Connector_Audio:NC3FAAH1-DA +Connector_Audio:NC3FAAH2 +Connector_Audio:NC3FAAH2-0 +Connector_Audio:NC3FAAV +Connector_Audio:NC3FAAV-0 +Connector_Audio:NC3FAAV1 +Connector_Audio:NC3FAAV1-0 +Connector_Audio:NC3FAAV1-DA +Connector_Audio:NC3FAAV2 +Connector_Audio:NC3FAAV2-0 +Connector_Audio:NC3FAH +Connector_Audio:NC3FAH-0 +Connector_Audio:NC3FAH1 +Connector_Audio:NC3FAH1-0 +Connector_Audio:NC3FAH1-DA +Connector_Audio:NC3FAH2 +Connector_Audio:NC3FAH2-0 +Connector_Audio:NC3FAH2-DA +Connector_Audio:NC3FAHL-0 +Connector_Audio:NC3FAHL1 +Connector_Audio:NC3FAHL1-0 +Connector_Audio:NC3FAHR-0 +Connector_Audio:NC3FAHR1 +Connector_Audio:NC3FAHR1-0 +Connector_Audio:NC3FAHR2 +Connector_Audio:NC3FAHR2-0 +Connector_Audio:NC3FAV +Connector_Audio:NC3FAV-0 +Connector_Audio:NC3FAV1 +Connector_Audio:NC3FAV1-0 +Connector_Audio:NC3FAV1-DA +Connector_Audio:NC3FAV2 +Connector_Audio:NC3FAV2-0 +Connector_Audio:NC3FAV2-DA +Connector_Audio:NC3FBH1 +Connector_Audio:NC3FBH1-B +Connector_Audio:NC3FBH1-DA +Connector_Audio:NC3FBH1-E +Connector_Audio:NC3FBH2 +Connector_Audio:NC3FBH2-B +Connector_Audio:NC3FBH2-DA +Connector_Audio:NC3FBH2-E +Connector_Audio:NC3FBHL1 +Connector_Audio:NC3FBV1 +Connector_Audio:NC3FBV1-0 +Connector_Audio:NC3FBV1-B +Connector_Audio:NC3FBV1-DA +Connector_Audio:NC3FBV2 +Connector_Audio:NC3FBV2-B +Connector_Audio:NC3FBV2-DA +Connector_Audio:NC3FBV2-SW +Connector_Audio:NC3MAAH +Connector_Audio:NC3MAAH-0 +Connector_Audio:NC3MAAH-1 +Connector_Audio:NC3MAAV +Connector_Audio:NC3MAAV-0 +Connector_Audio:NC3MAAV-1 +Connector_Audio:NC3MAFH-PH +Connector_Audio:NC3MAH +Connector_Audio:NC3MAH-0 +Connector_Audio:NC3MAHL +Connector_Audio:NC3MAHR +Connector_Audio:NC3MAMH-PH +Connector_Audio:NC3MAV +Connector_Audio:NC3MAV-0 +Connector_Audio:NC3MBH +Connector_Audio:NC3MBH-0 +Connector_Audio:NC3MBH-1 +Connector_Audio:NC3MBH-B +Connector_Audio:NC3MBH-E +Connector_Audio:NC3MBHL +Connector_Audio:NC3MBHL-B +Connector_Audio:NC3MBHR +Connector_Audio:NC3MBHR-B +Connector_Audio:NC3MBV +Connector_Audio:NC3MBV-0 +Connector_Audio:NC3MBV-1 +Connector_Audio:NC3MBV-B +Connector_Audio:NC3MBV-E +Connector_Audio:NC3MBV-SW +Connector_Audio:NC4FAH +Connector_Audio:NC4FAH-0 +Connector_Audio:NC4FAV +Connector_Audio:NC4FAV-0 +Connector_Audio:NC4FBH +Connector_Audio:NC4FBV +Connector_Audio:NC4MAH +Connector_Audio:NC4MAV +Connector_Audio:NC4MBH +Connector_Audio:NC4MBV +Connector_Audio:NC5FAH +Connector_Audio:NC5FAH-0 +Connector_Audio:NC5FAH-DA +Connector_Audio:NC5FAV +Connector_Audio:NC5FAV-DA +Connector_Audio:NC5FAV-SW +Connector_Audio:NC5FBH +Connector_Audio:NC5FBH-B +Connector_Audio:NC5FBV +Connector_Audio:NC5FBV-B +Connector_Audio:NC5FBV-SW +Connector_Audio:NC5MAH +Connector_Audio:NC5MAV +Connector_Audio:NC5MAV-SW +Connector_Audio:NC5MBH +Connector_Audio:NC5MBH-B +Connector_Audio:NC5MBV +Connector_Audio:NC5MBV-B +Connector_Audio:NC5MBV-SW +Connector_Audio:NCJ10FI-H +Connector_Audio:NCJ10FI-H-0 +Connector_Audio:NCJ10FI-V +Connector_Audio:NCJ10FI-V-0 +Connector_Audio:NCJ5FI-H +Connector_Audio:NCJ5FI-H-0 +Connector_Audio:NCJ5FI-V +Connector_Audio:NCJ5FI-V-0 +Connector_Audio:NCJ6FA-H +Connector_Audio:NCJ6FA-H-0 +Connector_Audio:NCJ6FA-H-DA +Connector_Audio:NCJ6FA-V +Connector_Audio:NCJ6FA-V-0 +Connector_Audio:NCJ6FA-V-DA +Connector_Audio:NCJ6FI-H +Connector_Audio:NCJ6FI-H-0 +Connector_Audio:NCJ6FI-V +Connector_Audio:NCJ6FI-V-0 +Connector_Audio:NCJ9FI-H +Connector_Audio:NCJ9FI-H-0 +Connector_Audio:NCJ9FI-V +Connector_Audio:NCJ9FI-V-0 +Connector_Audio:NJ2FD-V +Connector_Audio:NJ3FD-V +Connector_Audio:NJ5FD-V +Connector_Audio:NJ6FD-V +Connector_Audio:NJ6TB-V +Connector_Audio:NL2MDXX-H-3 +Connector_Audio:NL2MDXX-V +Connector_Audio:NL4MDXX-H-2 +Connector_Audio:NL4MDXX-H-3 +Connector_Audio:NL4MDXX-V +Connector_Audio:NL4MDXX-V-2 +Connector_Audio:NL4MDXX-V-3 +Connector_Audio:NL8MDXX-V +Connector_Audio:NL8MDXX-V-3 +Connector_Audio:NLJ2MDXX-H +Connector_Audio:NLJ2MDXX-V +Connector_Audio:NLT4MD-V +Connector_Audio:NMJ4HCD2 +Connector_Audio:NMJ4HFD2 +Connector_Audio:NMJ4HFD3 +Connector_Audio:NMJ4HHD2 +Connector_Audio:NMJ6HCD2 +Connector_Audio:NMJ6HCD3 +Connector_Audio:NMJ6HFD2 +Connector_Audio:NMJ6HFD2-AU +Connector_Audio:NMJ6HFD3 +Connector_Audio:NMJ6HFD4 +Connector_Audio:NMJ6HHD2 +Connector_Audio:NRJ3HF-1 +Connector_Audio:NRJ4HF +Connector_Audio:NRJ4HF-1 +Connector_Audio:NRJ4HH +Connector_Audio:NRJ4HH-1 +Connector_Audio:NRJ6HF +Connector_Audio:NRJ6HF-1 +Connector_Audio:NRJ6HF-1-AU +Connector_Audio:NRJ6HF-AU +Connector_Audio:NRJ6HH +Connector_Audio:NRJ6HH-1 +Connector_Audio:NRJ6HH-AU +Connector_Audio:NRJ6HM-1 +Connector_Audio:NRJ6HM-1-AU +Connector_Audio:NRJ6HM-1-PRE +Connector_Audio:NSJ12HC +Connector_Audio:NSJ12HF-1 +Connector_Audio:NSJ12HH-1 +Connector_Audio:NSJ12HL +Connector_Audio:NSJ8HC +Connector_Audio:NSJ8HL +Connector_Audio:SpeakON_NL2 +Connector_Audio:SpeakON_NL2_AudioJack2_Combo +Connector_Audio:SpeakON_NL4 +Connector_Audio:SpeakON_NL4_Switch +Connector_Audio:SpeakON_NL8 +Connector_Audio:XLR3 +Connector_Audio:XLR3_AudioJack2_Combo +Connector_Audio:XLR3_AudioJack2_Combo_Ground +Connector_Audio:XLR3_AudioJack3_Combo +Connector_Audio:XLR3_AudioJack3_Combo_Ground +Connector_Audio:XLR3_AudioJack3_Combo_GroundSwitch_Switch +Connector_Audio:XLR3_AudioJack3_Combo_Ground_Switch +Connector_Audio:XLR3_AudioJack3_Combo_Switch +Connector_Audio:XLR3_Ground +Connector_Audio:XLR3_Ground_Switched +Connector_Audio:XLR3_Switched +Connector_Audio:XLR4 +Connector_Audio:XLR4_Ground +Connector_Audio:XLR5 +Connector_Audio:XLR5_Ground +Connector_Audio:XLR5_Ground_Switched +Connector_Audio:XLR6 +Connector_Generic:Conn_01x01 +Connector_Generic:Conn_01x02 +Connector_Generic:Conn_01x03 +Connector_Generic:Conn_01x04 +Connector_Generic:Conn_01x05 +Connector_Generic:Conn_01x06 +Connector_Generic:Conn_01x07 +Connector_Generic:Conn_01x08 +Connector_Generic:Conn_01x09 +Connector_Generic:Conn_01x10 +Connector_Generic:Conn_01x11 +Connector_Generic:Conn_01x12 +Connector_Generic:Conn_01x13 +Connector_Generic:Conn_01x14 +Connector_Generic:Conn_01x15 +Connector_Generic:Conn_01x16 +Connector_Generic:Conn_01x17 +Connector_Generic:Conn_01x18 +Connector_Generic:Conn_01x19 +Connector_Generic:Conn_01x20 +Connector_Generic:Conn_01x21 +Connector_Generic:Conn_01x22 +Connector_Generic:Conn_01x23 +Connector_Generic:Conn_01x24 +Connector_Generic:Conn_01x25 +Connector_Generic:Conn_01x26 +Connector_Generic:Conn_01x27 +Connector_Generic:Conn_01x28 +Connector_Generic:Conn_01x29 +Connector_Generic:Conn_01x30 +Connector_Generic:Conn_01x31 +Connector_Generic:Conn_01x32 +Connector_Generic:Conn_01x33 +Connector_Generic:Conn_01x34 +Connector_Generic:Conn_01x35 +Connector_Generic:Conn_01x36 +Connector_Generic:Conn_01x37 +Connector_Generic:Conn_01x38 +Connector_Generic:Conn_01x39 +Connector_Generic:Conn_01x40 +Connector_Generic:Conn_01x41 +Connector_Generic:Conn_01x42 +Connector_Generic:Conn_01x43 +Connector_Generic:Conn_01x44 +Connector_Generic:Conn_01x45 +Connector_Generic:Conn_01x46 +Connector_Generic:Conn_01x47 +Connector_Generic:Conn_01x48 +Connector_Generic:Conn_01x49 +Connector_Generic:Conn_01x50 +Connector_Generic:Conn_01x51 +Connector_Generic:Conn_01x52 +Connector_Generic:Conn_01x53 +Connector_Generic:Conn_01x54 +Connector_Generic:Conn_01x55 +Connector_Generic:Conn_01x56 +Connector_Generic:Conn_01x57 +Connector_Generic:Conn_01x58 +Connector_Generic:Conn_01x59 +Connector_Generic:Conn_01x60 +Connector_Generic:Conn_02x01 +Connector_Generic:Conn_02x01_Row_Letter_First +Connector_Generic:Conn_02x01_Row_Letter_Last +Connector_Generic:Conn_02x02_Counter_Clockwise +Connector_Generic:Conn_02x02_Odd_Even +Connector_Generic:Conn_02x02_Row_Letter_First +Connector_Generic:Conn_02x02_Row_Letter_Last +Connector_Generic:Conn_02x02_Top_Bottom +Connector_Generic:Conn_02x03_Counter_Clockwise +Connector_Generic:Conn_02x03_Odd_Even +Connector_Generic:Conn_02x03_Row_Letter_First +Connector_Generic:Conn_02x03_Row_Letter_Last +Connector_Generic:Conn_02x03_Top_Bottom +Connector_Generic:Conn_02x04_Counter_Clockwise +Connector_Generic:Conn_02x04_Odd_Even +Connector_Generic:Conn_02x04_Row_Letter_First +Connector_Generic:Conn_02x04_Row_Letter_Last +Connector_Generic:Conn_02x04_Top_Bottom +Connector_Generic:Conn_02x05_Counter_Clockwise +Connector_Generic:Conn_02x05_Odd_Even +Connector_Generic:Conn_02x05_Row_Letter_First +Connector_Generic:Conn_02x05_Row_Letter_Last +Connector_Generic:Conn_02x05_Top_Bottom +Connector_Generic:Conn_02x06_Counter_Clockwise +Connector_Generic:Conn_02x06_Odd_Even +Connector_Generic:Conn_02x06_Row_Letter_First +Connector_Generic:Conn_02x06_Row_Letter_Last +Connector_Generic:Conn_02x06_Top_Bottom +Connector_Generic:Conn_02x07_Counter_Clockwise +Connector_Generic:Conn_02x07_Odd_Even +Connector_Generic:Conn_02x07_Row_Letter_First +Connector_Generic:Conn_02x07_Row_Letter_Last +Connector_Generic:Conn_02x07_Top_Bottom +Connector_Generic:Conn_02x08_Counter_Clockwise +Connector_Generic:Conn_02x08_Odd_Even +Connector_Generic:Conn_02x08_Row_Letter_First +Connector_Generic:Conn_02x08_Row_Letter_Last +Connector_Generic:Conn_02x08_Top_Bottom +Connector_Generic:Conn_02x09_Counter_Clockwise +Connector_Generic:Conn_02x09_Odd_Even +Connector_Generic:Conn_02x09_Row_Letter_First +Connector_Generic:Conn_02x09_Row_Letter_Last +Connector_Generic:Conn_02x09_Top_Bottom +Connector_Generic:Conn_02x10_Counter_Clockwise +Connector_Generic:Conn_02x10_Odd_Even +Connector_Generic:Conn_02x10_Row_Letter_First +Connector_Generic:Conn_02x10_Row_Letter_Last +Connector_Generic:Conn_02x10_Top_Bottom +Connector_Generic:Conn_02x11_Counter_Clockwise +Connector_Generic:Conn_02x11_Odd_Even +Connector_Generic:Conn_02x11_Row_Letter_First +Connector_Generic:Conn_02x11_Row_Letter_Last +Connector_Generic:Conn_02x11_Top_Bottom +Connector_Generic:Conn_02x12_Counter_Clockwise +Connector_Generic:Conn_02x12_Odd_Even +Connector_Generic:Conn_02x12_Row_Letter_First +Connector_Generic:Conn_02x12_Row_Letter_Last +Connector_Generic:Conn_02x12_Top_Bottom +Connector_Generic:Conn_02x13_Counter_Clockwise +Connector_Generic:Conn_02x13_Odd_Even +Connector_Generic:Conn_02x13_Row_Letter_First +Connector_Generic:Conn_02x13_Row_Letter_Last +Connector_Generic:Conn_02x13_Top_Bottom +Connector_Generic:Conn_02x14_Counter_Clockwise +Connector_Generic:Conn_02x14_Odd_Even +Connector_Generic:Conn_02x14_Row_Letter_First +Connector_Generic:Conn_02x14_Row_Letter_Last +Connector_Generic:Conn_02x14_Top_Bottom +Connector_Generic:Conn_02x15_Counter_Clockwise +Connector_Generic:Conn_02x15_Odd_Even +Connector_Generic:Conn_02x15_Row_Letter_First +Connector_Generic:Conn_02x15_Row_Letter_Last +Connector_Generic:Conn_02x15_Top_Bottom +Connector_Generic:Conn_02x16_Counter_Clockwise +Connector_Generic:Conn_02x16_Odd_Even +Connector_Generic:Conn_02x16_Row_Letter_First +Connector_Generic:Conn_02x16_Row_Letter_Last +Connector_Generic:Conn_02x16_Top_Bottom +Connector_Generic:Conn_02x17_Counter_Clockwise +Connector_Generic:Conn_02x17_Odd_Even +Connector_Generic:Conn_02x17_Row_Letter_First +Connector_Generic:Conn_02x17_Row_Letter_Last +Connector_Generic:Conn_02x17_Top_Bottom +Connector_Generic:Conn_02x18_Counter_Clockwise +Connector_Generic:Conn_02x18_Odd_Even +Connector_Generic:Conn_02x18_Row_Letter_First +Connector_Generic:Conn_02x18_Row_Letter_Last +Connector_Generic:Conn_02x18_Top_Bottom +Connector_Generic:Conn_02x19_Counter_Clockwise +Connector_Generic:Conn_02x19_Odd_Even +Connector_Generic:Conn_02x19_Row_Letter_First +Connector_Generic:Conn_02x19_Row_Letter_Last +Connector_Generic:Conn_02x19_Top_Bottom +Connector_Generic:Conn_02x20_Counter_Clockwise +Connector_Generic:Conn_02x20_Odd_Even +Connector_Generic:Conn_02x20_Row_Letter_First +Connector_Generic:Conn_02x20_Row_Letter_Last +Connector_Generic:Conn_02x20_Top_Bottom +Connector_Generic:Conn_02x21_Counter_Clockwise +Connector_Generic:Conn_02x21_Odd_Even +Connector_Generic:Conn_02x21_Row_Letter_First +Connector_Generic:Conn_02x21_Row_Letter_Last +Connector_Generic:Conn_02x21_Top_Bottom +Connector_Generic:Conn_02x22_Counter_Clockwise +Connector_Generic:Conn_02x22_Odd_Even +Connector_Generic:Conn_02x22_Row_Letter_First +Connector_Generic:Conn_02x22_Row_Letter_Last +Connector_Generic:Conn_02x22_Top_Bottom +Connector_Generic:Conn_02x23_Counter_Clockwise +Connector_Generic:Conn_02x23_Odd_Even +Connector_Generic:Conn_02x23_Row_Letter_First +Connector_Generic:Conn_02x23_Row_Letter_Last +Connector_Generic:Conn_02x23_Top_Bottom +Connector_Generic:Conn_02x24_Counter_Clockwise +Connector_Generic:Conn_02x24_Odd_Even +Connector_Generic:Conn_02x24_Row_Letter_First +Connector_Generic:Conn_02x24_Row_Letter_Last +Connector_Generic:Conn_02x24_Top_Bottom +Connector_Generic:Conn_02x25_Counter_Clockwise +Connector_Generic:Conn_02x25_Odd_Even +Connector_Generic:Conn_02x25_Row_Letter_First +Connector_Generic:Conn_02x25_Row_Letter_Last +Connector_Generic:Conn_02x25_Top_Bottom +Connector_Generic:Conn_02x26_Counter_Clockwise +Connector_Generic:Conn_02x26_Odd_Even +Connector_Generic:Conn_02x26_Row_Letter_First +Connector_Generic:Conn_02x26_Row_Letter_Last +Connector_Generic:Conn_02x26_Top_Bottom +Connector_Generic:Conn_02x27_Counter_Clockwise +Connector_Generic:Conn_02x27_Odd_Even +Connector_Generic:Conn_02x27_Row_Letter_First +Connector_Generic:Conn_02x27_Row_Letter_Last +Connector_Generic:Conn_02x27_Top_Bottom +Connector_Generic:Conn_02x28_Counter_Clockwise +Connector_Generic:Conn_02x28_Odd_Even +Connector_Generic:Conn_02x28_Row_Letter_First +Connector_Generic:Conn_02x28_Row_Letter_Last +Connector_Generic:Conn_02x28_Top_Bottom +Connector_Generic:Conn_02x29_Counter_Clockwise +Connector_Generic:Conn_02x29_Odd_Even +Connector_Generic:Conn_02x29_Row_Letter_First +Connector_Generic:Conn_02x29_Row_Letter_Last +Connector_Generic:Conn_02x29_Top_Bottom +Connector_Generic:Conn_02x30_Counter_Clockwise +Connector_Generic:Conn_02x30_Odd_Even +Connector_Generic:Conn_02x30_Row_Letter_First +Connector_Generic:Conn_02x30_Row_Letter_Last +Connector_Generic:Conn_02x30_Top_Bottom +Connector_Generic:Conn_02x31_Counter_Clockwise +Connector_Generic:Conn_02x31_Odd_Even +Connector_Generic:Conn_02x31_Row_Letter_First +Connector_Generic:Conn_02x31_Row_Letter_Last +Connector_Generic:Conn_02x31_Top_Bottom +Connector_Generic:Conn_02x32_Counter_Clockwise +Connector_Generic:Conn_02x32_Odd_Even +Connector_Generic:Conn_02x32_Row_Letter_First +Connector_Generic:Conn_02x32_Row_Letter_Last +Connector_Generic:Conn_02x32_Top_Bottom +Connector_Generic:Conn_02x33_Counter_Clockwise +Connector_Generic:Conn_02x33_Odd_Even +Connector_Generic:Conn_02x33_Row_Letter_First +Connector_Generic:Conn_02x33_Row_Letter_Last +Connector_Generic:Conn_02x33_Top_Bottom +Connector_Generic:Conn_02x34_Counter_Clockwise +Connector_Generic:Conn_02x34_Odd_Even +Connector_Generic:Conn_02x34_Row_Letter_First +Connector_Generic:Conn_02x34_Row_Letter_Last +Connector_Generic:Conn_02x34_Top_Bottom +Connector_Generic:Conn_02x35_Counter_Clockwise +Connector_Generic:Conn_02x35_Odd_Even +Connector_Generic:Conn_02x35_Row_Letter_First +Connector_Generic:Conn_02x35_Row_Letter_Last +Connector_Generic:Conn_02x35_Top_Bottom +Connector_Generic:Conn_02x36_Counter_Clockwise +Connector_Generic:Conn_02x36_Odd_Even +Connector_Generic:Conn_02x36_Row_Letter_First +Connector_Generic:Conn_02x36_Row_Letter_Last +Connector_Generic:Conn_02x36_Top_Bottom +Connector_Generic:Conn_02x37_Counter_Clockwise +Connector_Generic:Conn_02x37_Odd_Even +Connector_Generic:Conn_02x37_Row_Letter_First +Connector_Generic:Conn_02x37_Row_Letter_Last +Connector_Generic:Conn_02x37_Top_Bottom +Connector_Generic:Conn_02x38_Counter_Clockwise +Connector_Generic:Conn_02x38_Odd_Even +Connector_Generic:Conn_02x38_Row_Letter_First +Connector_Generic:Conn_02x38_Row_Letter_Last +Connector_Generic:Conn_02x38_Top_Bottom +Connector_Generic:Conn_02x39_Counter_Clockwise +Connector_Generic:Conn_02x39_Odd_Even +Connector_Generic:Conn_02x39_Row_Letter_First +Connector_Generic:Conn_02x39_Row_Letter_Last +Connector_Generic:Conn_02x39_Top_Bottom +Connector_Generic:Conn_02x40_Counter_Clockwise +Connector_Generic:Conn_02x40_Odd_Even +Connector_Generic:Conn_02x40_Row_Letter_First +Connector_Generic:Conn_02x40_Row_Letter_Last +Connector_Generic:Conn_02x40_Top_Bottom +Connector_Generic:Conn_02x41_Row_Letter_First +Connector_Generic:Conn_02x41_Row_Letter_Last +Connector_Generic:Conn_02x42_Row_Letter_First +Connector_Generic:Conn_02x42_Row_Letter_Last +Connector_Generic:Conn_02x43_Row_Letter_First +Connector_Generic:Conn_02x43_Row_Letter_Last +Connector_Generic:Conn_02x44_Row_Letter_First +Connector_Generic:Conn_02x44_Row_Letter_Last +Connector_Generic:Conn_02x45_Row_Letter_First +Connector_Generic:Conn_02x45_Row_Letter_Last +Connector_Generic:Conn_02x46_Row_Letter_First +Connector_Generic:Conn_02x46_Row_Letter_Last +Connector_Generic:Conn_02x47_Row_Letter_First +Connector_Generic:Conn_02x47_Row_Letter_Last +Connector_Generic:Conn_02x48_Row_Letter_First +Connector_Generic:Conn_02x48_Row_Letter_Last +Connector_Generic:Conn_02x49_Row_Letter_First +Connector_Generic:Conn_02x49_Row_Letter_Last +Connector_Generic:Conn_02x50_Row_Letter_First +Connector_Generic:Conn_02x50_Row_Letter_Last +Connector_Generic:Conn_02x51_Row_Letter_First +Connector_Generic:Conn_02x51_Row_Letter_Last +Connector_Generic:Conn_02x52_Row_Letter_First +Connector_Generic:Conn_02x52_Row_Letter_Last +Connector_Generic:Conn_02x53_Row_Letter_First +Connector_Generic:Conn_02x53_Row_Letter_Last +Connector_Generic:Conn_02x54_Row_Letter_First +Connector_Generic:Conn_02x54_Row_Letter_Last +Connector_Generic:Conn_02x55_Row_Letter_First +Connector_Generic:Conn_02x55_Row_Letter_Last +Connector_Generic:Conn_02x56_Row_Letter_First +Connector_Generic:Conn_02x56_Row_Letter_Last +Connector_Generic:Conn_02x57_Row_Letter_First +Connector_Generic:Conn_02x57_Row_Letter_Last +Connector_Generic:Conn_02x58_Row_Letter_First +Connector_Generic:Conn_02x58_Row_Letter_Last +Connector_Generic:Conn_02x59_Row_Letter_First +Connector_Generic:Conn_02x59_Row_Letter_Last +Connector_Generic:Conn_02x60_Row_Letter_First +Connector_Generic:Conn_02x60_Row_Letter_Last +Connector_Generic:Conn_2Rows-05Pins +Connector_Generic:Conn_2Rows-07Pins +Connector_Generic:Conn_2Rows-09Pins +Connector_Generic:Conn_2Rows-11Pins +Connector_Generic:Conn_2Rows-13Pins +Connector_Generic:Conn_2Rows-15Pins +Connector_Generic:Conn_2Rows-17Pins +Connector_Generic:Conn_2Rows-19Pins +Connector_Generic:Conn_2Rows-21Pins +Connector_Generic:Conn_2Rows-23Pins +Connector_Generic:Conn_2Rows-25Pins +Connector_Generic:Conn_2Rows-27Pins +Connector_Generic:Conn_2Rows-29Pins +Connector_Generic:Conn_2Rows-31Pins +Connector_Generic:Conn_2Rows-33Pins +Connector_Generic:Conn_2Rows-35Pins +Connector_Generic:Conn_2Rows-37Pins +Connector_Generic:Conn_2Rows-39Pins +Connector_Generic:Conn_2Rows-41Pins +Connector_Generic:Conn_2Rows-43Pins +Connector_Generic:Conn_2Rows-45Pins +Connector_Generic:Conn_2Rows-47Pins +Connector_Generic:Conn_2Rows-49Pins +Connector_Generic:Conn_2Rows-51Pins +Connector_Generic:Conn_2Rows-53Pins +Connector_Generic:Conn_2Rows-55Pins +Connector_Generic:Conn_2Rows-57Pins +Connector_Generic:Conn_2Rows-59Pins +Connector_Generic:Conn_2Rows-61Pins +Connector_Generic:Conn_2Rows-63Pins +Connector_Generic:Conn_2Rows-65Pins +Connector_Generic:Conn_2Rows-67Pins +Connector_Generic:Conn_2Rows-69Pins +Connector_Generic:Conn_2Rows-71Pins +Connector_Generic:Conn_2Rows-73Pins +Connector_Generic:Conn_2Rows-75Pins +Connector_Generic_MountingPin:Conn_01x01_MountingPin +Connector_Generic_MountingPin:Conn_01x02_MountingPin +Connector_Generic_MountingPin:Conn_01x03_MountingPin +Connector_Generic_MountingPin:Conn_01x04_MountingPin +Connector_Generic_MountingPin:Conn_01x05_MountingPin +Connector_Generic_MountingPin:Conn_01x06_MountingPin +Connector_Generic_MountingPin:Conn_01x07_MountingPin +Connector_Generic_MountingPin:Conn_01x08_MountingPin +Connector_Generic_MountingPin:Conn_01x09_MountingPin +Connector_Generic_MountingPin:Conn_01x10_MountingPin +Connector_Generic_MountingPin:Conn_01x11_MountingPin +Connector_Generic_MountingPin:Conn_01x12_MountingPin +Connector_Generic_MountingPin:Conn_01x13_MountingPin +Connector_Generic_MountingPin:Conn_01x14_MountingPin +Connector_Generic_MountingPin:Conn_01x15_MountingPin +Connector_Generic_MountingPin:Conn_01x16_MountingPin +Connector_Generic_MountingPin:Conn_01x17_MountingPin +Connector_Generic_MountingPin:Conn_01x18_MountingPin +Connector_Generic_MountingPin:Conn_01x19_MountingPin +Connector_Generic_MountingPin:Conn_01x20_MountingPin +Connector_Generic_MountingPin:Conn_01x21_MountingPin +Connector_Generic_MountingPin:Conn_01x22_MountingPin +Connector_Generic_MountingPin:Conn_01x23_MountingPin +Connector_Generic_MountingPin:Conn_01x24_MountingPin +Connector_Generic_MountingPin:Conn_01x25_MountingPin +Connector_Generic_MountingPin:Conn_01x26_MountingPin +Connector_Generic_MountingPin:Conn_01x27_MountingPin +Connector_Generic_MountingPin:Conn_01x28_MountingPin +Connector_Generic_MountingPin:Conn_01x29_MountingPin +Connector_Generic_MountingPin:Conn_01x30_MountingPin +Connector_Generic_MountingPin:Conn_01x31_MountingPin +Connector_Generic_MountingPin:Conn_01x32_MountingPin +Connector_Generic_MountingPin:Conn_01x33_MountingPin +Connector_Generic_MountingPin:Conn_01x34_MountingPin +Connector_Generic_MountingPin:Conn_01x35_MountingPin +Connector_Generic_MountingPin:Conn_01x36_MountingPin +Connector_Generic_MountingPin:Conn_01x37_MountingPin +Connector_Generic_MountingPin:Conn_01x38_MountingPin +Connector_Generic_MountingPin:Conn_01x39_MountingPin +Connector_Generic_MountingPin:Conn_01x40_MountingPin +Connector_Generic_MountingPin:Conn_01x41_MountingPin +Connector_Generic_MountingPin:Conn_01x42_MountingPin +Connector_Generic_MountingPin:Conn_01x43_MountingPin +Connector_Generic_MountingPin:Conn_01x44_MountingPin +Connector_Generic_MountingPin:Conn_01x45_MountingPin +Connector_Generic_MountingPin:Conn_01x46_MountingPin +Connector_Generic_MountingPin:Conn_01x47_MountingPin +Connector_Generic_MountingPin:Conn_01x48_MountingPin +Connector_Generic_MountingPin:Conn_01x49_MountingPin +Connector_Generic_MountingPin:Conn_01x50_MountingPin +Connector_Generic_MountingPin:Conn_01x51_MountingPin +Connector_Generic_MountingPin:Conn_01x52_MountingPin +Connector_Generic_MountingPin:Conn_01x53_MountingPin +Connector_Generic_MountingPin:Conn_01x54_MountingPin +Connector_Generic_MountingPin:Conn_01x55_MountingPin +Connector_Generic_MountingPin:Conn_01x56_MountingPin +Connector_Generic_MountingPin:Conn_01x57_MountingPin +Connector_Generic_MountingPin:Conn_01x58_MountingPin +Connector_Generic_MountingPin:Conn_01x59_MountingPin +Connector_Generic_MountingPin:Conn_01x60_MountingPin +Connector_Generic_MountingPin:Conn_02x01_MountingPin +Connector_Generic_MountingPin:Conn_02x01_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x01_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x02_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x02_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x02_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x02_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x02_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x03_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x03_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x03_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x03_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x03_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x04_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x04_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x04_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x04_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x04_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x05_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x05_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x05_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x05_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x05_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x06_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x06_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x06_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x06_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x06_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x07_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x07_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x07_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x07_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x07_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x08_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x08_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x08_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x08_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x08_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x09_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x09_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x09_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x09_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x09_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x10_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x10_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x10_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x10_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x10_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x11_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x11_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x11_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x11_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x11_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x12_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x12_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x12_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x12_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x12_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x13_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x13_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x13_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x13_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x13_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x14_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x14_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x14_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x14_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x14_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x15_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x15_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x15_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x15_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x15_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x16_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x16_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x16_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x16_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x16_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x17_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x17_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x17_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x17_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x17_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x18_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x18_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x18_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x18_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x18_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x19_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x19_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x19_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x19_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x19_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x20_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x20_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x20_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x20_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x20_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x21_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x21_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x21_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x21_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x21_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x22_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x22_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x22_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x22_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x22_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x23_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x23_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x23_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x23_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x23_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x24_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x24_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x24_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x24_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x24_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x25_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x25_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x25_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x25_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x25_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x26_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x26_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x26_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x26_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x26_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x27_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x27_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x27_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x27_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x27_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x28_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x28_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x28_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x28_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x28_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x29_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x29_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x29_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x29_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x29_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x30_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x30_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x30_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x30_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x30_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x31_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x31_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x31_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x31_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x31_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x32_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x32_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x32_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x32_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x32_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x33_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x33_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x33_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x33_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x33_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x34_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x34_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x34_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x34_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x34_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x35_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x35_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x35_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x35_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x35_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x36_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x36_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x36_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x36_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x36_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x37_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x37_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x37_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x37_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x37_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x38_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x38_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x38_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x38_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x38_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x39_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x39_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x39_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x39_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x39_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x40_Counter_Clockwise_MountingPin +Connector_Generic_MountingPin:Conn_02x40_Odd_Even_MountingPin +Connector_Generic_MountingPin:Conn_02x40_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x40_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x40_Top_Bottom_MountingPin +Connector_Generic_MountingPin:Conn_02x41_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x41_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x42_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x42_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x43_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x43_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x44_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x44_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x45_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x45_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x46_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x46_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x47_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x47_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x48_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x48_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x49_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x49_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x50_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x50_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x51_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x51_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x52_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x52_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x53_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x53_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x54_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x54_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x55_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x55_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x56_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x56_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x57_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x57_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x58_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x58_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x59_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x59_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_02x60_Row_Letter_First_MountingPin +Connector_Generic_MountingPin:Conn_02x60_Row_Letter_Last_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-05Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-07Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-09Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-11Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-13Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-15Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-17Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-19Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-21Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-23Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-25Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-27Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-29Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-31Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-33Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-35Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-37Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-39Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-41Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-43Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-45Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-47Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-49Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-51Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-53Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-55Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-57Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-59Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-61Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-63Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-65Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-67Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-69Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-71Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-73Pins_MountingPin +Connector_Generic_MountingPin:Conn_2Rows-75Pins_MountingPin +Connector_Generic_Shielded:Conn_01x01_Shielded +Connector_Generic_Shielded:Conn_01x02_Shielded +Connector_Generic_Shielded:Conn_01x03_Shielded +Connector_Generic_Shielded:Conn_01x04_Shielded +Connector_Generic_Shielded:Conn_01x05_Shielded +Connector_Generic_Shielded:Conn_01x06_Shielded +Connector_Generic_Shielded:Conn_01x07_Shielded +Connector_Generic_Shielded:Conn_01x08_Shielded +Connector_Generic_Shielded:Conn_01x09_Shielded +Connector_Generic_Shielded:Conn_01x10_Shielded +Connector_Generic_Shielded:Conn_01x11_Shielded +Connector_Generic_Shielded:Conn_01x12_Shielded +Connector_Generic_Shielded:Conn_01x13_Shielded +Connector_Generic_Shielded:Conn_01x14_Shielded +Connector_Generic_Shielded:Conn_01x15_Shielded +Connector_Generic_Shielded:Conn_01x16_Shielded +Connector_Generic_Shielded:Conn_01x17_Shielded +Connector_Generic_Shielded:Conn_01x18_Shielded +Connector_Generic_Shielded:Conn_01x19_Shielded +Connector_Generic_Shielded:Conn_01x20_Shielded +Connector_Generic_Shielded:Conn_01x21_Shielded +Connector_Generic_Shielded:Conn_01x22_Shielded +Connector_Generic_Shielded:Conn_01x23_Shielded +Connector_Generic_Shielded:Conn_01x24_Shielded +Connector_Generic_Shielded:Conn_01x25_Shielded +Connector_Generic_Shielded:Conn_01x26_Shielded +Connector_Generic_Shielded:Conn_01x27_Shielded +Connector_Generic_Shielded:Conn_01x28_Shielded +Connector_Generic_Shielded:Conn_01x29_Shielded +Connector_Generic_Shielded:Conn_01x30_Shielded +Connector_Generic_Shielded:Conn_01x31_Shielded +Connector_Generic_Shielded:Conn_01x32_Shielded +Connector_Generic_Shielded:Conn_01x33_Shielded +Connector_Generic_Shielded:Conn_01x34_Shielded +Connector_Generic_Shielded:Conn_01x35_Shielded +Connector_Generic_Shielded:Conn_01x36_Shielded +Connector_Generic_Shielded:Conn_01x37_Shielded +Connector_Generic_Shielded:Conn_01x38_Shielded +Connector_Generic_Shielded:Conn_01x39_Shielded +Connector_Generic_Shielded:Conn_01x40_Shielded +Connector_Generic_Shielded:Conn_01x41_Shielded +Connector_Generic_Shielded:Conn_01x42_Shielded +Connector_Generic_Shielded:Conn_01x43_Shielded +Connector_Generic_Shielded:Conn_01x44_Shielded +Connector_Generic_Shielded:Conn_01x45_Shielded +Connector_Generic_Shielded:Conn_01x46_Shielded +Connector_Generic_Shielded:Conn_01x47_Shielded +Connector_Generic_Shielded:Conn_01x48_Shielded +Connector_Generic_Shielded:Conn_01x49_Shielded +Connector_Generic_Shielded:Conn_01x50_Shielded +Connector_Generic_Shielded:Conn_01x51_Shielded +Connector_Generic_Shielded:Conn_01x52_Shielded +Connector_Generic_Shielded:Conn_01x53_Shielded +Connector_Generic_Shielded:Conn_01x54_Shielded +Connector_Generic_Shielded:Conn_01x55_Shielded +Connector_Generic_Shielded:Conn_01x56_Shielded +Connector_Generic_Shielded:Conn_01x57_Shielded +Connector_Generic_Shielded:Conn_01x58_Shielded +Connector_Generic_Shielded:Conn_01x59_Shielded +Connector_Generic_Shielded:Conn_01x60_Shielded +Connector_Generic_Shielded:Conn_02x01_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x01_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x01_Shielded +Connector_Generic_Shielded:Conn_02x02_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x02_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x02_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x02_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x02_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x03_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x03_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x03_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x03_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x03_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x04_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x04_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x04_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x04_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x04_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x05_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x05_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x05_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x05_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x05_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x06_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x06_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x06_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x06_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x06_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x07_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x07_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x07_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x07_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x07_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x08_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x08_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x08_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x08_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x08_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x09_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x09_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x09_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x09_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x09_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x10_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x10_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x10_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x10_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x10_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x11_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x11_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x11_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x11_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x11_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x12_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x12_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x12_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x12_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x12_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x13_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x13_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x13_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x13_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x13_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x14_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x14_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x14_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x14_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x14_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x15_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x15_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x15_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x15_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x15_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x16_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x16_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x16_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x16_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x16_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x17_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x17_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x17_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x17_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x17_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x18_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x18_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x18_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x18_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x18_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x19_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x19_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x19_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x19_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x19_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x20_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x20_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x20_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x20_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x20_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x21_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x21_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x21_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x21_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x21_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x22_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x22_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x22_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x22_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x22_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x23_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x23_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x23_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x23_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x23_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x24_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x24_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x24_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x24_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x24_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x25_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x25_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x25_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x25_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x25_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x26_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x26_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x26_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x26_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x26_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x27_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x27_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x27_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x27_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x27_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x28_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x28_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x28_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x28_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x28_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x29_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x29_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x29_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x29_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x29_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x30_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x30_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x30_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x30_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x30_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x31_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x31_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x31_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x31_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x31_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x32_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x32_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x32_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x32_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x32_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x33_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x33_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x33_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x33_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x33_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x34_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x34_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x34_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x34_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x34_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x35_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x35_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x35_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x35_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x35_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x36_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x36_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x36_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x36_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x36_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x37_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x37_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x37_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x37_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x37_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x38_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x38_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x38_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x38_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x38_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x39_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x39_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x39_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x39_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x39_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x40_Counter_Clockwise_Shielded +Connector_Generic_Shielded:Conn_02x40_Odd_Even_Shielded +Connector_Generic_Shielded:Conn_02x40_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x40_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x40_Top_Bottom_Shielded +Connector_Generic_Shielded:Conn_02x40_Top_Bottom_Shielded_1 +Connector_Generic_Shielded:Conn_02x41_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x41_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x42_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x42_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x43_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x43_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x44_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x44_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x45_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x45_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x46_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x46_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x47_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x47_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x48_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x48_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x49_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x49_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x50_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x50_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x51_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x51_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x52_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x52_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x53_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x53_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x54_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x54_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x55_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x55_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x56_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x56_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x57_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x57_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x58_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x58_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x59_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x59_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_02x60_Row_Letter_First_Shielded +Connector_Generic_Shielded:Conn_02x60_Row_Letter_Last_Shielded +Connector_Generic_Shielded:Conn_2Rows-05Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-07Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-09Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-11Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-13Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-15Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-17Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-19Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-21Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-23Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-25Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-27Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-29Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-31Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-33Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-35Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-37Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-39Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-41Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-43Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-45Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-47Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-49Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-51Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-53Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-55Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-57Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-59Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-61Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-63Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-65Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-67Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-69Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-71Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-73Pins_Shielded +Connector_Generic_Shielded:Conn_2Rows-75Pins_Shielded +Converter_ACDC:BAC05S05DC +Converter_ACDC:HLK-10M03 +Converter_ACDC:HLK-10M05 +Converter_ACDC:HLK-10M09 +Converter_ACDC:HLK-10M12 +Converter_ACDC:HLK-10M15 +Converter_ACDC:HLK-10M24 +Converter_ACDC:HLK-12M03A +Converter_ACDC:HLK-12M05A +Converter_ACDC:HLK-12M09A +Converter_ACDC:HLK-12M12A +Converter_ACDC:HLK-12M15A +Converter_ACDC:HLK-12M24A +Converter_ACDC:HLK-20M05 +Converter_ACDC:HLK-20M09 +Converter_ACDC:HLK-20M12 +Converter_ACDC:HLK-20M15 +Converter_ACDC:HLK-20M24 +Converter_ACDC:HLK-2M03 +Converter_ACDC:HLK-2M05 +Converter_ACDC:HLK-2M09 +Converter_ACDC:HLK-2M12 +Converter_ACDC:HLK-2M15 +Converter_ACDC:HLK-2M24 +Converter_ACDC:HLK-30M05 +Converter_ACDC:HLK-30M05C +Converter_ACDC:HLK-30M09 +Converter_ACDC:HLK-30M09C +Converter_ACDC:HLK-30M12 +Converter_ACDC:HLK-30M12C +Converter_ACDC:HLK-30M15 +Converter_ACDC:HLK-30M15C +Converter_ACDC:HLK-30M24 +Converter_ACDC:HLK-30M24C +Converter_ACDC:HLK-5M03 +Converter_ACDC:HLK-5M05 +Converter_ACDC:HLK-5M09 +Converter_ACDC:HLK-5M12 +Converter_ACDC:HLK-5M15 +Converter_ACDC:HLK-5M24 +Converter_ACDC:HLK-PM01 +Converter_ACDC:HLK-PM03 +Converter_ACDC:HLK-PM09 +Converter_ACDC:HLK-PM12 +Converter_ACDC:HLK-PM15 +Converter_ACDC:HLK-PM24 +Converter_ACDC:HS-40003 +Converter_ACDC:HS-40005 +Converter_ACDC:HS-40009 +Converter_ACDC:HS-40012 +Converter_ACDC:HS-40015 +Converter_ACDC:HS-40018 +Converter_ACDC:HS-40024 +Converter_ACDC:IRM-02-12 +Converter_ACDC:IRM-02-12S +Converter_ACDC:IRM-02-15 +Converter_ACDC:IRM-02-15S +Converter_ACDC:IRM-02-24 +Converter_ACDC:IRM-02-24S +Converter_ACDC:IRM-02-3.3 +Converter_ACDC:IRM-02-3.3S +Converter_ACDC:IRM-02-5 +Converter_ACDC:IRM-02-5S +Converter_ACDC:IRM-02-9 +Converter_ACDC:IRM-02-9S +Converter_ACDC:IRM-03-12 +Converter_ACDC:IRM-03-12S +Converter_ACDC:IRM-03-15 +Converter_ACDC:IRM-03-15S +Converter_ACDC:IRM-03-24 +Converter_ACDC:IRM-03-24S +Converter_ACDC:IRM-03-3.3 +Converter_ACDC:IRM-03-3.3S +Converter_ACDC:IRM-03-5 +Converter_ACDC:IRM-03-5S +Converter_ACDC:IRM-03-9 +Converter_ACDC:IRM-03-9S +Converter_ACDC:IRM-05-12 +Converter_ACDC:IRM-05-15 +Converter_ACDC:IRM-05-24 +Converter_ACDC:IRM-05-3.3 +Converter_ACDC:IRM-05-5 +Converter_ACDC:IRM-10-12 +Converter_ACDC:IRM-10-15 +Converter_ACDC:IRM-10-24 +Converter_ACDC:IRM-10-3.3 +Converter_ACDC:IRM-10-5 +Converter_ACDC:IRM-20-12 +Converter_ACDC:IRM-20-15 +Converter_ACDC:IRM-20-24 +Converter_ACDC:IRM-20-3.3 +Converter_ACDC:IRM-20-5 +Converter_ACDC:IRM-60-12 +Converter_ACDC:IRM-60-15 +Converter_ACDC:IRM-60-24 +Converter_ACDC:IRM-60-48 +Converter_ACDC:IRM-60-5 +Converter_ACDC:MFM-10-12 +Converter_ACDC:MFM-10-15 +Converter_ACDC:MFM-10-24 +Converter_ACDC:MFM-10-3.3 +Converter_ACDC:MFM-10-5 +Converter_ACDC:MFM-15-12 +Converter_ACDC:MFM-15-15 +Converter_ACDC:MFM-15-24 +Converter_ACDC:MFM-15-3.3 +Converter_ACDC:MFM-15-5 +Converter_ACDC:PBO-3-S12 +Converter_ACDC:PBO-3-S15 +Converter_ACDC:PBO-3-S24 +Converter_ACDC:PBO-3-S3.3 +Converter_ACDC:PBO-3-S5 +Converter_ACDC:PBO-3-S9 +Converter_ACDC:RAC01-05SGB +Converter_ACDC:RAC01-12SGB +Converter_ACDC:RAC01-24SGB +Converter_ACDC:RAC01-3.3SGB +Converter_ACDC:RAC01-xxSGB +Converter_ACDC:RAC04-05SGA +Converter_ACDC:RAC04-05SGB +Converter_ACDC:RAC04-09SGA +Converter_ACDC:RAC04-09SGB +Converter_ACDC:RAC04-12SGA +Converter_ACDC:RAC04-12SGB +Converter_ACDC:RAC04-15SGA +Converter_ACDC:RAC04-15SGB +Converter_ACDC:RAC04-24SGA +Converter_ACDC:RAC04-24SGB +Converter_ACDC:RAC04-3.3SGA +Converter_ACDC:RAC04-3.3SGB +Converter_ACDC:RAC04-xxSGA +Converter_ACDC:RAC04-xxSGB +Converter_ACDC:RAC05-05SK +Converter_ACDC:RAC05-12SK +Converter_ACDC:RAC05-15SK +Converter_ACDC:RAC05-24SK +Converter_ACDC:RAC05-3.3SK +Converter_ACDC:RAC20-05SK +Converter_ACDC:RAC20-12DK +Converter_ACDC:RAC20-12SK +Converter_ACDC:RAC20-15DK +Converter_ACDC:RAC20-15SK +Converter_ACDC:RAC20-24SK +Converter_ACDC:RAC20-48SK +Converter_ACDC:TMF05105 +Converter_ACDC:TMF05112 +Converter_ACDC:TMF05115 +Converter_ACDC:TMF05124 +Converter_ACDC:TMF10105 +Converter_ACDC:TMF10112 +Converter_ACDC:TMF10115 +Converter_ACDC:TMF10124 +Converter_ACDC:TMF20105 +Converter_ACDC:TMF20112 +Converter_ACDC:TMF20115 +Converter_ACDC:TMF20124 +Converter_ACDC:TMF30105 +Converter_ACDC:TMF30112 +Converter_ACDC:TMF30115 +Converter_ACDC:TMF30124 +Converter_ACDC:TMLM04103 +Converter_ACDC:TMLM04105 +Converter_ACDC:TMLM04109 +Converter_ACDC:TMLM04112 +Converter_ACDC:TMLM04115 +Converter_ACDC:TMLM04124 +Converter_ACDC:TMLM04225 +Converter_ACDC:TMLM04253 +Converter_ACDC:TMLM05103 +Converter_ACDC:TMLM05105 +Converter_ACDC:TMLM05112 +Converter_ACDC:TMLM05115 +Converter_ACDC:TMLM05124 +Converter_ACDC:TMLM10103 +Converter_ACDC:TMLM10105 +Converter_ACDC:TMLM10112 +Converter_ACDC:TMLM10115 +Converter_ACDC:TMLM10124 +Converter_ACDC:TMLM20103 +Converter_ACDC:TMLM20105 +Converter_ACDC:TMLM20112 +Converter_ACDC:TMLM20115 +Converter_ACDC:TMLM20124 +Converter_ACDC:TPP-15-103-D +Converter_ACDC:TPP-15-105-D +Converter_ACDC:TPP-15-109-D +Converter_ACDC:TPP-15-112-D +Converter_ACDC:TPP-15-115-D +Converter_ACDC:TPP-15-124-D +Converter_ACDC:TPP-15-136-D +Converter_ACDC:TPP-15-148-D +Converter_ACDC:VTX-214-010-103 +Converter_ACDC:VTX-214-010-105 +Converter_ACDC:VTX-214-010-106 +Converter_ACDC:VTX-214-010-107 +Converter_ACDC:VTX-214-010-108 +Converter_ACDC:VTX-214-010-109 +Converter_ACDC:VTX-214-010-110 +Converter_ACDC:VTX-214-010-112 +Converter_ACDC:VTX-214-010-115 +Converter_ACDC:VTX-214-010-118 +Converter_ACDC:VTX-214-010-124 +Converter_ACDC:VTX-214-010-148 +Converter_ACDC:VTX-214-015-103 +Converter_ACDC:VTX-214-015-105 +Converter_ACDC:VTX-214-015-106 +Converter_ACDC:VTX-214-015-107 +Converter_ACDC:VTX-214-015-109 +Converter_ACDC:VTX-214-015-112 +Converter_ACDC:VTX-214-015-115 +Converter_ACDC:VTX-214-015-118 +Converter_ACDC:VTX-214-015-124 +Converter_ACDC:VTX-214-015-148 +Converter_DCDC:ATA00A18S-L +Converter_DCDC:ATA00A36S-L +Converter_DCDC:ATA00AA18S-L +Converter_DCDC:ATA00AA36S-L +Converter_DCDC:ATA00B18S-L +Converter_DCDC:ATA00B36S-L +Converter_DCDC:ATA00BB18S-L +Converter_DCDC:ATA00BB36S-L +Converter_DCDC:ATA00C18S-L +Converter_DCDC:ATA00C36S-L +Converter_DCDC:ATA00CC18S-L +Converter_DCDC:ATA00CC36S-L +Converter_DCDC:ATA00F18S-L +Converter_DCDC:ATA00F36S-L +Converter_DCDC:ATA00H18S-L +Converter_DCDC:ATA00H36S-L +Converter_DCDC:Ag9905LP +Converter_DCDC:BD8314NUV +Converter_DCDC:IA0305D +Converter_DCDC:IA0305S +Converter_DCDC:IA0503D +Converter_DCDC:IA0503S +Converter_DCDC:IA0505D +Converter_DCDC:IA0505S +Converter_DCDC:IA0509D +Converter_DCDC:IA0509S +Converter_DCDC:IA0512D +Converter_DCDC:IA0512S +Converter_DCDC:IA0515D +Converter_DCDC:IA0515S +Converter_DCDC:IA0524D +Converter_DCDC:IA0524S +Converter_DCDC:IA1203D +Converter_DCDC:IA1203S +Converter_DCDC:IA1205D +Converter_DCDC:IA1205S +Converter_DCDC:IA1209D +Converter_DCDC:IA1209S +Converter_DCDC:IA1212D +Converter_DCDC:IA1212S +Converter_DCDC:IA1215D +Converter_DCDC:IA1215S +Converter_DCDC:IA1224D +Converter_DCDC:IA1224S +Converter_DCDC:IA2403D +Converter_DCDC:IA2403S +Converter_DCDC:IA2405D +Converter_DCDC:IA2405S +Converter_DCDC:IA2409D +Converter_DCDC:IA2409S +Converter_DCDC:IA2412D +Converter_DCDC:IA2412S +Converter_DCDC:IA2415D +Converter_DCDC:IA2415S +Converter_DCDC:IA2424D +Converter_DCDC:IA2424S +Converter_DCDC:IA4803D +Converter_DCDC:IA4803S +Converter_DCDC:IA4805D +Converter_DCDC:IA4805S +Converter_DCDC:IA4809D +Converter_DCDC:IA4809S +Converter_DCDC:IA4812D +Converter_DCDC:IA4812S +Converter_DCDC:IA4815D +Converter_DCDC:IA4815S +Converter_DCDC:IA4824D +Converter_DCDC:IA4824S +Converter_DCDC:IH0503D +Converter_DCDC:IH0503DH +Converter_DCDC:IH0503S +Converter_DCDC:IH0503SH +Converter_DCDC:IH0505D +Converter_DCDC:IH0505DH +Converter_DCDC:IH0505S +Converter_DCDC:IH0505SH +Converter_DCDC:IH0509D +Converter_DCDC:IH0509DH +Converter_DCDC:IH0509S +Converter_DCDC:IH0509SH +Converter_DCDC:IH0512D +Converter_DCDC:IH0512DH +Converter_DCDC:IH0512S +Converter_DCDC:IH0512SH +Converter_DCDC:IH0515D +Converter_DCDC:IH0515DH +Converter_DCDC:IH0515S +Converter_DCDC:IH0515SH +Converter_DCDC:IH0524D +Converter_DCDC:IH0524DH +Converter_DCDC:IH0524S +Converter_DCDC:IH0524SH +Converter_DCDC:IH1203D +Converter_DCDC:IH1203DH +Converter_DCDC:IH1203S +Converter_DCDC:IH1203SH +Converter_DCDC:IH1205D +Converter_DCDC:IH1205DH +Converter_DCDC:IH1205S +Converter_DCDC:IH1205SH +Converter_DCDC:IH1209D +Converter_DCDC:IH1209DH +Converter_DCDC:IH1209S +Converter_DCDC:IH1209SH +Converter_DCDC:IH1212D +Converter_DCDC:IH1212DH +Converter_DCDC:IH1212S +Converter_DCDC:IH1212SH +Converter_DCDC:IH1215D +Converter_DCDC:IH1215DH +Converter_DCDC:IH1215S +Converter_DCDC:IH1215SH +Converter_DCDC:IH1224D +Converter_DCDC:IH1224DH +Converter_DCDC:IH1224S +Converter_DCDC:IH1224SH +Converter_DCDC:IH2403D +Converter_DCDC:IH2403DH +Converter_DCDC:IH2403S +Converter_DCDC:IH2403SH +Converter_DCDC:IH2405D +Converter_DCDC:IH2405DH +Converter_DCDC:IH2405S +Converter_DCDC:IH2405SH +Converter_DCDC:IH2409D +Converter_DCDC:IH2409DH +Converter_DCDC:IH2409S +Converter_DCDC:IH2409SH +Converter_DCDC:IH2412D +Converter_DCDC:IH2412DH +Converter_DCDC:IH2412S +Converter_DCDC:IH2412SH +Converter_DCDC:IH2415D +Converter_DCDC:IH2415DH +Converter_DCDC:IH2415S +Converter_DCDC:IH2415SH +Converter_DCDC:IH2424D +Converter_DCDC:IH2424DH +Converter_DCDC:IH2424S +Converter_DCDC:IH2424SH +Converter_DCDC:IH4803D +Converter_DCDC:IH4803DH +Converter_DCDC:IH4803S +Converter_DCDC:IH4803SH +Converter_DCDC:IH4805D +Converter_DCDC:IH4805DH +Converter_DCDC:IH4805S +Converter_DCDC:IH4805SH +Converter_DCDC:IH4809D +Converter_DCDC:IH4809DH +Converter_DCDC:IH4809S +Converter_DCDC:IH4809SH +Converter_DCDC:IH4812D +Converter_DCDC:IH4812DH +Converter_DCDC:IH4812S +Converter_DCDC:IH4812SH +Converter_DCDC:IH4815D +Converter_DCDC:IH4815DH +Converter_DCDC:IH4815S +Converter_DCDC:IH4815SH +Converter_DCDC:IH4824D +Converter_DCDC:IH4824DH +Converter_DCDC:IH4824S +Converter_DCDC:IH4824SH +Converter_DCDC:ISU0205D12 +Converter_DCDC:ISU0205D15 +Converter_DCDC:ISU0205S05 +Converter_DCDC:ISU0205S12 +Converter_DCDC:ISU0205S15 +Converter_DCDC:ISU0205S24 +Converter_DCDC:ISU0224D12 +Converter_DCDC:ISU0224D15 +Converter_DCDC:ISU0224S05 +Converter_DCDC:ISU0224S12 +Converter_DCDC:ISU0224S15 +Converter_DCDC:ISU0224S24 +Converter_DCDC:ISU0248D12 +Converter_DCDC:ISU0248D15 +Converter_DCDC:ISU0248S05 +Converter_DCDC:ISU0248S12 +Converter_DCDC:ISU0248S15 +Converter_DCDC:ISU0248S24 +Converter_DCDC:ITQ2403SA +Converter_DCDC:ITQ2403SA-H +Converter_DCDC:ITQ2405S +Converter_DCDC:ITQ2405S-H +Converter_DCDC:ITQ2405SA +Converter_DCDC:ITQ2405SA-H +Converter_DCDC:ITQ2409SA +Converter_DCDC:ITQ2409SA-H +Converter_DCDC:ITQ2412S +Converter_DCDC:ITQ2412S-H +Converter_DCDC:ITQ2412SA +Converter_DCDC:ITQ2412SA-H +Converter_DCDC:ITQ2415S +Converter_DCDC:ITQ2415S-H +Converter_DCDC:ITQ2415SA +Converter_DCDC:ITQ2415SA-H +Converter_DCDC:ITQ2424SA +Converter_DCDC:ITQ2424SA-H +Converter_DCDC:ITQ4803SA +Converter_DCDC:ITQ4803SA-H +Converter_DCDC:ITQ4805S +Converter_DCDC:ITQ4805S-H +Converter_DCDC:ITQ4805SA +Converter_DCDC:ITQ4805SA-H +Converter_DCDC:ITQ4809SA +Converter_DCDC:ITQ4809SA-H +Converter_DCDC:ITQ4812S +Converter_DCDC:ITQ4812S-H +Converter_DCDC:ITQ4812SA +Converter_DCDC:ITQ4812SA-H +Converter_DCDC:ITQ4815S +Converter_DCDC:ITQ4815S-H +Converter_DCDC:ITQ4815SA +Converter_DCDC:ITQ4815SA-H +Converter_DCDC:ITQ4824SA +Converter_DCDC:ITQ4824SA-H +Converter_DCDC:ITX0503SA +Converter_DCDC:ITX0503SA-H +Converter_DCDC:ITX0503SA-HR +Converter_DCDC:ITX0503SA-R +Converter_DCDC:ITX0505S +Converter_DCDC:ITX0505S-H +Converter_DCDC:ITX0505S-HR +Converter_DCDC:ITX0505S-R +Converter_DCDC:ITX0505SA +Converter_DCDC:ITX0505SA-H +Converter_DCDC:ITX0505SA-HR +Converter_DCDC:ITX0505SA-R +Converter_DCDC:ITX0509SA +Converter_DCDC:ITX0509SA-H +Converter_DCDC:ITX0509SA-HR +Converter_DCDC:ITX0509SA-R +Converter_DCDC:ITX0512S +Converter_DCDC:ITX0512S-H +Converter_DCDC:ITX0512S-HR +Converter_DCDC:ITX0512S-R +Converter_DCDC:ITX0512SA +Converter_DCDC:ITX0512SA-H +Converter_DCDC:ITX0512SA-HR +Converter_DCDC:ITX0512SA-R +Converter_DCDC:ITX0515S +Converter_DCDC:ITX0515S-H +Converter_DCDC:ITX0515S-HR +Converter_DCDC:ITX0515S-R +Converter_DCDC:ITX0515SA +Converter_DCDC:ITX0515SA-H +Converter_DCDC:ITX0515SA-HR +Converter_DCDC:ITX0515SA-R +Converter_DCDC:ITX0524SA +Converter_DCDC:ITX0524SA-H +Converter_DCDC:ITX0524SA-HR +Converter_DCDC:ITX0524SA-R +Converter_DCDC:ITX1203SA +Converter_DCDC:ITX1203SA-H +Converter_DCDC:ITX1203SA-HR +Converter_DCDC:ITX1203SA-R +Converter_DCDC:ITX1205S +Converter_DCDC:ITX1205S-H +Converter_DCDC:ITX1205S-HR +Converter_DCDC:ITX1205S-R +Converter_DCDC:ITX1205SA +Converter_DCDC:ITX1205SA-H +Converter_DCDC:ITX1205SA-HR +Converter_DCDC:ITX1205SA-R +Converter_DCDC:ITX1209SA +Converter_DCDC:ITX1209SA-H +Converter_DCDC:ITX1209SA-HR +Converter_DCDC:ITX1209SA-R +Converter_DCDC:ITX1212S +Converter_DCDC:ITX1212S-H +Converter_DCDC:ITX1212S-HR +Converter_DCDC:ITX1212S-R +Converter_DCDC:ITX1212SA +Converter_DCDC:ITX1212SA-H +Converter_DCDC:ITX1212SA-HR +Converter_DCDC:ITX1212SA-R +Converter_DCDC:ITX1215S +Converter_DCDC:ITX1215S-H +Converter_DCDC:ITX1215S-HR +Converter_DCDC:ITX1215S-R +Converter_DCDC:ITX1215SA +Converter_DCDC:ITX1215SA-H +Converter_DCDC:ITX1215SA-HR +Converter_DCDC:ITX1215SA-R +Converter_DCDC:ITX1224SA +Converter_DCDC:ITX1224SA-H +Converter_DCDC:ITX1224SA-HR +Converter_DCDC:ITX1224SA-R +Converter_DCDC:ITX2403SA +Converter_DCDC:ITX2403SA-H +Converter_DCDC:ITX2403SA-HR +Converter_DCDC:ITX2403SA-R +Converter_DCDC:ITX2405S +Converter_DCDC:ITX2405S-H +Converter_DCDC:ITX2405S-HR +Converter_DCDC:ITX2405S-R +Converter_DCDC:ITX2405SA +Converter_DCDC:ITX2405SA-H +Converter_DCDC:ITX2405SA-HR +Converter_DCDC:ITX2405SA-R +Converter_DCDC:ITX2409SA +Converter_DCDC:ITX2409SA-H +Converter_DCDC:ITX2409SA-HR +Converter_DCDC:ITX2409SA-R +Converter_DCDC:ITX2412S +Converter_DCDC:ITX2412S-H +Converter_DCDC:ITX2412S-HR +Converter_DCDC:ITX2412S-R +Converter_DCDC:ITX2412SA +Converter_DCDC:ITX2412SA-H +Converter_DCDC:ITX2412SA-HR +Converter_DCDC:ITX2412SA-R +Converter_DCDC:ITX2415S +Converter_DCDC:ITX2415S-H +Converter_DCDC:ITX2415S-HR +Converter_DCDC:ITX2415S-R +Converter_DCDC:ITX2415SA +Converter_DCDC:ITX2415SA-H +Converter_DCDC:ITX2415SA-HR +Converter_DCDC:ITX2415SA-R +Converter_DCDC:ITX2424SA +Converter_DCDC:ITX2424SA-H +Converter_DCDC:ITX2424SA-HR +Converter_DCDC:ITX2424SA-R +Converter_DCDC:ITX4803SA +Converter_DCDC:ITX4803SA-H +Converter_DCDC:ITX4803SA-HR +Converter_DCDC:ITX4803SA-R +Converter_DCDC:ITX4805S +Converter_DCDC:ITX4805S-H +Converter_DCDC:ITX4805S-HR +Converter_DCDC:ITX4805S-R +Converter_DCDC:ITX4805SA +Converter_DCDC:ITX4805SA-H +Converter_DCDC:ITX4805SA-HR +Converter_DCDC:ITX4805SA-R +Converter_DCDC:ITX4809SA +Converter_DCDC:ITX4809SA-H +Converter_DCDC:ITX4809SA-HR +Converter_DCDC:ITX4809SA-R +Converter_DCDC:ITX4812S +Converter_DCDC:ITX4812S-H +Converter_DCDC:ITX4812S-HR +Converter_DCDC:ITX4812S-R +Converter_DCDC:ITX4812SA +Converter_DCDC:ITX4812SA-H +Converter_DCDC:ITX4812SA-HR +Converter_DCDC:ITX4812SA-R +Converter_DCDC:ITX4815S +Converter_DCDC:ITX4815S-H +Converter_DCDC:ITX4815S-HR +Converter_DCDC:ITX4815S-R +Converter_DCDC:ITX4815SA +Converter_DCDC:ITX4815SA-H +Converter_DCDC:ITX4815SA-HR +Converter_DCDC:ITX4815SA-R +Converter_DCDC:ITX4824SA +Converter_DCDC:ITX4824SA-H +Converter_DCDC:ITX4824SA-HR +Converter_DCDC:ITX4824SA-R +Converter_DCDC:JTD1524D05 +Converter_DCDC:JTD1524D12 +Converter_DCDC:JTD1524D15 +Converter_DCDC:JTD1524S05 +Converter_DCDC:JTD1524S12 +Converter_DCDC:JTD1524S15 +Converter_DCDC:JTD1524S3V3 +Converter_DCDC:JTD1548D05 +Converter_DCDC:JTD1548D12 +Converter_DCDC:JTD1548D15 +Converter_DCDC:JTD1548S05 +Converter_DCDC:JTD1548S12 +Converter_DCDC:JTD1548S15 +Converter_DCDC:JTD1548S3V3 +Converter_DCDC:JTD2024D05 +Converter_DCDC:JTD2024D12 +Converter_DCDC:JTD2024D15 +Converter_DCDC:JTD2024S05 +Converter_DCDC:JTD2024S12 +Converter_DCDC:JTD2024S15 +Converter_DCDC:JTD2024S3V3 +Converter_DCDC:JTD2048D05 +Converter_DCDC:JTD2048D12 +Converter_DCDC:JTD2048D15 +Converter_DCDC:JTD2048S05 +Converter_DCDC:JTD2048S12 +Converter_DCDC:JTD2048S15 +Converter_DCDC:JTD2048S3V3 +Converter_DCDC:JTE0624D03 +Converter_DCDC:JTE0624D05 +Converter_DCDC:JTE0624D12 +Converter_DCDC:JTE0624D15 +Converter_DCDC:JTE0624D24 +Converter_DCDC:LT1026 +Converter_DCDC:MEE1S0303SC +Converter_DCDC:MEE1S0305SC +Converter_DCDC:MEE1S0309SC +Converter_DCDC:MEE1S0312SC +Converter_DCDC:MEE1S0315SC +Converter_DCDC:MEE1S0503SC +Converter_DCDC:MEE1S0505SC +Converter_DCDC:MEE1S0509SC +Converter_DCDC:MEE1S0512SC +Converter_DCDC:MEE1S0515SC +Converter_DCDC:MEE1S1205SC +Converter_DCDC:MEE1S1209SC +Converter_DCDC:MEE1S1212SC +Converter_DCDC:MEE1S1215SC +Converter_DCDC:MEE1S1505SC +Converter_DCDC:MEE1S1509SC +Converter_DCDC:MEE1S1512SC +Converter_DCDC:MEE1S1515SC +Converter_DCDC:MEE1S2405SC +Converter_DCDC:MEE1S2409SC +Converter_DCDC:MEE1S2412SC +Converter_DCDC:MEE1S2415SC +Converter_DCDC:MEE3S0505SC +Converter_DCDC:MEE3S0509SC +Converter_DCDC:MEE3S0512SC +Converter_DCDC:MEE3S0515SC +Converter_DCDC:MEE3S1205SC +Converter_DCDC:MEE3S1209SC +Converter_DCDC:MEE3S1212SC +Converter_DCDC:MEE3S1215SC +Converter_DCDC:MGJ2D051505SC +Converter_DCDC:MGJ2D051509SC +Converter_DCDC:MGJ2D051515SC +Converter_DCDC:MGJ2D051802SC +Converter_DCDC:MGJ2D052003SC +Converter_DCDC:MGJ2D052005SC +Converter_DCDC:MGJ2D121505SC +Converter_DCDC:MGJ2D121509SC +Converter_DCDC:MGJ2D121802SC +Converter_DCDC:MGJ2D122003SC +Converter_DCDC:MGJ2D122005SC +Converter_DCDC:MGJ2D151505SC +Converter_DCDC:MGJ2D151509SC +Converter_DCDC:MGJ2D151515SC +Converter_DCDC:MGJ2D151802SC +Converter_DCDC:MGJ2D152003SC +Converter_DCDC:MGJ2D152005SC +Converter_DCDC:MGJ2D241505SC +Converter_DCDC:MGJ2D241509SC +Converter_DCDC:MGJ2D241709SC +Converter_DCDC:MGJ2D241802SC +Converter_DCDC:MGJ2D242003SC +Converter_DCDC:MGJ2D242005SC +Converter_DCDC:MGJ3T05150505MC +Converter_DCDC:MGJ3T12150505MC +Converter_DCDC:MGJ3T24150505MC +Converter_DCDC:MYRGPxx0060x21RC +Converter_DCDC:MYRGPxx0060x21RF +Converter_DCDC:NCS1S1203SC +Converter_DCDC:NCS1S1205SC +Converter_DCDC:NCS1S1212SC +Converter_DCDC:NCS1S2403SC +Converter_DCDC:NCS1S2405SC +Converter_DCDC:NCS1S2412SC +Converter_DCDC:NSD10-xxDyy +Converter_DCDC:NSD10-xxSyy +Converter_DCDC:OKI-78SR-12_1.0-W36-C +Converter_DCDC:OKI-78SR-12_1.0-W36H-C +Converter_DCDC:OKI-78SR-3.3_1.5-W36-C +Converter_DCDC:OKI-78SR-3.3_1.5-W36H-C +Converter_DCDC:OKI-78SR-5_1.5-W36-C +Converter_DCDC:OKI-78SR-5_1.5-W36H-C +Converter_DCDC:PTN78000H_EUS-5 +Converter_DCDC:PTN78000W_EUS-5 +Converter_DCDC:PTN78020H_EUK-7 +Converter_DCDC:PTN78020W_EUK-7 +Converter_DCDC:PTN78060H_EUW-7 +Converter_DCDC:PTN78060W_EUW-7 +Converter_DCDC:RPA60-2405SFW +Converter_DCDC:RPA60-2412SFW +Converter_DCDC:RPA60-2415SFW +Converter_DCDC:RPA60-2424SFW +Converter_DCDC:RPM3.3-1.0 +Converter_DCDC:RPM3.3-2.0 +Converter_DCDC:RPM3.3-3.0 +Converter_DCDC:RPM3.3-6.0 +Converter_DCDC:RPM5.0-1.0 +Converter_DCDC:RPM5.0-2.0 +Converter_DCDC:RPM5.0-3.0 +Converter_DCDC:RPM5.0-6.0 +Converter_DCDC:RPMH12-1.5 +Converter_DCDC:RPMH15-1.5 +Converter_DCDC:RPMH24-1.5 +Converter_DCDC:RPMH3.3-1.5 +Converter_DCDC:RPMH5.0-1.5 +Converter_DCDC:TBA1-0511E +Converter_DCDC:TBA1-0512E +Converter_DCDC:TBA1-0513E +Converter_DCDC:TBA1-0521E +Converter_DCDC:TBA1-0522E +Converter_DCDC:TBA1-0523E +Converter_DCDC:TBA1-1211E +Converter_DCDC:TBA1-1212E +Converter_DCDC:TBA1-1213E +Converter_DCDC:TBA1-1221E +Converter_DCDC:TBA1-1222E +Converter_DCDC:TBA1-1223E +Converter_DCDC:TBA1-2411E +Converter_DCDC:TBA1-2412E +Converter_DCDC:TBA1-2413E +Converter_DCDC:TBA1-2421E +Converter_DCDC:TBA1-2422E +Converter_DCDC:TBA1-2423E +Converter_DCDC:TBA2-0511 +Converter_DCDC:TBA2-0512 +Converter_DCDC:TBA2-0513 +Converter_DCDC:TBA2-0521 +Converter_DCDC:TBA2-0522 +Converter_DCDC:TBA2-0523 +Converter_DCDC:TBA2-1211 +Converter_DCDC:TBA2-1212 +Converter_DCDC:TBA2-1213 +Converter_DCDC:TBA2-1221 +Converter_DCDC:TBA2-1222 +Converter_DCDC:TBA2-1223 +Converter_DCDC:TBA2-2411 +Converter_DCDC:TBA2-2412 +Converter_DCDC:TBA2-2413 +Converter_DCDC:TBA2-2421 +Converter_DCDC:TBA2-2422 +Converter_DCDC:TBA2-2423 +Converter_DCDC:TC7662AxPA +Converter_DCDC:TC7662Bx0A +Converter_DCDC:TC7662BxPA +Converter_DCDC:TDU1-0511 +Converter_DCDC:TDU1-0512 +Converter_DCDC:TDU1-0513 +Converter_DCDC:TDU1-1211 +Converter_DCDC:TDU1-1212 +Converter_DCDC:TDU1-1213 +Converter_DCDC:TDU1-2411 +Converter_DCDC:TDU1-2412 +Converter_DCDC:TDU1-2413 +Converter_DCDC:TEA1-0505 +Converter_DCDC:TEA1-0505E +Converter_DCDC:TEA1-0505HI +Converter_DCDC:TEC2-1210WI +Converter_DCDC:TEC2-1211WI +Converter_DCDC:TEC2-1212WI +Converter_DCDC:TEC2-1213WI +Converter_DCDC:TEC2-1215WI +Converter_DCDC:TEC2-1219WI +Converter_DCDC:TEC2-2410WI +Converter_DCDC:TEC2-2411WI +Converter_DCDC:TEC2-2412WI +Converter_DCDC:TEC2-2413WI +Converter_DCDC:TEC2-2415WI +Converter_DCDC:TEC2-2419WI +Converter_DCDC:TEC2-4810WI +Converter_DCDC:TEC2-4811WI +Converter_DCDC:TEC2-4812WI +Converter_DCDC:TEC2-4813WI +Converter_DCDC:TEC2-4815WI +Converter_DCDC:TEC2-4819WI +Converter_DCDC:TEC3-2410UI +Converter_DCDC:TEC3-2411UI +Converter_DCDC:TEC3-2412UI +Converter_DCDC:TEC3-2413UI +Converter_DCDC:TEC3-2421UI +Converter_DCDC:TEC3-2422UI +Converter_DCDC:TEC3-2423UI +Converter_DCDC:TEL12-1211 +Converter_DCDC:TEL12-1212 +Converter_DCDC:TEL12-1213 +Converter_DCDC:TEL12-1215 +Converter_DCDC:TEL12-1222 +Converter_DCDC:TEL12-1223 +Converter_DCDC:TEL12-2411 +Converter_DCDC:TEL12-2411WI +Converter_DCDC:TEL12-2412 +Converter_DCDC:TEL12-2412WI +Converter_DCDC:TEL12-2413 +Converter_DCDC:TEL12-2413WI +Converter_DCDC:TEL12-2415 +Converter_DCDC:TEL12-2415WI +Converter_DCDC:TEL12-2422 +Converter_DCDC:TEL12-2422WI +Converter_DCDC:TEL12-2423 +Converter_DCDC:TEL12-2423WI +Converter_DCDC:TEL12-4811 +Converter_DCDC:TEL12-4811WI +Converter_DCDC:TEL12-4812 +Converter_DCDC:TEL12-4812WI +Converter_DCDC:TEL12-4813 +Converter_DCDC:TEL12-4813WI +Converter_DCDC:TEL12-4815 +Converter_DCDC:TEL12-4815WI +Converter_DCDC:TEL12-4822 +Converter_DCDC:TEL12-4822WI +Converter_DCDC:TEL12-4823 +Converter_DCDC:TEL12-4823WI +Converter_DCDC:TEN10-11010WIRH +Converter_DCDC:TEN10-11011WIRH +Converter_DCDC:TEN10-11012WIRH +Converter_DCDC:TEN10-11013WIRH +Converter_DCDC:TEN10-11015WIRH +Converter_DCDC:TEN10-11021WIRH +Converter_DCDC:TEN10-11022WIRH +Converter_DCDC:TEN10-11023WIRH +Converter_DCDC:TEN20-11011WIRH +Converter_DCDC:TEN20-11012WIRH +Converter_DCDC:TEN20-11013WIRH +Converter_DCDC:TEN20-11015WIRH +Converter_DCDC:TEN20-11021WIRH +Converter_DCDC:TEN20-11022WIRH +Converter_DCDC:TEN20-11023WIRH +Converter_DCDC:TEN20-2410WIN +Converter_DCDC:TEN20-2411WIN +Converter_DCDC:TEN20-2412WIN +Converter_DCDC:TEN20-2413WIN +Converter_DCDC:TEN20-2421WIN +Converter_DCDC:TEN20-2422WIN +Converter_DCDC:TEN20-2423WIN +Converter_DCDC:TEN20-4810WIN +Converter_DCDC:TEN20-4811WIN +Converter_DCDC:TEN20-4812WIN +Converter_DCDC:TEN20-4813WIN +Converter_DCDC:TEN20-4821WIN +Converter_DCDC:TEN20-4822WIN +Converter_DCDC:TEN20-4823WIN +Converter_DCDC:TEN3-11010WIRH +Converter_DCDC:TEN3-11011WIRH +Converter_DCDC:TEN3-11012WIRH +Converter_DCDC:TEN3-11013WIRH +Converter_DCDC:TEN3-11015WIRH +Converter_DCDC:TEN3-11021WIRH +Converter_DCDC:TEN3-11022WIRH +Converter_DCDC:TEN3-11023WIRH +Converter_DCDC:TEN40-11011WIRH +Converter_DCDC:TEN40-11012WIRH +Converter_DCDC:TEN40-11013WIRH +Converter_DCDC:TEN40-11015WIRH +Converter_DCDC:TEN40-11022WIRH +Converter_DCDC:TEN40-11023WIRH +Converter_DCDC:TEN6-11010WIRH +Converter_DCDC:TEN6-11011WIRH +Converter_DCDC:TEN6-11012WIRH +Converter_DCDC:TEN6-11013WIRH +Converter_DCDC:TEN6-11015WIRH +Converter_DCDC:TEN6-11021WIRH +Converter_DCDC:TEN6-11022WIRH +Converter_DCDC:TEN6-11023WIRH +Converter_DCDC:THB10-1211 +Converter_DCDC:THB10-1212 +Converter_DCDC:THB10-1222 +Converter_DCDC:THB10-1223 +Converter_DCDC:THB10-2411 +Converter_DCDC:THB10-2412 +Converter_DCDC:THB10-2422 +Converter_DCDC:THB10-2423 +Converter_DCDC:THB10-4811 +Converter_DCDC:THB10-4812 +Converter_DCDC:THB10-4822 +Converter_DCDC:THB10-4823 +Converter_DCDC:THR40-7211WI +Converter_DCDC:THR40-7212WI +Converter_DCDC:THR40-7213WI +Converter_DCDC:THR40-72154WI +Converter_DCDC:THR40-7215WI +Converter_DCDC:THR40-7222WI +Converter_DCDC:THR40-7223WI +Converter_DCDC:TMA-0505D +Converter_DCDC:TMA-0505S +Converter_DCDC:TMA-0512D +Converter_DCDC:TMA-0512S +Converter_DCDC:TMA-0515D +Converter_DCDC:TMA-0515S +Converter_DCDC:TMA-1205D +Converter_DCDC:TMA-1205S +Converter_DCDC:TMA-1212D +Converter_DCDC:TMA-1212S +Converter_DCDC:TMA-1215D +Converter_DCDC:TMA-1215S +Converter_DCDC:TMA-1505D +Converter_DCDC:TMA-1505S +Converter_DCDC:TMA-1512D +Converter_DCDC:TMA-1512S +Converter_DCDC:TMA-1515D +Converter_DCDC:TMA-1515S +Converter_DCDC:TMA-2405D +Converter_DCDC:TMA-2405S +Converter_DCDC:TMA-2412D +Converter_DCDC:TMA-2412S +Converter_DCDC:TMA-2415D +Converter_DCDC:TMA-2415S +Converter_DCDC:TME-0303S +Converter_DCDC:TME-0305S +Converter_DCDC:TME-0503S +Converter_DCDC:TME-0505S +Converter_DCDC:TME-0509S +Converter_DCDC:TME-0512S +Converter_DCDC:TME-0515S +Converter_DCDC:TME-1205S +Converter_DCDC:TME-1209S +Converter_DCDC:TME-1212S +Converter_DCDC:TME-1215S +Converter_DCDC:TME-2405S +Converter_DCDC:TME-2409S +Converter_DCDC:TME-2412S +Converter_DCDC:TME-2415S +Converter_DCDC:TMR-0510 +Converter_DCDC:TMR-0511 +Converter_DCDC:TMR-0512 +Converter_DCDC:TMR-1210 +Converter_DCDC:TMR-1211 +Converter_DCDC:TMR-1212 +Converter_DCDC:TMR-2410 +Converter_DCDC:TMR-2411 +Converter_DCDC:TMR-2412 +Converter_DCDC:TMR-4810 +Converter_DCDC:TMR-4811 +Converter_DCDC:TMR-4812 +Converter_DCDC:TMR2-2410WI +Converter_DCDC:TMR2-2411WI +Converter_DCDC:TMR2-2412WI +Converter_DCDC:TMR2-2413WI +Converter_DCDC:TMR2-4810WI +Converter_DCDC:TMR2-4811WI +Converter_DCDC:TMR2-4812WI +Converter_DCDC:TMR2-4813WI +Converter_DCDC:TMR4-2411WI +Converter_DCDC:TMR4-2412WI +Converter_DCDC:TMR4-2413WI +Converter_DCDC:TMR4-2415WI +Converter_DCDC:TMR4-2422WI +Converter_DCDC:TMR4-2423WI +Converter_DCDC:TMR4-4811WI +Converter_DCDC:TMR4-4812WI +Converter_DCDC:TMR4-4813WI +Converter_DCDC:TMR4-4815WI +Converter_DCDC:TMR4-4822WI +Converter_DCDC:TMR4-4823WI +Converter_DCDC:TMU3-0511 +Converter_DCDC:TMU3-0512 +Converter_DCDC:TMU3-0513 +Converter_DCDC:TMU3-1211 +Converter_DCDC:TMU3-1212 +Converter_DCDC:TMU3-1213 +Converter_DCDC:TMU3-2411 +Converter_DCDC:TMU3-2412 +Converter_DCDC:TMU3-2413 +Converter_DCDC:TPS43060RTE +Converter_DCDC:TPS54240DGQ +Converter_DCDC:TPS54240DRC +Converter_DCDC:TPS61022 +Converter_DCDC:TPSM53602RDA +Converter_DCDC:TPSM53603RDA +Converter_DCDC:TPSM53604RDA +Converter_DCDC:TRA3-0511 +Converter_DCDC:TRA3-0512 +Converter_DCDC:TRA3-0513 +Converter_DCDC:TRA3-0519 +Converter_DCDC:TRA3-1211 +Converter_DCDC:TRA3-1212 +Converter_DCDC:TRA3-1213 +Converter_DCDC:TRA3-1219 +Converter_DCDC:TRA3-2411 +Converter_DCDC:TRA3-2412 +Converter_DCDC:TRA3-2413 +Converter_DCDC:TRA3-2419 +Converter_DCDC:TRI1-0511 +Converter_DCDC:TRI1-0512 +Converter_DCDC:TRI1-0513 +Converter_DCDC:TRI1-1211 +Converter_DCDC:TRI1-1212 +Converter_DCDC:TRI1-1213 +Converter_DCDC:TRI1-2411 +Converter_DCDC:TRI1-2412 +Converter_DCDC:TRI1-2413 +CPLD_Altera:EP1210 +CPLD_Altera:EP1810 +CPLD_Altera:EP300 +CPLD_Altera:EP310 +CPLD_Altera:EP320 +CPLD_Altera:EP600 +CPLD_Altera:EP910 +CPLD_Altera:EPM1270F256 +CPLD_Altera:EPM1270M256 +CPLD_Altera:EPM1270T144 +CPLD_Altera:EPM2210F256 +CPLD_Altera:EPM2210F324 +CPLD_Altera:EPM240F100 +CPLD_Altera:EPM240M100 +CPLD_Altera:EPM240T100 +CPLD_Altera:EPM240ZM100 +CPLD_Altera:EPM240ZM68 +CPLD_Altera:EPM570F100 +CPLD_Altera:EPM570F256 +CPLD_Altera:EPM570M100 +CPLD_Altera:EPM570M256 +CPLD_Altera:EPM570T100 +CPLD_Altera:EPM570T144 +CPLD_Altera:EPM570ZM100 +CPLD_Altera:EPM570ZM144 +CPLD_Altera:EPM570ZM256 +CPLD_Microchip:ATF1502AS-xAx44 +CPLD_Microchip:ATF1502ASL-xAx44 +CPLD_Microchip:ATF1502ASV-xAx44 +CPLD_Microchip:ATF1504AS-xAx44 +CPLD_Microchip:ATF1504ASL-xAx44 +CPLD_Microchip:ATF1504ASV-xAx44 +CPLD_Microchip:ATF1504ASVL-xAx44 +CPLD_Renesas:SLG46826G +CPLD_Xilinx:XC7336 +CPLD_Xilinx:XC95108PC84 +CPLD_Xilinx:XC95108PQ100 +CPLD_Xilinx:XC95144PQ100 +CPLD_Xilinx:XC95144XL-TQ100 +CPLD_Xilinx:XC95144XL-TQ144 +CPLD_Xilinx:XC9536PC44 +CPLD_Xilinx:XC9572XL-TQ100 +CPLD_Xilinx:XC9572XL-VQ64 +CPLD_Xilinx:XCR3064-VQ100 +CPLD_Xilinx:XCR3064-VQ44 +CPLD_Xilinx:XCR3064XL-VQ100 +CPLD_Xilinx:XCR3064XL-VQ44 +CPLD_Xilinx:XCR3128-VQ100 +CPLD_Xilinx:XCR3128XL-VQ100 +CPLD_Xilinx:XCR3256-TQ144 +CPLD_Xilinx:XCR3256XL-TQ144 +CPU:CDP1802ACE +CPU:CDP1802ACEX +CPU:CDP1802BCE +CPU:CDP1802BCEX +CPU:P4080-BGA1295 +CPU:Z80CPU +CPU_NXP_6800:MC6800 +CPU_NXP_6800:MC6802 +CPU_NXP_6800:MC6809 +CPU_NXP_6800:MC6809E +CPU_NXP_6800:MC68A00 +CPU_NXP_6800:MC68A02 +CPU_NXP_6800:MC68A09 +CPU_NXP_6800:MC68A09E +CPU_NXP_6800:MC68B00 +CPU_NXP_6800:MC68B02 +CPU_NXP_6800:MC68B09 +CPU_NXP_6800:MC68B09E +CPU_NXP_68000:68000D +CPU_NXP_68000:68008D +CPU_NXP_68000:68010D +CPU_NXP_68000:MC68000FN +CPU_NXP_68000:MC68332 +CPU_NXP_IMX:MCIMX6D4AVT +CPU_NXP_IMX:MCIMX6D5EYM +CPU_NXP_IMX:MCIMX6D6AVT +CPU_NXP_IMX:MCIMX6D7CVT +CPU_NXP_IMX:MCIMX6DP4AVT +CPU_NXP_IMX:MCIMX6DP5EVT +CPU_NXP_IMX:MCIMX6DP5EYM +CPU_NXP_IMX:MCIMX6DP6AVT +CPU_NXP_IMX:MCIMX6DP7CVT +CPU_NXP_IMX:MCIMX6Q4AVT +CPU_NXP_IMX:MCIMX6Q5EYM +CPU_NXP_IMX:MCIMX6Q6AVT +CPU_NXP_IMX:MCIMX6Q7CVT +CPU_NXP_IMX:MCIMX6QP4AVT +CPU_NXP_IMX:MCIMX6QP5EVT +CPU_NXP_IMX:MCIMX6QP5EYM +CPU_NXP_IMX:MCIMX6QP6AVT +CPU_NXP_IMX:MCIMX6QP7CVT +CPU_PowerPC:MPC8641D +Device:Ammeter_AC +Device:Ammeter_DC +Device:Antenna +Device:Antenna_Chip +Device:Antenna_Dipole +Device:Antenna_Loop +Device:Antenna_Shield +Device:Battery +Device:Battery_Cell +Device:Buzzer +Device:C +Device:C_45deg +Device:C_Feedthrough +Device:C_Network04 +Device:C_Network05 +Device:C_Network06 +Device:C_Network07 +Device:C_Network08 +Device:C_Polarized +Device:C_Polarized_Series_2C +Device:C_Polarized_Small +Device:C_Polarized_Small_Series_2C +Device:C_Polarized_Small_US +Device:C_Polarized_Small_US_Series_2C +Device:C_Polarized_US +Device:C_Polarized_US_Series_2C +Device:C_Small +Device:C_Trim +Device:C_Trim_Differential +Device:C_Trim_Small +Device:C_Variable +Device:CircuitBreaker_1P +Device:CircuitBreaker_1P_US +Device:CircuitBreaker_2P +Device:CircuitBreaker_2P_US +Device:CircuitBreaker_3P +Device:CircuitBreaker_3P_US +Device:Crystal +Device:Crystal_GND2 +Device:Crystal_GND23 +Device:Crystal_GND23_Small +Device:Crystal_GND24 +Device:Crystal_GND24_Small +Device:Crystal_GND2_Small +Device:Crystal_GND3 +Device:Crystal_GND3_Small +Device:Crystal_Small +Device:D +Device:DIAC +Device:DIAC_Filled +Device:D_45deg +Device:D_45deg_Filled +Device:D_AAK +Device:D_Bridge_+-AA +Device:D_Bridge_+A-A +Device:D_Bridge_+AA- +Device:D_Bridge_-A+A +Device:D_Bridge_-AA+ +Device:D_Capacitance +Device:D_Capacitance_Filled +Device:D_Current-regulator +Device:D_Current-regulator_Small +Device:D_Dual_CommonAnode_AKK +Device:D_Dual_CommonAnode_AKK_Parallel +Device:D_Dual_CommonAnode_AKK_Split +Device:D_Dual_CommonAnode_KAK +Device:D_Dual_CommonAnode_KAK_Parallel +Device:D_Dual_CommonAnode_KAK_Split +Device:D_Dual_CommonAnode_KKA +Device:D_Dual_CommonAnode_KKA_Parallel +Device:D_Dual_CommonAnode_KKA_Split +Device:D_Dual_CommonCathode_AAK +Device:D_Dual_CommonCathode_AAK_Parallel +Device:D_Dual_CommonCathode_AAK_Split +Device:D_Dual_CommonCathode_AKA +Device:D_Dual_CommonCathode_AKA_Parallel +Device:D_Dual_CommonCathode_AKA_Split +Device:D_Dual_CommonCathode_KAA +Device:D_Dual_CommonCathode_KAA_Parallel +Device:D_Dual_CommonCathode_KAA_Split +Device:D_Dual_Series_ACK +Device:D_Dual_Series_ACK_Parallel +Device:D_Dual_Series_ACK_Split +Device:D_Dual_Series_AKC +Device:D_Dual_Series_AKC_Parallel +Device:D_Dual_Series_AKC_Split +Device:D_Dual_Series_CAK +Device:D_Dual_Series_CAK_Parallel +Device:D_Dual_Series_CAK_Split +Device:D_Dual_Series_CKA +Device:D_Dual_Series_CKA_Parallel +Device:D_Dual_Series_CKA_Split +Device:D_Dual_Series_KAC +Device:D_Dual_Series_KAC_Parallel +Device:D_Dual_Series_KAC_Split +Device:D_Dual_Series_KCA +Device:D_Dual_Series_KCA_Parallel +Device:D_Dual_Series_KCA_Split +Device:D_Filled +Device:D_KAA +Device:D_KAK +Device:D_KKA +Device:D_Laser_1A3C +Device:D_Laser_1C2A +Device:D_Laser_Photo_MType +Device:D_Laser_Photo_NType +Device:D_Laser_Photo_PType +Device:D_Photo +Device:D_Photo_Filled +Device:D_Radiation +Device:D_Radiation_Filled +Device:D_Schottky +Device:D_Schottky_AAK +Device:D_Schottky_AKA +Device:D_Schottky_AKK +Device:D_Schottky_Dual_CommonAnode_AKK +Device:D_Schottky_Dual_CommonAnode_AKK_Parallel +Device:D_Schottky_Dual_CommonAnode_AKK_Split +Device:D_Schottky_Dual_CommonAnode_KAK +Device:D_Schottky_Dual_CommonAnode_KAK_Parallel +Device:D_Schottky_Dual_CommonAnode_KAK_Split +Device:D_Schottky_Dual_CommonAnode_KKA +Device:D_Schottky_Dual_CommonAnode_KKA_Parallel +Device:D_Schottky_Dual_CommonAnode_KKA_Split +Device:D_Schottky_Dual_CommonCathode_AAK +Device:D_Schottky_Dual_CommonCathode_AAK_Parallel +Device:D_Schottky_Dual_CommonCathode_AAK_Split +Device:D_Schottky_Dual_CommonCathode_AKA +Device:D_Schottky_Dual_CommonCathode_AKA_Parallel +Device:D_Schottky_Dual_CommonCathode_AKA_Split +Device:D_Schottky_Dual_CommonCathode_KAA +Device:D_Schottky_Dual_CommonCathode_KAA_Parallel +Device:D_Schottky_Dual_CommonCathode_KAA_Split +Device:D_Schottky_Dual_Series_ACK +Device:D_Schottky_Dual_Series_ACK_Parallel +Device:D_Schottky_Dual_Series_ACK_Split +Device:D_Schottky_Dual_Series_AKC +Device:D_Schottky_Dual_Series_AKC_Parallel +Device:D_Schottky_Dual_Series_AKC_Split +Device:D_Schottky_Dual_Series_CAK +Device:D_Schottky_Dual_Series_CAK_Parallel +Device:D_Schottky_Dual_Series_CAK_Split +Device:D_Schottky_Dual_Series_CKA +Device:D_Schottky_Dual_Series_CKA_Parallel +Device:D_Schottky_Dual_Series_CKA_Split +Device:D_Schottky_Dual_Series_KAC +Device:D_Schottky_Dual_Series_KAC_Parallel +Device:D_Schottky_Dual_Series_KAC_Split +Device:D_Schottky_Dual_Series_KCA +Device:D_Schottky_Dual_Series_KCA_Parallel +Device:D_Schottky_Dual_Series_KCA_Split +Device:D_Schottky_Filled +Device:D_Schottky_KAA +Device:D_Schottky_KAK +Device:D_Schottky_KKA +Device:D_Schottky_Small +Device:D_Schottky_Small_Filled +Device:D_Shockley +Device:D_SiPM +Device:D_Small +Device:D_Small_Filled +Device:D_TVS +Device:D_TVS_Dual_AAC +Device:D_TVS_Dual_ACA +Device:D_TVS_Dual_CAA +Device:D_TVS_Filled +Device:D_TVS_Small +Device:D_TVS_Small_Filled +Device:D_TemperatureDependent +Device:D_TemperatureDependent_Filled +Device:D_Tunnel +Device:D_Tunnel_Filled +Device:D_Unitunnel +Device:D_Unitunnel_Filled +Device:D_Zener +Device:D_Zener_Dual_CommonAnode_AKK +Device:D_Zener_Dual_CommonAnode_AKK_Parallel +Device:D_Zener_Dual_CommonAnode_AKK_Split +Device:D_Zener_Dual_CommonAnode_KAK +Device:D_Zener_Dual_CommonAnode_KAK_Parallel +Device:D_Zener_Dual_CommonAnode_KAK_Split +Device:D_Zener_Dual_CommonAnode_KKA +Device:D_Zener_Dual_CommonAnode_KKA_Parallel +Device:D_Zener_Dual_CommonAnode_KKA_Split +Device:D_Zener_Dual_CommonCathode_AAK +Device:D_Zener_Dual_CommonCathode_AAK_Parallel +Device:D_Zener_Dual_CommonCathode_AAK_Split +Device:D_Zener_Dual_CommonCathode_AKA +Device:D_Zener_Dual_CommonCathode_AKA_Parallel +Device:D_Zener_Dual_CommonCathode_AKA_Split +Device:D_Zener_Dual_CommonCathode_KAA +Device:D_Zener_Dual_CommonCathode_KAA_Parallel +Device:D_Zener_Dual_CommonCathode_KAA_Split +Device:D_Zener_Filled +Device:D_Zener_Small +Device:D_Zener_Small_Filled +Device:DelayLine +Device:Earphone +Device:ElectromagneticActor +Device:FerriteBead +Device:FerriteBead_Small +Device:Filter_EMI_C +Device:Filter_EMI_CLC +Device:Filter_EMI_CommonMode +Device:Filter_EMI_LCL +Device:Filter_EMI_LL +Device:Filter_EMI_LLL +Device:Filter_EMI_LLLL +Device:Filter_EMI_LLLL_15263748 +Device:Filter_EMI_LLL_162534 +Device:Filter_EMI_LL_1423 +Device:FrequencyCounter +Device:Fuse +Device:Fuse_Polarized +Device:Fuse_Polarized_Small +Device:Fuse_Small +Device:GDT_2Pin +Device:GDT_3Pin +Device:Galvanometer +Device:HallGenerator +Device:Heater +Device:L +Device:LED +Device:LED_45deg +Device:LED_45deg_Filled +Device:LED_ABGR +Device:LED_ABRG +Device:LED_AGBR +Device:LED_AGRB +Device:LED_ARBG +Device:LED_ARGB +Device:LED_BAGR +Device:LED_BARG +Device:LED_BGAR +Device:LED_BGKR +Device:LED_BGRA +Device:LED_BGRK +Device:LED_BKGR +Device:LED_BKRG +Device:LED_BRAG +Device:LED_BRGA +Device:LED_BRGK +Device:LED_BRKG +Device:LED_Dual_AAK +Device:LED_Dual_AAKK +Device:LED_Dual_AKA +Device:LED_Dual_AKAK +Device:LED_Dual_AKKA +Device:LED_Dual_Bidirectional +Device:LED_Dual_KAK +Device:LED_Dual_KAKA +Device:LED_Dual_KKA +Device:LED_Filled +Device:LED_GABR +Device:LED_GARB +Device:LED_GBAR +Device:LED_GBKR +Device:LED_GBRA +Device:LED_GBRK +Device:LED_GKBR +Device:LED_GKRB +Device:LED_GRAB +Device:LED_GRBA +Device:LED_GRBK +Device:LED_GRKB +Device:LED_KBGR +Device:LED_KBRG +Device:LED_KGBR +Device:LED_KGRB +Device:LED_KRBG +Device:LED_KRGB +Device:LED_Pad +Device:LED_RABG +Device:LED_RAGB +Device:LED_RBAG +Device:LED_RBGA +Device:LED_RBGK +Device:LED_RBKG +Device:LED_RGAB +Device:LED_RGB +Device:LED_RGBA +Device:LED_RGBK +Device:LED_RGB_EP +Device:LED_RGKB +Device:LED_RKBG +Device:LED_RKGB +Device:LED_Series +Device:LED_Series_Pad +Device:LED_Small +Device:LED_Small_Filled +Device:L_45deg +Device:L_Coupled +Device:L_Coupled_1243 +Device:L_Coupled_1324 +Device:L_Coupled_1342 +Device:L_Coupled_1423 +Device:L_Coupled_Small +Device:L_Coupled_Small_1243 +Device:L_Coupled_Small_1324 +Device:L_Coupled_Small_1342 +Device:L_Coupled_Small_1423 +Device:L_Ferrite +Device:L_Ferrite_Coupled +Device:L_Ferrite_Coupled_1243 +Device:L_Ferrite_Coupled_1324 +Device:L_Ferrite_Coupled_1342 +Device:L_Ferrite_Coupled_1423 +Device:L_Ferrite_Coupled_Small +Device:L_Ferrite_Coupled_Small_1243 +Device:L_Ferrite_Coupled_Small_1324 +Device:L_Ferrite_Coupled_Small_1342 +Device:L_Ferrite_Coupled_Small_1423 +Device:L_Ferrite_Small +Device:L_Iron +Device:L_Iron_Coupled +Device:L_Iron_Coupled_1243 +Device:L_Iron_Coupled_1324 +Device:L_Iron_Coupled_1342 +Device:L_Iron_Coupled_1423 +Device:L_Iron_Coupled_Small +Device:L_Iron_Coupled_Small_1243 +Device:L_Iron_Coupled_Small_1324 +Device:L_Iron_Coupled_Small_1342 +Device:L_Iron_Coupled_Small_1423 +Device:L_Iron_Small +Device:L_Pack04 +Device:L_Small +Device:L_Trim +Device:Lamp +Device:Lamp_Flash +Device:Lamp_Neon +Device:Memristor +Device:Microphone +Device:Microphone_Condenser +Device:Microphone_Crystal +Device:Microphone_Ultrasound +Device:NetTie_2 +Device:NetTie_3 +Device:NetTie_3_Tee +Device:NetTie_4 +Device:NetTie_4_Cross +Device:Ohmmeter +Device:Opamp_Dual +Device:Opamp_Quad +Device:Oscilloscope +Device:PeltierElement +Device:Polyfuse +Device:Polyfuse_Small +Device:Q_NIGBT_CEG +Device:Q_NIGBT_CGE +Device:Q_NIGBT_ECG +Device:Q_NIGBT_ECGC +Device:Q_NIGBT_EGC +Device:Q_NIGBT_GCE +Device:Q_NIGBT_GCEC +Device:Q_NIGBT_GEC +Device:Q_NJFET_DGS +Device:Q_NJFET_DSG +Device:Q_NJFET_GDS +Device:Q_NJFET_GSD +Device:Q_NJFET_SDG +Device:Q_NJFET_SGD +Device:Q_NMOS +Device:Q_NMOS_Depletion +Device:Q_NPN +Device:Q_NPN_BRT +Device:Q_NPN_BRT_No_R2 +Device:Q_NPN_CurrentMirror +Device:Q_NPN_Darlington +Device:Q_NUJT_BEB +Device:Q_PJFET_DGS +Device:Q_PJFET_DSG +Device:Q_PJFET_GDS +Device:Q_PJFET_GSD +Device:Q_PJFET_SDG +Device:Q_PJFET_SGD +Device:Q_PMOS +Device:Q_PMOS_Depletion +Device:Q_PNP +Device:Q_PNP_BRT +Device:Q_PNP_BRT_No_R2 +Device:Q_PNP_CurrentMirror +Device:Q_PNP_Darlington +Device:Q_PUJT_BEB +Device:Q_Photo_NPN +Device:Q_Photo_NPN_CBE +Device:Q_Photo_NPN_CE +Device:Q_Photo_NPN_EBC +Device:Q_Photo_NPN_EC +Device:Q_SCR_AGK +Device:Q_SCR_AKG +Device:Q_SCR_GAK +Device:Q_SCR_GKA +Device:Q_SCR_KAG +Device:Q_SCR_KGA +Device:Q_Triac +Device:R +Device:RFShield_OnePiece +Device:RFShield_TwoPieces +Device:R_45deg +Device:R_Network03 +Device:R_Network03_Split +Device:R_Network03_US +Device:R_Network04 +Device:R_Network04_Split +Device:R_Network04_US +Device:R_Network05 +Device:R_Network05_Split +Device:R_Network05_US +Device:R_Network06 +Device:R_Network06_Split +Device:R_Network06_US +Device:R_Network07 +Device:R_Network07_Split +Device:R_Network07_US +Device:R_Network08 +Device:R_Network08_Split +Device:R_Network08_US +Device:R_Network09 +Device:R_Network09_Split +Device:R_Network09_US +Device:R_Network10 +Device:R_Network10_Split +Device:R_Network10_US +Device:R_Network11 +Device:R_Network11_Split +Device:R_Network11_US +Device:R_Network12 +Device:R_Network12_Split +Device:R_Network12_US +Device:R_Network13 +Device:R_Network13_Split +Device:R_Network13_US +Device:R_Network_Dividers_x02_SIP +Device:R_Network_Dividers_x03_SIP +Device:R_Network_Dividers_x04_SIP +Device:R_Network_Dividers_x05_SIP +Device:R_Network_Dividers_x06_SIP +Device:R_Network_Dividers_x07_SIP +Device:R_Network_Dividers_x08_SIP +Device:R_Network_Dividers_x09_SIP +Device:R_Network_Dividers_x10_SIP +Device:R_Network_Dividers_x11_SIP +Device:R_Pack02 +Device:R_Pack02_SIP +Device:R_Pack02_SIP_Split +Device:R_Pack02_Split +Device:R_Pack03 +Device:R_Pack03_SIP +Device:R_Pack03_SIP_Split +Device:R_Pack03_Split +Device:R_Pack04 +Device:R_Pack04_SIP +Device:R_Pack04_SIP_Split +Device:R_Pack04_Split +Device:R_Pack05 +Device:R_Pack05_SIP +Device:R_Pack05_SIP_Split +Device:R_Pack05_Split +Device:R_Pack06 +Device:R_Pack06_SIP +Device:R_Pack06_SIP_Split +Device:R_Pack06_Split +Device:R_Pack07 +Device:R_Pack07_SIP +Device:R_Pack07_SIP_Split +Device:R_Pack07_Split +Device:R_Pack08 +Device:R_Pack08_Split +Device:R_Pack09 +Device:R_Pack09_Split +Device:R_Pack10 +Device:R_Pack10_Split +Device:R_Pack11 +Device:R_Pack11_Split +Device:R_Photo +Device:R_Potentiometer +Device:R_Potentiometer_Dual +Device:R_Potentiometer_Dual_MountingPin +Device:R_Potentiometer_Dual_Separate +Device:R_Potentiometer_MountingPin +Device:R_Potentiometer_Small +Device:R_Potentiometer_Trim +Device:R_Potentiometer_Trim_US +Device:R_Potentiometer_US +Device:R_Shunt +Device:R_Shunt_US +Device:R_Small +Device:R_Small_US +Device:R_Trim +Device:R_US +Device:R_Variable +Device:R_Variable_US +Device:Resonator +Device:Resonator_Small +Device:RotaryEncoder +Device:RotaryEncoder_Switch +Device:RotaryEncoder_Switch_MP +Device:Solar_Cell +Device:Solar_Cells +Device:SparkGap +Device:Speaker +Device:Speaker_Crystal +Device:Speaker_Ultrasound +Device:Thermistor +Device:Thermistor_NTC +Device:Thermistor_NTC_3Wire +Device:Thermistor_NTC_4Wire +Device:Thermistor_NTC_US +Device:Thermistor_PTC +Device:Thermistor_PTC_3Wire +Device:Thermistor_PTC_4Wire +Device:Thermistor_PTC_US +Device:Thermistor_US +Device:Thermocouple +Device:Thermocouple_Alt +Device:Thermocouple_Block +Device:Transformer_1P_1S +Device:Transformer_1P_1S_SO8 +Device:Transformer_1P_2S +Device:Transformer_1P_SS +Device:Transformer_Audio +Device:Transformer_SP_1S +Device:Transformer_SP_2S +Device:Varistor +Device:Varistor_US +Device:VoltageDivider +Device:VoltageDivider_CenterPin1 +Device:VoltageDivider_CenterPin3 +Device:Voltmeter_AC +Device:Voltmeter_DC +Diode:1.5KExxA +Diode:1.5KExxCA +Diode:1.5SMCxxA +Diode:1.5SMCxxCA +Diode:1N4001 +Diode:1N4002 +Diode:1N4003 +Diode:1N4004 +Diode:1N4005 +Diode:1N4006 +Diode:1N4007 +Diode:1N4148 +Diode:1N4148W +Diode:1N4148WS +Diode:1N4148WT +Diode:1N4149 +Diode:1N4151 +Diode:1N4448 +Diode:1N4448W +Diode:1N4448WS +Diode:1N4448WT +Diode:1N47xxA +Diode:1N4933 +Diode:1N4934 +Diode:1N4935 +Diode:1N4936 +Diode:1N4937 +Diode:1N53xxB +Diode:1N5400 +Diode:1N5401 +Diode:1N5402 +Diode:1N5403 +Diode:1N5404 +Diode:1N5405 +Diode:1N5406 +Diode:1N5407 +Diode:1N5408 +Diode:1N5711 +Diode:1N5711UR +Diode:1N5712 +Diode:1N5712UR +Diode:1N5817 +Diode:1N5818 +Diode:1N5819 +Diode:1N5819WS +Diode:1N5820 +Diode:1N5821 +Diode:1N5822 +Diode:1N5908 +Diode:1N6263 +Diode:1N62xxA +Diode:1N62xxCA +Diode:1N630xA +Diode:1N630xCA +Diode:1N6857 +Diode:1N6857UR +Diode:1N6858 +Diode:1N6858UR +Diode:1N914 +Diode:1N914WT +Diode:1SS355VM +Diode:2BZX84Cxx +Diode:5KPxxA +Diode:5KPxxCA +Diode:B120-E3 +Diode:B130-E3 +Diode:B140-E3 +Diode:B150-E3 +Diode:B160-E3 +Diode:B220 +Diode:B230 +Diode:B240 +Diode:B250 +Diode:B260 +Diode:B320 +Diode:B330 +Diode:B340 +Diode:B350 +Diode:B360 +Diode:BA157 +Diode:BA158 +Diode:BA159 +Diode:BA243 +Diode:BA244 +Diode:BA282 +Diode:BA283 +Diode:BAR42FILM +Diode:BAR43FILM +Diode:BAS16TW +Diode:BAS16VY +Diode:BAS16W +Diode:BAS19 +Diode:BAS20 +Diode:BAS21 +Diode:BAS316 +Diode:BAS40-04 +Diode:BAS516 +Diode:BAT160A +Diode:BAT160C +Diode:BAT160S +Diode:BAT41 +Diode:BAT42 +Diode:BAT42W-V +Diode:BAT43 +Diode:BAT43W-V +Diode:BAT46 +Diode:BAT48JFILM +Diode:BAT48RL +Diode:BAT48ZFILM +Diode:BAT54A +Diode:BAT54ADW +Diode:BAT54AW +Diode:BAT54C +Diode:BAT54CW +Diode:BAT54J +Diode:BAT54S +Diode:BAT54SDW +Diode:BAT54SW +Diode:BAT54W +Diode:BAT60A +Diode:BAT85 +Diode:BAT86 +Diode:BAT86S +Diode:BAV16W +Diode:BAV17 +Diode:BAV18 +Diode:BAV19 +Diode:BAV199DW +Diode:BAV20 +Diode:BAV21 +Diode:BAV300 +Diode:BAV301 +Diode:BAV302 +Diode:BAV303 +Diode:BAV70 +Diode:BAV70M +Diode:BAV70S +Diode:BAV70T +Diode:BAV70W +Diode:BAV756S +Diode:BAV99 +Diode:BAV99S +Diode:BAW56DW +Diode:BAW56S +Diode:BAW75 +Diode:BAW76 +Diode:BAY93 +Diode:BYV79-100 +Diode:BYV79-150 +Diode:BYV79-200 +Diode:BZD27Cxx +Diode:BZM55Bxx +Diode:BZM55Cxx +Diode:BZT52Bxx +Diode:BZV55B10 +Diode:BZV55B11 +Diode:BZV55B12 +Diode:BZV55B13 +Diode:BZV55B15 +Diode:BZV55B16 +Diode:BZV55B18 +Diode:BZV55B20 +Diode:BZV55B22 +Diode:BZV55B24 +Diode:BZV55B27 +Diode:BZV55B2V4 +Diode:BZV55B2V7 +Diode:BZV55B30 +Diode:BZV55B33 +Diode:BZV55B36 +Diode:BZV55B39 +Diode:BZV55B3V0 +Diode:BZV55B3V3 +Diode:BZV55B3V6 +Diode:BZV55B3V9 +Diode:BZV55B43 +Diode:BZV55B47 +Diode:BZV55B4V3 +Diode:BZV55B4V7 +Diode:BZV55B51 +Diode:BZV55B56 +Diode:BZV55B5V1 +Diode:BZV55B5V6 +Diode:BZV55B62 +Diode:BZV55B68 +Diode:BZV55B6V2 +Diode:BZV55B6V8 +Diode:BZV55B75 +Diode:BZV55B7V5 +Diode:BZV55B8V2 +Diode:BZV55B9V1 +Diode:BZV55C10 +Diode:BZV55C11 +Diode:BZV55C12 +Diode:BZV55C13 +Diode:BZV55C15 +Diode:BZV55C16 +Diode:BZV55C18 +Diode:BZV55C20 +Diode:BZV55C22 +Diode:BZV55C24 +Diode:BZV55C27 +Diode:BZV55C2V4 +Diode:BZV55C2V7 +Diode:BZV55C30 +Diode:BZV55C33 +Diode:BZV55C36 +Diode:BZV55C39 +Diode:BZV55C3V0 +Diode:BZV55C3V3 +Diode:BZV55C3V6 +Diode:BZV55C3V9 +Diode:BZV55C43 +Diode:BZV55C47 +Diode:BZV55C4V3 +Diode:BZV55C4V7 +Diode:BZV55C51 +Diode:BZV55C56 +Diode:BZV55C5V1 +Diode:BZV55C5V6 +Diode:BZV55C62 +Diode:BZV55C68 +Diode:BZV55C6V2 +Diode:BZV55C6V8 +Diode:BZV55C75 +Diode:BZV55C7V5 +Diode:BZV55C8V2 +Diode:BZV55C9V1 +Diode:BZX384xxxx +Diode:BZX84Cxx +Diode:C3D02060A +Diode:C3D02060E +Diode:C3D02060F +Diode:C3D02065E +Diode:C3D03060A +Diode:C3D03060E +Diode:C3D03060F +Diode:C3D03065E +Diode:C3D04060A +Diode:C3D04060E +Diode:C3D04060F +Diode:C3D04065A +Diode:C3D04065E +Diode:C3D06060A +Diode:C3D06060F +Diode:C3D06060G +Diode:C3D06065A +Diode:C3D06065E +Diode:C3D06065I +Diode:C3D08060A +Diode:C3D08060G +Diode:C3D08065A +Diode:C3D08065E +Diode:C3D08065I +Diode:C3D10060A +Diode:C3D10060G +Diode:C3D10065A +Diode:C3D10065E +Diode:C3D10065I +Diode:C3D10170H +Diode:C3D12065A +Diode:C3D16060D +Diode:C3D16065A +Diode:C3D16065D +Diode:C3D1P7060Q +Diode:C3D20060D +Diode:C3D20065D +Diode:C3D25170H +Diode:C3D30065D +Diode:C4D02120A +Diode:C4D02120E +Diode:C4D05120A +Diode:C4D05120E +Diode:C4D08120A +Diode:C4D08120E +Diode:C4D10120A +Diode:C4D10120D +Diode:C4D10120E +Diode:C4D10120H +Diode:C4D15120A +Diode:C4D15120D +Diode:C4D15120H +Diode:C4D20120A +Diode:C4D20120D +Diode:C4D20120H +Diode:C4D30120D +Diode:C4D40120D +Diode:C5D50065D +Diode:CD4148W +Diode:CDBA3100-HF +Diode:CDBA340-HF +Diode:CDBA360-HF +Diode:CDBU40-HF +Diode:CSD01060A +Diode:CSD01060E +Diode:CVFD20065A +Diode:Central_Semi_CMKD4448 +Diode:Central_Semi_CMKD6001 +Diode:Comchip_ACDSV6-4448TI-G +Diode:Comchip_CDSV6-4148-G +Diode:Comchip_CDSV6-4448TI-G +Diode:DB3 +Diode:DB4 +Diode:DC34 +Diode:DSB2810 +Diode:DSB5712 +Diode:DZ2S030X0L +Diode:DZ2S033X0L +Diode:DZ2S036X0L +Diode:DZ2S039X0L +Diode:DZ2S047X0L +Diode:DZ2S051X0L +Diode:DZ2S056X0L +Diode:DZ2S068X0L +Diode:DZ2S082X0L +Diode:DZ2S100X0L +Diode:DZ2S110X0L +Diode:DZ2S120X0L +Diode:DZ2S130X0L +Diode:DZ2S150X0L +Diode:DZ2S160X0L +Diode:DZ2S180X0L +Diode:DZ2S200X0L +Diode:DZ2S360X0L +Diode:ESD131-B1-W0201 +Diode:ESD5Zxx +Diode:ESD9B3.3ST5G +Diode:ESD9B5.0ST5G +Diode:ESH2PB +Diode:ESH2PC +Diode:ESH2PD +Diode:HN2D02FU +Diode:IDDD04G65C6 +Diode:IDDD06G65C6 +Diode:IDDD08G65C6 +Diode:IDDD10G65C6 +Diode:IDDD12G65C6 +Diode:IDDD16G65C6 +Diode:IDDD20G65C6 +Diode:LL41 +Diode:LL4148 +Diode:LL42 +Diode:LL43 +Diode:LL4448 +Diode:MBR0520 +Diode:MBR0520LT +Diode:MBR0530 +Diode:MBR0540 +Diode:MBR0550 +Diode:MBR0560 +Diode:MBR0570 +Diode:MBR0580 +Diode:MBR1020VL +Diode:MBR340 +Diode:MBR735 +Diode:MBR745 +Diode:MBRA340 +Diode:MBRS340 +Diode:MCL4148 +Diode:MCL4448 +Diode:MM3Zxx +Diode:MM5Zxx +Diode:MMBD4148TW +Diode:MMBD4448HADW +Diode:MMBD4448HCQW +Diode:MMBD4448HTW +Diode:MMBZxx +Diode:MMSD4148 +Diode:MMSD914 +Diode:MRA4003T3G +Diode:MRA4004T3G +Diode:MRA4005T3G +Diode:MRA4006T3G +Diode:MRA4007T3G +Diode:NRVA4003T3G +Diode:NRVA4004T3G +Diode:NRVA4005T3G +Diode:NRVA4006T3G +Diode:NRVA4007T3G +Diode:NSR0340HT1G +Diode:PMEG030V030EPD +Diode:PMEG030V050EPD +Diode:PMEG040V030EPD +Diode:PMEG040V050EPD +Diode:PMEG045T050EPD +Diode:PMEG045T100EPD +Diode:PMEG045T150EIPD +Diode:PMEG045T150EPD +Diode:PMEG045V050EPD +Diode:PMEG045V100EPD +Diode:PMEG045V150EPD +Diode:PMEG050T150EPD +Diode:PMEG050V030EPD +Diode:PMEG050V150EPD +Diode:PMEG060V030EPD +Diode:PMEG060V050EPD +Diode:PMEG060V100EPD +Diode:PMEG10010ELR +Diode:PMEG10020AELR +Diode:PMEG10020ELR +Diode:PMEG100V060ELPD +Diode:PMEG100V080ELPD +Diode:PMEG100V100ELPD +Diode:PMEG1020EH +Diode:PMEG1020EJ +Diode:PMEG1030EH +Diode:PMEG1030EJ +Diode:PMEG2005EH +Diode:PMEG2005EJ +Diode:PMEG2010AEH +Diode:PMEG2010AEJ +Diode:PMEG2010AET +Diode:PMEG2010BER +Diode:PMEG2010EH +Diode:PMEG2010EJ +Diode:PMEG2010ER +Diode:PMEG2010ET +Diode:PMEG2015EH +Diode:PMEG2015EJ +Diode:PMEG2020EH +Diode:PMEG2020EJ +Diode:PMEG3002EJ +Diode:PMEG3005EH +Diode:PMEG3005EJ +Diode:PMEG3010BER +Diode:PMEG3010CEH +Diode:PMEG3010CEJ +Diode:PMEG3010EH +Diode:PMEG3010EJ +Diode:PMEG3010ER +Diode:PMEG3010ET +Diode:PMEG3015EH +Diode:PMEG3015EJ +Diode:PMEG3020BER +Diode:PMEG3020EH +Diode:PMEG3020EJ +Diode:PMEG3020ER +Diode:PMEG4002EJ +Diode:PMEG4005CEJ +Diode:PMEG4005EH +Diode:PMEG4005EJ +Diode:PMEG4010CEH +Diode:PMEG4010CEJ +Diode:PMEG4010EH +Diode:PMEG4010EJ +Diode:PMEG4010ER +Diode:PMEG4010ET +Diode:PMEG4020ER +Diode:PMEG4030ER +Diode:PMEG4050EP +Diode:PMEG40T10ER +Diode:PMEG40T20ER +Diode:PMEG40T30ER +Diode:PMEG45A10EPD +Diode:PMEG45T15EPD +Diode:PMEG45U10EPD +Diode:PMEG6002EJ +Diode:PMEG6010CEH +Diode:PMEG6010CEJ +Diode:PMEG6010ELR +Diode:PMEG6010ER +Diode:PMEG6020AELR +Diode:PMEG6020ELR +Diode:PMEG6020ER +Diode:PMEG6030EP +Diode:PMEG6045ETP +Diode:PMEG60T10ELR +Diode:PMEG60T20ELR +Diode:PMEG60T30ELR +Diode:PTVS10VZ1USK +Diode:PTVS12VZ1USK +Diode:PTVS15VZ1USK +Diode:PTVS18VZ1USK +Diode:PTVS20VZ1USK +Diode:PTVS22VZ1USK +Diode:PTVS26VZ1USK +Diode:PTVS5V0Z1USK +Diode:PTVS5V0Z1USKP +Diode:PTVS7V5Z1USK +Diode:Panasonic_MA5J002E +Diode:RF01VM2S +Diode:Rohm_UMN1N +Diode:Rohm_UMP11N +Diode:S2JTR +Diode:SB120 +Diode:SB130 +Diode:SB140 +Diode:SB150 +Diode:SB160 +Diode:SB5H100 +Diode:SB5H90 +Diode:SD05_SOD323 +Diode:SD103ATW +Diode:SD12_SOD323 +Diode:SD15_SOD323 +Diode:SD24_SOD323 +Diode:SD36_SOD323 +Diode:SM15T36A +Diode:SM15T36CA +Diode:SM15T6V8A +Diode:SM15T6V8CA +Diode:SM15T7V5A +Diode:SM15T7V5CA +Diode:SM2000 +Diode:SM4001 +Diode:SM4002 +Diode:SM4003 +Diode:SM4004 +Diode:SM4005 +Diode:SM4006 +Diode:SM4007 +Diode:SM5059 +Diode:SM5060 +Diode:SM5061 +Diode:SM5062 +Diode:SM5063 +Diode:SM513 +Diode:SM516 +Diode:SM518 +Diode:SM5908 +Diode:SM6T100A +Diode:SM6T10A +Diode:SM6T12A +Diode:SM6T150A +Diode:SM6T15A +Diode:SM6T18A +Diode:SM6T200A +Diode:SM6T220A +Diode:SM6T22A +Diode:SM6T24A +Diode:SM6T27A +Diode:SM6T30A +Diode:SM6T33A +Diode:SM6T36A +Diode:SM6T39A +Diode:SM6T56A +Diode:SM6T68A +Diode:SM6T6V8A +Diode:SM6T75A +Diode:SM6T7V5A +Diode:SM712_SOT23 +Diode:SMAJ100A +Diode:SMAJ100CA +Diode:SMAJ10A +Diode:SMAJ10CA +Diode:SMAJ110A +Diode:SMAJ110CA +Diode:SMAJ11A +Diode:SMAJ11CA +Diode:SMAJ120A +Diode:SMAJ120CA +Diode:SMAJ12A +Diode:SMAJ12CA +Diode:SMAJ130A +Diode:SMAJ130CA +Diode:SMAJ13A +Diode:SMAJ13CA +Diode:SMAJ14A +Diode:SMAJ14CA +Diode:SMAJ150A +Diode:SMAJ150CA +Diode:SMAJ15A +Diode:SMAJ15CA +Diode:SMAJ160A +Diode:SMAJ160CA +Diode:SMAJ16A +Diode:SMAJ16CA +Diode:SMAJ170A +Diode:SMAJ170CA +Diode:SMAJ17A +Diode:SMAJ17CA +Diode:SMAJ180A +Diode:SMAJ180CA +Diode:SMAJ188A +Diode:SMAJ188CA +Diode:SMAJ18A +Diode:SMAJ18CA +Diode:SMAJ200A +Diode:SMAJ200CA +Diode:SMAJ20A +Diode:SMAJ20CA +Diode:SMAJ220A +Diode:SMAJ220CA +Diode:SMAJ22A +Diode:SMAJ22CA +Diode:SMAJ24A +Diode:SMAJ24CA +Diode:SMAJ250A +Diode:SMAJ250CA +Diode:SMAJ26A +Diode:SMAJ26CA +Diode:SMAJ28A +Diode:SMAJ28CA +Diode:SMAJ300A +Diode:SMAJ300CA +Diode:SMAJ30A +Diode:SMAJ30CA +Diode:SMAJ33A +Diode:SMAJ33CA +Diode:SMAJ350A +Diode:SMAJ350CA +Diode:SMAJ36A +Diode:SMAJ36CA +Diode:SMAJ400A +Diode:SMAJ400CA +Diode:SMAJ40A +Diode:SMAJ40CA +Diode:SMAJ43A +Diode:SMAJ43CA +Diode:SMAJ440A +Diode:SMAJ440CA +Diode:SMAJ45A +Diode:SMAJ45CA +Diode:SMAJ48A +Diode:SMAJ48CA +Diode:SMAJ5.0A +Diode:SMAJ5.0CA +Diode:SMAJ51A +Diode:SMAJ51CA +Diode:SMAJ54A +Diode:SMAJ54CA +Diode:SMAJ58A +Diode:SMAJ58CA +Diode:SMAJ6.0A +Diode:SMAJ6.0CA +Diode:SMAJ6.5A +Diode:SMAJ6.5CA +Diode:SMAJ60A +Diode:SMAJ60CA +Diode:SMAJ64A +Diode:SMAJ64CA +Diode:SMAJ7.0A +Diode:SMAJ7.0CA +Diode:SMAJ7.5A +Diode:SMAJ7.5CA +Diode:SMAJ70A +Diode:SMAJ70CA +Diode:SMAJ75A +Diode:SMAJ75CA +Diode:SMAJ78A +Diode:SMAJ78CA +Diode:SMAJ8.0A +Diode:SMAJ8.0CA +Diode:SMAJ8.5A +Diode:SMAJ8.5CA +Diode:SMAJ85A +Diode:SMAJ85CA +Diode:SMAJ9.0A +Diode:SMAJ9.0CA +Diode:SMAJ90A +Diode:SMAJ90CA +Diode:SMF10A +Diode:SMF11A +Diode:SMF12A +Diode:SMF13A +Diode:SMF14A +Diode:SMF15A +Diode:SMF16A +Diode:SMF17A +Diode:SMF18A +Diode:SMF20A +Diode:SMF22A +Diode:SMF24A +Diode:SMF26A +Diode:SMF28A +Diode:SMF30A +Diode:SMF33A +Diode:SMF36A +Diode:SMF40A +Diode:SMF43A +Diode:SMF45A +Diode:SMF48A +Diode:SMF51A +Diode:SMF54A +Diode:SMF58A +Diode:SMF5V0A +Diode:SMF6V0A +Diode:SMF6V5A +Diode:SMF7V0A +Diode:SMF7V5A +Diode:SMF8V0A +Diode:SMF8V5A +Diode:SMF9V0A +Diode:SMZxxx +Diode:SS110 +Diode:SS1150 +Diode:SS12 +Diode:SS1200 +Diode:SS13 +Diode:SS14 +Diode:SS15 +Diode:SS16 +Diode:SS18 +Diode:SS210 +Diode:SS2150 +Diode:SS22 +Diode:SS2200 +Diode:SS23 +Diode:SS24 +Diode:SS25 +Diode:SS26 +Diode:SS28 +Diode:SS310 +Diode:SS3150 +Diode:SS32 +Diode:SS3200 +Diode:SS33 +Diode:SS34 +Diode:SS35 +Diode:SS36 +Diode:SS38 +Diode:STBR3008WY +Diode:STBR3012WY +Diode:STBR6008WY +Diode:STBR6012WY +Diode:STTH2002D +Diode:STTH2002G +Diode:STTH212S +Diode:STTH212U +Diode:SZESD9B5.0ST5G +Diode:Toshiba_HN1D01FU +Diode:UF5400 +Diode:UF5401 +Diode:UF5402 +Diode:UF5403 +Diode:UF5404 +Diode:UF5405 +Diode:UF5406 +Diode:UF5407 +Diode:UF5408 +Diode:US1A +Diode:US1B +Diode:US1D +Diode:US1G +Diode:US1J +Diode:US1K +Diode:US1M +Diode:US2AA +Diode:US2BA +Diode:US2DA +Diode:US2FA +Diode:US2GA +Diode:US2JA +Diode:US2KA +Diode:US2MA +Diode:VS-6ESU06 +Diode:Z1SMAxxx +Diode:Z2SMBxxx +Diode:Z3SMCxxx +Diode:ZMDxx +Diode:ZMMxx +Diode:ZMYxx +Diode:ZPDxx +Diode:ZPYxx +Diode:ZYxxx +Diode_Bridge:ABS10 +Diode_Bridge:ABS2 +Diode_Bridge:ABS4 +Diode_Bridge:ABS6 +Diode_Bridge:ABS8 +Diode_Bridge:B125C1500G +Diode_Bridge:B125C2300-1500A +Diode_Bridge:B125C2300-1500B +Diode_Bridge:B125C3x00-2200A +Diode_Bridge:B125C5000-3x00A +Diode_Bridge:B125C800DM +Diode_Bridge:B125R +Diode_Bridge:B250C1500G +Diode_Bridge:B250C2300-1500A +Diode_Bridge:B250C2300-1500B +Diode_Bridge:B250C3x00-2200A +Diode_Bridge:B250C5000-3x00A +Diode_Bridge:B250C800DM +Diode_Bridge:B250R +Diode_Bridge:B380C1500G +Diode_Bridge:B380C2300-1500A +Diode_Bridge:B380C2300-1500B +Diode_Bridge:B380C3x00-2200A +Diode_Bridge:B380C5000-3x00A +Diode_Bridge:B380C800DM +Diode_Bridge:B380R +Diode_Bridge:B40C1500G +Diode_Bridge:B40C2300-1500A +Diode_Bridge:B40C2300-1500B +Diode_Bridge:B40C3x00-2200A +Diode_Bridge:B40C5000-3x00A +Diode_Bridge:B40C800DM +Diode_Bridge:B40R +Diode_Bridge:B500C2300-1500A +Diode_Bridge:B500C3x00-2200A +Diode_Bridge:B500C5000-3x00A +Diode_Bridge:B500R +Diode_Bridge:B700C2300-1500B +Diode_Bridge:B80C1500G +Diode_Bridge:B80C2300-1500A +Diode_Bridge:B80C2300-1500B +Diode_Bridge:B80C3x00-2200A +Diode_Bridge:B80C5000-3x00A +Diode_Bridge:B80C800DM +Diode_Bridge:B80R +Diode_Bridge:DF005M +Diode_Bridge:DF005S +Diode_Bridge:DF01M +Diode_Bridge:DF01S +Diode_Bridge:DF01S1 +Diode_Bridge:DF02M +Diode_Bridge:DF02S +Diode_Bridge:DF04M +Diode_Bridge:DF04S +Diode_Bridge:DF06M +Diode_Bridge:DF06S +Diode_Bridge:DF08M +Diode_Bridge:DF08S +Diode_Bridge:DF10M +Diode_Bridge:DF10S +Diode_Bridge:DMA40U1800GU +Diode_Bridge:DNA40U2200GU +Diode_Bridge:GBU4A +Diode_Bridge:GBU4B +Diode_Bridge:GBU4D +Diode_Bridge:GBU4G +Diode_Bridge:GBU4J +Diode_Bridge:GBU4K +Diode_Bridge:GBU4M +Diode_Bridge:GBU6A +Diode_Bridge:GBU6B +Diode_Bridge:GBU6D +Diode_Bridge:GBU6G +Diode_Bridge:GBU6J +Diode_Bridge:GBU6K +Diode_Bridge:GBU6M +Diode_Bridge:GBU8A +Diode_Bridge:GBU8B +Diode_Bridge:GBU8D +Diode_Bridge:GBU8G +Diode_Bridge:GBU8J +Diode_Bridge:GBU8K +Diode_Bridge:GBU8M +Diode_Bridge:GUO40-08NO1 +Diode_Bridge:GUO40-12NO1 +Diode_Bridge:GUO40-16NO1 +Diode_Bridge:KBPC15005T +Diode_Bridge:KBPC15005W +Diode_Bridge:KBPC1501T +Diode_Bridge:KBPC1501W +Diode_Bridge:KBPC1502T +Diode_Bridge:KBPC1502W +Diode_Bridge:KBPC1504T +Diode_Bridge:KBPC1504W +Diode_Bridge:KBPC1506T +Diode_Bridge:KBPC1506W +Diode_Bridge:KBPC1508T +Diode_Bridge:KBPC1508W +Diode_Bridge:KBPC1510T +Diode_Bridge:KBPC1510W +Diode_Bridge:KBPC25005T +Diode_Bridge:KBPC25005W +Diode_Bridge:KBPC2501T +Diode_Bridge:KBPC2501W +Diode_Bridge:KBPC2502T +Diode_Bridge:KBPC2502W +Diode_Bridge:KBPC2504T +Diode_Bridge:KBPC2504W +Diode_Bridge:KBPC2506T +Diode_Bridge:KBPC2506W +Diode_Bridge:KBPC2508T +Diode_Bridge:KBPC2508W +Diode_Bridge:KBPC2510T +Diode_Bridge:KBPC2510W +Diode_Bridge:KBPC35005T +Diode_Bridge:KBPC35005W +Diode_Bridge:KBPC3501T +Diode_Bridge:KBPC3501W +Diode_Bridge:KBPC3502T +Diode_Bridge:KBPC3502W +Diode_Bridge:KBPC3504T +Diode_Bridge:KBPC3504W +Diode_Bridge:KBPC3506T +Diode_Bridge:KBPC3506W +Diode_Bridge:KBPC3508T +Diode_Bridge:KBPC3508W +Diode_Bridge:KBPC3510T +Diode_Bridge:KBPC3510W +Diode_Bridge:KBPC50005T +Diode_Bridge:KBPC50005W +Diode_Bridge:KBPC5001T +Diode_Bridge:KBPC5001W +Diode_Bridge:KBPC5002T +Diode_Bridge:KBPC5002W +Diode_Bridge:KBPC5004T +Diode_Bridge:KBPC5004W +Diode_Bridge:KBPC5006T +Diode_Bridge:KBPC5006W +Diode_Bridge:KBPC5008T +Diode_Bridge:KBPC5008W +Diode_Bridge:KBPC5010T +Diode_Bridge:KBPC5010W +Diode_Bridge:KBU4A +Diode_Bridge:KBU4B +Diode_Bridge:KBU4D +Diode_Bridge:KBU4G +Diode_Bridge:KBU4J +Diode_Bridge:KBU4K +Diode_Bridge:KBU4M +Diode_Bridge:KBU6A +Diode_Bridge:KBU6B +Diode_Bridge:KBU6D +Diode_Bridge:KBU6G +Diode_Bridge:KBU6J +Diode_Bridge:KBU6K +Diode_Bridge:KBU6M +Diode_Bridge:KBU8A +Diode_Bridge:KBU8B +Diode_Bridge:KBU8D +Diode_Bridge:KBU8G +Diode_Bridge:KBU8J +Diode_Bridge:KBU8K +Diode_Bridge:KBU8M +Diode_Bridge:MB2S +Diode_Bridge:MB4S +Diode_Bridge:MB6S +Diode_Bridge:MBL104S +Diode_Bridge:MBL106S +Diode_Bridge:MBL108S +Diode_Bridge:MBL110S +Diode_Bridge:MDB10S +Diode_Bridge:MDB6S +Diode_Bridge:MDB8S +Diode_Bridge:RB151 +Diode_Bridge:RB152 +Diode_Bridge:RB153 +Diode_Bridge:RB154 +Diode_Bridge:RB155 +Diode_Bridge:RB156 +Diode_Bridge:RB157 +Diode_Bridge:RMB2S +Diode_Bridge:RMB4S +Diode_Bridge:SC35VB160S-G +Diode_Bridge:SC35VB80S-G +Diode_Bridge:VS-KBPC1005 +Diode_Bridge:VS-KBPC101 +Diode_Bridge:VS-KBPC102 +Diode_Bridge:VS-KBPC104 +Diode_Bridge:VS-KBPC106 +Diode_Bridge:VS-KBPC108 +Diode_Bridge:VS-KBPC110 +Diode_Bridge:VS-KBPC6005 +Diode_Bridge:VS-KBPC601 +Diode_Bridge:VS-KBPC602 +Diode_Bridge:VS-KBPC604 +Diode_Bridge:VS-KBPC606 +Diode_Bridge:VS-KBPC608 +Diode_Bridge:VS-KBPC610 +Diode_Bridge:VS-KBPC8005 +Diode_Bridge:VS-KBPC801 +Diode_Bridge:VS-KBPC802 +Diode_Bridge:VS-KBPC804 +Diode_Bridge:VS-KBPC806 +Diode_Bridge:VS-KBPC808 +Diode_Bridge:VS-KBPC810 +Diode_Bridge:W005G +Diode_Bridge:W01G +Diode_Bridge:W02G +Diode_Bridge:W04G +Diode_Bridge:W06G +Diode_Bridge:W08G +Diode_Bridge:W10G +Diode_Laser:PL520 +Diode_Laser:PLT5_450B +Diode_Laser:PLT5_488 +Diode_Laser:PLT5_510 +Diode_Laser:SPL_PL90 +Display_Character:AD-121F2 +Display_Character:CA56-12CGKWA +Display_Character:CA56-12EWA +Display_Character:CA56-12SEKWA +Display_Character:CA56-12SRWA +Display_Character:CA56-12SURKWA +Display_Character:CA56-12SYKWA +Display_Character:CC56-12CGKWA +Display_Character:CC56-12EWA +Display_Character:CC56-12GWA +Display_Character:CC56-12SEKWA +Display_Character:CC56-12SRWA +Display_Character:CC56-12SURKWA +Display_Character:CC56-12SYKWA +Display_Character:CC56-12YWA +Display_Character:D148K +Display_Character:D168K +Display_Character:D198K +Display_Character:D1X8K-14BL +Display_Character:DA04-11CGKWA +Display_Character:DA04-11EWA +Display_Character:DA04-11GWA +Display_Character:DA04-11SEKWA +Display_Character:DA04-11SRWA +Display_Character:DA04-11SURKWA +Display_Character:DA04-11SYKWA +Display_Character:DA56-11CGKWA +Display_Character:DA56-11EWA +Display_Character:DA56-11GWA +Display_Character:DA56-11SEKWA +Display_Character:DA56-11SRWA +Display_Character:DA56-11SURKWA +Display_Character:DA56-11SYKWA +Display_Character:DA56-11YWA +Display_Character:DC56-11CGKWA +Display_Character:DC56-11EWA +Display_Character:DC56-11GWA +Display_Character:DC56-11SEKWA +Display_Character:DC56-11SRWA +Display_Character:DC56-11SURKWA +Display_Character:DC56-11SYKWA +Display_Character:DC56-11YWA +Display_Character:DE113-XX-XX +Display_Character:DE114-RS-20 +Display_Character:DE122-XX-XX +Display_Character:DE170-XX-XX +Display_Character:EA_T123X-I2C +Display_Character:ELD-426SYGWA +Display_Character:HDSM-441B +Display_Character:HDSM-443B +Display_Character:HDSM-541B +Display_Character:HDSM-543B +Display_Character:HDSP-7401 +Display_Character:HDSP-7403 +Display_Character:HDSP-7501 +Display_Character:HDSP-7503 +Display_Character:HDSP-7507 +Display_Character:HDSP-7508 +Display_Character:HDSP-7801 +Display_Character:HDSP-7803 +Display_Character:HDSP-7807 +Display_Character:HDSP-7808 +Display_Character:HDSP-A151 +Display_Character:HDSP-A153 +Display_Character:HDSP-A401 +Display_Character:HDSP-A403 +Display_Character:HY1602E +Display_Character:KCSA02-105 +Display_Character:KCSA02-106 +Display_Character:KCSA02-107 +Display_Character:KCSA02-123 +Display_Character:KCSA02-136 +Display_Character:KCSC02-105 +Display_Character:KCSC02-106 +Display_Character:KCSC02-107 +Display_Character:KCSC02-123 +Display_Character:KCSC02-136 +Display_Character:LCD-016N002L +Display_Character:LM16255K +Display_Character:LTC-4627JD +Display_Character:LTC-4627JD-01 +Display_Character:LTC-4627JF +Display_Character:LTC-4627JG +Display_Character:LTC-4627JR +Display_Character:LTC-4627JS +Display_Character:LTS-6960HR +Display_Character:LTS-6980HR +Display_Character:MAN3410A +Display_Character:MAN3420A +Display_Character:MAN3440A +Display_Character:MAN3610A +Display_Character:MAN3620A +Display_Character:MAN3630A +Display_Character:MAN3640A +Display_Character:MAN3810A +Display_Character:MAN3820A +Display_Character:MAN3840A +Display_Character:MAN71A +Display_Character:MAN72A +Display_Character:MAN73A +Display_Character:MAN74A +Display_Character:NHD-0420H1Z +Display_Character:NHD-C0220BIZ +Display_Character:NHD-C0220BIZ-FSRGB +Display_Character:RC1602A +Display_Character:RC1602A-GHW-ESX +Display_Character:SA15-11EWA +Display_Character:SA15-11GWA +Display_Character:SA15-11SRWA +Display_Character:SA39-11EWA +Display_Character:SA39-11GWA +Display_Character:SA39-11SRWA +Display_Character:SA39-11YWA +Display_Character:SA39-12EWA +Display_Character:SA39-12GWA +Display_Character:SA39-12SRWA +Display_Character:SA39-12YWA +Display_Character:SBC18-11EGWA +Display_Character:SBC18-11SURKCGKWA +Display_Character:SC39-11EWA +Display_Character:SC39-11GWA +Display_Character:SC39-11SRWA +Display_Character:SC39-11YWA +Display_Character:SC39-12EWA +Display_Character:SC39-12GWA +Display_Character:SC39-12SRWA +Display_Character:SC39-12YWA +Display_Character:SM420561N +Display_Character:WC1602A +Display_Graphic:AG12864E +Display_Graphic:EA_DOGL128X-6 +Display_Graphic:EA_DOGM128X-6 +Display_Graphic:EA_DOGS104B-A +Display_Graphic:EA_DOGXL160-7 +Display_Graphic:EA_eDIP128B-6LW +Display_Graphic:EA_eDIP128B-6LWTP +Display_Graphic:EA_eDIP128W-6LW +Display_Graphic:EA_eDIP128W-6LWTP +Display_Graphic:EA_eDIP160B-7LW +Display_Graphic:EA_eDIP160B-7LWTP +Display_Graphic:EA_eDIP160W-7LW +Display_Graphic:EA_eDIP160W-7LWTP +Display_Graphic:EA_eDIP240B-7LW +Display_Graphic:EA_eDIP240B-7LWTP +Display_Graphic:EA_eDIP240J-7LA +Display_Graphic:EA_eDIP240J-7LATP +Display_Graphic:EA_eDIP240J-7LW +Display_Graphic:EA_eDIP240J-7LWTP +Display_Graphic:EA_eDIP320B-8LW +Display_Graphic:EA_eDIP320B-8LWTP +Display_Graphic:EA_eDIP320J-8LA +Display_Graphic:EA_eDIP320J-8LATP +Display_Graphic:EA_eDIP320J-8LW +Display_Graphic:EA_eDIP320J-8LWTP +Display_Graphic:EA_eDIPTFT32-A +Display_Graphic:EA_eDIPTFT32-ATP +Display_Graphic:EA_eDIPTFT43-A +Display_Graphic:EA_eDIPTFT43-ATC +Display_Graphic:EA_eDIPTFT43-ATP +Display_Graphic:EA_eDIPTFT43-ATS +Display_Graphic:EA_eDIPTFT57-A +Display_Graphic:EA_eDIPTFT57-ATP +Display_Graphic:EA_eDIPTFT70-A +Display_Graphic:EA_eDIPTFT70-ATC +Display_Graphic:EA_eDIPTFT70-ATP +Display_Graphic:ERM19264 +Display_Graphic:NHD-C12832A1Z-FSRGB +Display_Graphic:OLED-128O064D +Driver_Display:82720 +Driver_Display:ADS7843E +Driver_Display:ADS7843E-2K5 +Driver_Display:ADS7843EG4 +Driver_Display:ADS7843IDBQRQ1 +Driver_Display:AY0438X-L +Driver_Display:AY0438X-P +Driver_Display:CR2013-MI2120 +Driver_Display:XPT2046QF +Driver_Display:XPT2046TS +Driver_FET:1EDN7550B +Driver_FET:1EDN8550B +Driver_FET:2ED1323S12P +Driver_FET:2ED1324S12P +Driver_FET:2ED21824S06J +Driver_FET:2EDL23N06PJXUMA1 +Driver_FET:ACPL-336J +Driver_FET:ACPL-P343 +Driver_FET:ACPL-W343 +Driver_FET:AN34092B +Driver_FET:BSP75N +Driver_FET:BSP76 +Driver_FET:BTS4140N +Driver_FET:EL7202CN +Driver_FET:EL7202CS +Driver_FET:EL7212CN +Driver_FET:EL7212CS +Driver_FET:EL7222CN +Driver_FET:EL7222CS +Driver_FET:FAN3111C +Driver_FET:FAN3111E +Driver_FET:FAN3268 +Driver_FET:FAN3278 +Driver_FET:FAN7371 +Driver_FET:FAN7388 +Driver_FET:FAN7842 +Driver_FET:FAN7888 +Driver_FET:FL5150MX +Driver_FET:FL5160MX +Driver_FET:HCPL-3120 +Driver_FET:HCPL-314J +Driver_FET:HIP2100_DFN +Driver_FET:HIP2100_EPSOIC +Driver_FET:HIP2100_QFN +Driver_FET:HIP2100_SOIC +Driver_FET:HIP2101_DFN +Driver_FET:HIP2101_EPSOIC +Driver_FET:HIP2101_QFN +Driver_FET:HIP2101_SOIC +Driver_FET:HIP4080A +Driver_FET:HIP4081A +Driver_FET:HIP4082xB +Driver_FET:HIP4082xP +Driver_FET:ICL7667 +Driver_FET:IR2010 +Driver_FET:IR2010S +Driver_FET:IR2011 +Driver_FET:IR2085S +Driver_FET:IR2101 +Driver_FET:IR2102 +Driver_FET:IR2103 +Driver_FET:IR2104 +Driver_FET:IR2106 +Driver_FET:IR21064 +Driver_FET:IR2108 +Driver_FET:IR21084 +Driver_FET:IR2109 +Driver_FET:IR21091 +Driver_FET:IR21094 +Driver_FET:IR2110 +Driver_FET:IR2110S +Driver_FET:IR2111 +Driver_FET:IR2112 +Driver_FET:IR2112S +Driver_FET:IR2113 +Driver_FET:IR2113S +Driver_FET:IR2114S +Driver_FET:IR2133 +Driver_FET:IR2133S +Driver_FET:IR2135 +Driver_FET:IR2135S +Driver_FET:IR2153 +Driver_FET:IR21531 +Driver_FET:IR2155 +Driver_FET:IR2181 +Driver_FET:IR21814 +Driver_FET:IR2183 +Driver_FET:IR21834 +Driver_FET:IR2184 +Driver_FET:IR21844 +Driver_FET:IR2213 +Driver_FET:IR2213S +Driver_FET:IR2214S +Driver_FET:IR2233 +Driver_FET:IR2233S +Driver_FET:IR2235 +Driver_FET:IR2235S +Driver_FET:IR2301 +Driver_FET:IR2302 +Driver_FET:IR2304 +Driver_FET:IR2308 +Driver_FET:IR25602S +Driver_FET:IR25603 +Driver_FET:IR25604S +Driver_FET:IR25607S +Driver_FET:IR7106S +Driver_FET:IR7184S +Driver_FET:IR7304S +Driver_FET:IRS2001 +Driver_FET:IRS2001M +Driver_FET:IRS2003 +Driver_FET:IRS2004 +Driver_FET:IRS2005M +Driver_FET:IRS2005S +Driver_FET:IRS2008S +Driver_FET:IRS2011 +Driver_FET:IRS2101 +Driver_FET:IRS2103 +Driver_FET:IRS2104 +Driver_FET:IRS2106 +Driver_FET:IRS21064 +Driver_FET:IRS2108 +Driver_FET:IRS21084 +Driver_FET:IRS2109 +Driver_FET:IRS21091 +Driver_FET:IRS21094 +Driver_FET:IRS2110 +Driver_FET:IRS2110S +Driver_FET:IRS2111 +Driver_FET:IRS2112 +Driver_FET:IRS2112S +Driver_FET:IRS2113 +Driver_FET:IRS2113M +Driver_FET:IRS2113S +Driver_FET:IRS21531D +Driver_FET:IRS2153D +Driver_FET:IRS2181 +Driver_FET:IRS21814 +Driver_FET:IRS21814M +Driver_FET:IRS2183 +Driver_FET:IRS21834 +Driver_FET:IRS2184 +Driver_FET:IRS21844 +Driver_FET:IRS21844M +Driver_FET:IRS2186 +Driver_FET:IRS21864 +Driver_FET:IRS21867S +Driver_FET:IRS2301S +Driver_FET:IRS2302S +Driver_FET:IRS2304 +Driver_FET:IRS2308 +Driver_FET:IRS25606S +Driver_FET:IRS2890DS +Driver_FET:ITS711L1 +Driver_FET:ITS716G +Driver_FET:ITS724G +Driver_FET:L6491 +Driver_FET:LF2190N +Driver_FET:LM2105D +Driver_FET:LM2105DSG +Driver_FET:LM5109AMA +Driver_FET:LM5109ASD +Driver_FET:LM5109BMA +Driver_FET:LM5109BSD +Driver_FET:LM5109MA +Driver_FET:LMG1020YFF +Driver_FET:LTC4440EMS8 +Driver_FET:LTC4440ES6 +Driver_FET:LTC4440IMS8 +Driver_FET:LTC4440IS6 +Driver_FET:MAX15012AxSA +Driver_FET:MAX15012BxSA +Driver_FET:MAX15012CxSA +Driver_FET:MAX15012DxSA +Driver_FET:MAX15013AxSA +Driver_FET:MAX15013BxSA +Driver_FET:MAX15013CxSA +Driver_FET:MAX15013DxSA +Driver_FET:MC33152 +Driver_FET:MC34152 +Driver_FET:MCP1415 +Driver_FET:MCP1415R +Driver_FET:MCP1416 +Driver_FET:MCP1416R +Driver_FET:MCP14A0303xMNY +Driver_FET:MCP14A0304xMNY +Driver_FET:MCP14A0305xMNY +Driver_FET:MCP14A0901xMNY +Driver_FET:MCP14A0902xMNY +Driver_FET:MCP14A1201xMNY +Driver_FET:MCP14A1202xMNY +Driver_FET:MIC4426 +Driver_FET:MIC4427 +Driver_FET:MIC4428 +Driver_FET:MIC4604YM +Driver_FET:NCD5702 +Driver_FET:NCV8402xST +Driver_FET:PE29101 +Driver_FET:PE29102 +Driver_FET:PM8834 +Driver_FET:PM8834M +Driver_FET:SM72295MA +Driver_FET:STGAP1AS +Driver_FET:STGAP2SCM +Driver_FET:STGAP2SM +Driver_FET:TC4421 +Driver_FET:TC4422 +Driver_FET:TC4426xOA +Driver_FET:TC4427xOA +Driver_FET:TC4428xOA +Driver_FET:TLP250 +Driver_FET:UCC21520ADW +Driver_FET:UCC21520DW +Driver_FET:UCC27511ADBV +Driver_FET:UCC27714D +Driver_FET:ZXGD3001E6 +Driver_FET:ZXGD3002E6 +Driver_FET:ZXGD3003E6 +Driver_FET:ZXGD3004E6 +Driver_FET:ZXGD3006E6 +Driver_FET:ZXGD3009E6 +Driver_Haptic:DRV2510-Q1 +Driver_Haptic:DRV2605LDGS +Driver_LED:AL8860MP +Driver_LED:AL8860WT +Driver_LED:AP3019AKTR +Driver_LED:AP3019AKTTR +Driver_LED:BCR430UW6 +Driver_LED:CH455G +Driver_LED:CH455H +Driver_LED:CH455K +Driver_LED:CL220K4-G +Driver_LED:CL220N5-G +Driver_LED:DIO5661CD6 +Driver_LED:DIO5661ST6 +Driver_LED:DIO5661TST6 +Driver_LED:HT1632C-52LQFP +Driver_LED:HV9921N8-G +Driver_LED:HV9922N8-G +Driver_LED:HV9923N8-G +Driver_LED:HV9925SG-G +Driver_LED:HV9930LG-G +Driver_LED:HV9931LG-G +Driver_LED:HV9961LG-G +Driver_LED:HV9961NG-G +Driver_LED:HV9967BK7-G +Driver_LED:HV9967BMG-G +Driver_LED:HV9972LG-G +Driver_LED:IS31FL3216 +Driver_LED:IS31FL3216A +Driver_LED:IS31FL3218-GR +Driver_LED:IS31FL3218-QF +Driver_LED:IS31FL3236-TQ +Driver_LED:IS31FL3236A-TQ +Driver_LED:IS31FL3731-QF +Driver_LED:IS31FL3731-SA +Driver_LED:IS31FL3733-QF +Driver_LED:IS31FL3733-TQ +Driver_LED:IS31FL3736 +Driver_LED:IS31FL3737 +Driver_LED:IS31LT3360 +Driver_LED:KTD2026 +Driver_LED:KTD2027 +Driver_LED:KTD2061xxUAC +Driver_LED:LED1642GWPTR +Driver_LED:LED1642GWQTR +Driver_LED:LED1642GWTTR +Driver_LED:LED1642GWXTTR +Driver_LED:LED5000 +Driver_LED:LM3914N +Driver_LED:LM3914V +Driver_LED:LP5036 +Driver_LED:LP8868XQDMT +Driver_LED:LT3465 +Driver_LED:LT3465A +Driver_LED:LT3755xMSE +Driver_LED:LT3755xMSE-1 +Driver_LED:LT3755xMSE-2 +Driver_LED:LT3755xUD +Driver_LED:LT3755xUD-1 +Driver_LED:LT3755xUD-2 +Driver_LED:LT3756xMSE +Driver_LED:LT3756xMSE-1 +Driver_LED:LT3756xMSE-2 +Driver_LED:LT3756xUD +Driver_LED:LT3756xUD-1 +Driver_LED:LT3756xUD-2 +Driver_LED:LT8391xFE +Driver_LED:MAX7219 +Driver_LED:MAX7221xNG +Driver_LED:MAX7221xRG +Driver_LED:MAX7221xWG +Driver_LED:MBI5252GFN +Driver_LED:MBI5252GP +Driver_LED:MC14495P +Driver_LED:MCP1643xMS +Driver_LED:MCP1662-xOT +Driver_LED:MP3362GJ +Driver_LED:MPQ2483DQ +Driver_LED:MPQ3362GJ-AEC1 +Driver_LED:NCP5623DTBR2G +Driver_LED:NCR401U +Driver_LED:PCA9531PW +Driver_LED:PCA9635 +Driver_LED:PCA9685BS +Driver_LED:PCA9685PW +Driver_LED:PCA9745BTW +Driver_LED:RCD-24 +Driver_LED:ST1CC40DR +Driver_LED:ST1CC40PUR +Driver_LED:STP08CP05B +Driver_LED:STP08CP05M +Driver_LED:STP08CP05T +Driver_LED:STP08CP05XT +Driver_LED:STP16CP05M +Driver_LED:STP16CP05P +Driver_LED:STP16CP05T +Driver_LED:STP16CP05XT +Driver_LED:STP16CPC26M +Driver_LED:STP16CPC26P +Driver_LED:STP16CPC26T +Driver_LED:STP16CPC26X +Driver_LED:TCA6507RUE +Driver_LED:TLC59108xPW +Driver_LED:TLC5916 +Driver_LED:TLC5917 +Driver_LED:TLC5940NT +Driver_LED:TLC5940PWP +Driver_LED:TLC5947DAP +Driver_LED:TLC5947RHB +Driver_LED:TLC5949PWP +Driver_LED:TLC5951DAP +Driver_LED:TLC5951RHA +Driver_LED:TLC5951RTA +Driver_LED:TLC5957RTQ +Driver_LED:TLC5971PWP +Driver_LED:TLC5971RGE +Driver_LED:TLC5973 +Driver_LED:TPS61165DBV +Driver_LED:TPS92692PWP +Driver_LED:WS2811 +Driver_LED:iC-HTG +Driver_Motor:A4950E +Driver_Motor:A4950K +Driver_Motor:A4952_LY +Driver_Motor:A4953_LJ +Driver_Motor:A4954 +Driver_Motor:AMT49413 +Driver_Motor:DRV8212P +Driver_Motor:DRV8308 +Driver_Motor:DRV8412 +Driver_Motor:DRV8432 +Driver_Motor:DRV8461SPWP +Driver_Motor:DRV8662 +Driver_Motor:DRV8711 +Driver_Motor:DRV8800PWP +Driver_Motor:DRV8800RTY +Driver_Motor:DRV8801PWP +Driver_Motor:DRV8801RTY +Driver_Motor:DRV8833PW +Driver_Motor:DRV8833PWP +Driver_Motor:DRV8833RTY +Driver_Motor:DRV8837 +Driver_Motor:DRV8837C +Driver_Motor:DRV8838 +Driver_Motor:DRV8847PWP +Driver_Motor:DRV8847PWR +Driver_Motor:DRV8847RTE +Driver_Motor:DRV8847SPWR +Driver_Motor:DRV8848 +Driver_Motor:DRV8870DDA +Driver_Motor:DRV8871DDA +Driver_Motor:DRV8872DDA +Driver_Motor:EMC2301-x-ACZL +Driver_Motor:EMC2302-x-AIZL +Driver_Motor:EMC2303-x-KP +Driver_Motor:EMC2305-x-AP +Driver_Motor:L293 +Driver_Motor:L293D +Driver_Motor:L293E +Driver_Motor:L297 +Driver_Motor:L298HN +Driver_Motor:L298N +Driver_Motor:L298P +Driver_Motor:LMD18200 +Driver_Motor:MAX22201 +Driver_Motor:MAX22202 +Driver_Motor:MAX22207 +Driver_Motor:MP6536DU +Driver_Motor:PAC5527QM +Driver_Motor:PG001M +Driver_Motor:Pololu_Breakout_A4988 +Driver_Motor:Pololu_Breakout_DRV8825 +Driver_Motor:SLA7042M +Driver_Motor:SLA7044M +Driver_Motor:SLA7070MPRT +Driver_Motor:SLA7071MPRT +Driver_Motor:SLA7072MPRT +Driver_Motor:SLA7073MPRT +Driver_Motor:SLA7075MPRT +Driver_Motor:SLA7076MPRT +Driver_Motor:SLA7077MPRT +Driver_Motor:SLA7078MPRT +Driver_Motor:SN754410NE +Driver_Motor:STK672-040-E +Driver_Motor:STK672-080-E +Driver_Motor:STSPIN220 +Driver_Motor:STSPIN230 +Driver_Motor:STSPIN233 +Driver_Motor:STSPIN240 +Driver_Motor:TB6612FNG +Driver_Motor:TC78H670FTG +Driver_Motor:TMC2041-LA +Driver_Motor:TMC2100-LA +Driver_Motor:TMC2100-TA +Driver_Motor:TMC2130-LA +Driver_Motor:TMC2130-TA +Driver_Motor:TMC2160 +Driver_Motor:TMC2202-WA +Driver_Motor:TMC2208-LA +Driver_Motor:TMC2224-LA +Driver_Motor:TMC2226-SA +Driver_Motor:TMC262 +Driver_Motor:TMC2660 +Driver_Motor:TMC5130A-TA +Driver_Motor:TMC5160A-TA +Driver_Motor:VNH2SP30 +Driver_Motor:VNH5019A-E +Driver_Motor:ZXBM5210-S +Driver_Motor:ZXBM5210-SP +Driver_Relay:DRV8860 +Driver_Relay:DRV8860_PWPR +Driver_Relay:MAX4820xUP +Driver_Relay:MAX4821xUP +Driver_Relay:TPL9201_TSSOP +Driver_TEC:MAX1968xUI +Driver_TEC:MAX1969xUI +DSP_AnalogDevices:ADAU1450 +DSP_AnalogDevices:ADAU1451 +DSP_AnalogDevices:ADAU1452 +DSP_AnalogDevices:ADAU1701 +DSP_AnalogDevices:ADAU1702 +DSP_Freescale:DSP96002 +DSP_Microchip_DSPIC33:DSPIC33EP256MU810-xPT +DSP_Microchip_DSPIC33:DSPIC33FJ128GP204 +DSP_Microchip_DSPIC33:DSPIC33FJ128GP804 +DSP_Microchip_DSPIC33:DSPIC33FJ128MC204 +DSP_Microchip_DSPIC33:DSPIC33FJ128MC510A +DSP_Microchip_DSPIC33:DSPIC33FJ128MC710A +DSP_Microchip_DSPIC33:DSPIC33FJ128MC804 +DSP_Microchip_DSPIC33:DSPIC33FJ256MC510A +DSP_Microchip_DSPIC33:DSPIC33FJ256MC710A +DSP_Microchip_DSPIC33:DSPIC33FJ32GP304 +DSP_Microchip_DSPIC33:DSPIC33FJ32MC304 +DSP_Microchip_DSPIC33:DSPIC33FJ64GP204 +DSP_Microchip_DSPIC33:DSPIC33FJ64GP306A-IMR +DSP_Microchip_DSPIC33:DSPIC33FJ64GP804 +DSP_Microchip_DSPIC33:DSPIC33FJ64MC204 +DSP_Microchip_DSPIC33:DSPIC33FJ64MC510A +DSP_Microchip_DSPIC33:DSPIC33FJ64MC710A +DSP_Microchip_DSPIC33:DSPIC33FJ64MC802-xSP +DSP_Microchip_DSPIC33:DSPIC33FJ64MC804 +DSP_Motorola:DSP56301 +DSP_Texas:TMS320LF2406PZ +Fiber_Optic:AFBR-1624Z +Fiber_Optic:AFBR-2624Z +Filter:0603USB-142 +Filter:0603USB-222 +Filter:0603USB-251 +Filter:0603USB-601 +Filter:0603USB-951 +Filter:0850BM14E0016 +Filter:0900FM15K0039 +Filter:1FP41-4R +Filter:1FP42-3R +Filter:1FP44-2R +Filter:1FP45-0R +Filter:1FP45-1R +Filter:1FP61-4R +Filter:1FP62-3R +Filter:1FP64-2R +Filter:1FP65-0R +Filter:1FP65-1R +Filter:B39162B8813P810 +Filter:BNX025 +Filter:Choke_CommonMode_FerriteCore_1234 +Filter:Choke_CommonMode_FerriteCore_1243 +Filter:Choke_CommonMode_FerriteCore_1324 +Filter:Choke_CommonMode_FerriteCore_1342 +Filter:Choke_CommonMode_FerriteCore_1423 +Filter:Choke_CommonMode_PulseElectronics_PH9455x105NL +Filter:Choke_CommonMode_PulseElectronics_PH9455x155NL +Filter:Choke_CommonMode_PulseElectronics_PH9455x156NL +Filter:Choke_CommonMode_PulseElectronics_PH9455x205NL +Filter:Choke_CommonMode_PulseElectronics_PH9455x356NL +Filter:Choke_CommonMode_PulseElectronics_PH9455x405NL +Filter:Choke_CommonMode_PulseElectronics_PH9455x705NL +Filter:Choke_CommonMode_PulseElectronics_PH9455x826NL +Filter:Choke_Schaffner_RN102-0.3-02-12M +Filter:Choke_Schaffner_RN102-0.3-02-22M +Filter:Choke_Schaffner_RN102-0.6-02-4M4 +Filter:Choke_Schaffner_RN102-1-02-3M0 +Filter:Choke_Schaffner_RN102-1.5-02-1M6 +Filter:Choke_Schaffner_RN102-2-02-1M1 +Filter:Choke_Wurth_WE-CNSW_744232090 +Filter:FN405-0.5-02 +Filter:FN405-1-02 +Filter:FN405-10-02 +Filter:FN405-3-02 +Filter:FN405-6-02 +Filter:FN406-0.5-02 +Filter:FN406-1-02 +Filter:FN406-3-02 +Filter:FN406-6-02 +Filter:FN406-8.4-02 +Filter:FN406B-0.5-02 +Filter:FN406B-1-02 +Filter:FN406B-3-02 +Filter:FN406B-6-02 +Filter:FN406B-8.4-02 +Filter:LTC1562xG-2 +Filter:LTC1562xxG +Filter:P300PL104M275xC222 +Filter:P300PL104M275xC332 +Filter:P300PL104M275xC472 +Filter:P300PL154M275xC222 +Filter:P300PL154M275xC332 +Filter:P300PL154M275xC472 +Filter:SAFFA1G58KA0F0A +Filter:SAFFA1G96FN0F0A +Filter:SAFFA2G14FA0F0A +Filter:SAFFA881MFL0F0A +Filter:SAFFA942MFM0F0A +Filter:SAFFB1G58KA0F0A +Filter:SAFFB1G96FN0F0A +Filter:SAFFB2G14FA0F0A +Filter:SAFFB881MFL0F0A +Filter:SAFFB942MFM0F0A +Filter:SF14-1575F5UUA1 +Filter:SF14-1575F5UUC1 +FPGA_CologneChip_GateMate:CCGM1A1 +FPGA_Efinix_Trion:T8Q144xx +FPGA_Lattice:ICE40HX1K-TQ144 +FPGA_Lattice:ICE40HX4K-BG121 +FPGA_Lattice:ICE40HX4K-TQ144 +FPGA_Lattice:ICE40HX8K-BG121 +FPGA_Lattice:ICE40UL1K-SWG16 +FPGA_Lattice:ICE40UP5K-SG48ITR +FPGA_Lattice:ICE5LP1K-SG48 +FPGA_Lattice:LFE5U-85F-6BG381x +FPGA_Lattice:LFE5U-85F-6BG756x +FPGA_Lattice:LFE5U-85F-7BG381x +FPGA_Lattice:LFE5U-85F-7BG756x +FPGA_Lattice:LFE5U-85F-8BG381x +FPGA_Lattice:LFE5U-85F-8BG756x +FPGA_Lattice:LFE5UM-85F-6BG381x +FPGA_Lattice:LFE5UM-85F-6BG756x +FPGA_Lattice:LFE5UM-85F-7BG381x +FPGA_Lattice:LFE5UM-85F-7BG756x +FPGA_Lattice:LFE5UM-85F-8BG381x +FPGA_Lattice:LFE5UM-85F-8BG756x +FPGA_Lattice:LFE5UM5G-85F-8BG381x +FPGA_Lattice:LFE5UM5G-85F-8BG756x +FPGA_Lattice:LFXP2-5E-5TN144 +FPGA_Lattice:LFXP2-5E-6TN144 +FPGA_Lattice:LFXP2-5E-7TN144 +FPGA_Microsemi:A3P030-VQG100 +FPGA_Microsemi:A3P060-VQG100 +FPGA_Microsemi:A3P1000-PQG208 +FPGA_Microsemi:A3P125-PQG208 +FPGA_Microsemi:A3P125-VQG100 +FPGA_Microsemi:A3P250-PQG208 +FPGA_Microsemi:A3P250-VQG100 +FPGA_Microsemi:A3P400-PQG208 +FPGA_Microsemi:A3P600-PQG208 +FPGA_Microsemi:ACT1020PL44 +FPGA_Microsemi:ACT1020PL68 +FPGA_Microsemi:ACT1225PL84 +FPGA_Microsemi:EX128-TQ100 +FPGA_Microsemi:EX128-TQ64 +FPGA_Microsemi:EX256-TQ100 +FPGA_Microsemi:EX64-TQ100 +FPGA_Microsemi:EX64-TQ64 +FPGA_Microsemi:M2GL090T-FG484 +FPGA_Xilinx:XC2018-PC68 +FPGA_Xilinx:XC2018-PC84 +FPGA_Xilinx:XC2064-PC68 +FPGA_Xilinx:XC2C256-TQ144 +FPGA_Xilinx:XC2C256-VQ100 +FPGA_Xilinx:XC2S100TQ144 +FPGA_Xilinx:XC2S150PQ208 +FPGA_Xilinx:XC2S200PQ208 +FPGA_Xilinx:XC2S300PQ208 +FPGA_Xilinx:XC2S400FT256 +FPGA_Xilinx:XC2S50-PQ208 +FPGA_Xilinx:XC2S64A-xQFG48 +FPGA_Xilinx:XC3020-PC68 +FPGA_Xilinx:XC3030-PC44 +FPGA_Xilinx:XC3030-PC68 +FPGA_Xilinx:XC3030-PC84 +FPGA_Xilinx:XC3030-VQ100 +FPGA_Xilinx:XC3042-PC84 +FPGA_Xilinx:XC3042-VQ100 +FPGA_Xilinx:XC3S1400A-FG484 +FPGA_Xilinx:XC3S200AN-FT256 +FPGA_Xilinx:XC3S400-FG320 +FPGA_Xilinx:XC3S400-PQ208 +FPGA_Xilinx:XC3S50-VQ100 +FPGA_Xilinx:XC3S50AN-TQG144 +FPGA_Xilinx:XC4003-PC84 +FPGA_Xilinx:XC4003-VQ100 +FPGA_Xilinx:XC4004-PQ160 +FPGA_Xilinx:XC4005-PC84 +FPGA_Xilinx:XC4005-PG156 +FPGA_Xilinx:XC4005-PQ100 +FPGA_Xilinx:XC4005-PQ160 +FPGA_Xilinx:XC6SLX25T-BG484 +FPGA_Xilinx:XCV150_BG352 +FPGA_Xilinx_Artix7:XC7A100T-CSG324 +FPGA_Xilinx_Artix7:XC7A100T-FGG484 +FPGA_Xilinx_Artix7:XC7A100T-FGG676 +FPGA_Xilinx_Artix7:XC7A100T-FTG256 +FPGA_Xilinx_Artix7:XC7A15T-CPG236 +FPGA_Xilinx_Artix7:XC7A15T-CSG324 +FPGA_Xilinx_Artix7:XC7A15T-CSG325 +FPGA_Xilinx_Artix7:XC7A15T-FGG484 +FPGA_Xilinx_Artix7:XC7A15T-FTG256 +FPGA_Xilinx_Artix7:XC7A200T-FBG484 +FPGA_Xilinx_Artix7:XC7A200T-FBG676 +FPGA_Xilinx_Artix7:XC7A200T-FFG1156 +FPGA_Xilinx_Artix7:XC7A200T-SBG484 +FPGA_Xilinx_Artix7:XC7A35T-CPG236 +FPGA_Xilinx_Artix7:XC7A35T-CSG324 +FPGA_Xilinx_Artix7:XC7A35T-CSG325 +FPGA_Xilinx_Artix7:XC7A35T-FGG484 +FPGA_Xilinx_Artix7:XC7A35T-FTG256 +FPGA_Xilinx_Artix7:XC7A50T-CPG236 +FPGA_Xilinx_Artix7:XC7A50T-CSG324 +FPGA_Xilinx_Artix7:XC7A50T-CSG325 +FPGA_Xilinx_Artix7:XC7A50T-FGG484 +FPGA_Xilinx_Artix7:XC7A50T-FTG256 +FPGA_Xilinx_Artix7:XC7A75T-CSG324 +FPGA_Xilinx_Artix7:XC7A75T-FGG484 +FPGA_Xilinx_Artix7:XC7A75T-FGG676 +FPGA_Xilinx_Artix7:XC7A75T-FTG256 +FPGA_Xilinx_Kintex7:XC7K160T-FBG484 +FPGA_Xilinx_Kintex7:XC7K160T-FBG676 +FPGA_Xilinx_Kintex7:XC7K160T-FFG676 +FPGA_Xilinx_Kintex7:XC7K325T-FBG676 +FPGA_Xilinx_Kintex7:XC7K325T-FBG900 +FPGA_Xilinx_Kintex7:XC7K325T-FFG676 +FPGA_Xilinx_Kintex7:XC7K325T-FFG900 +FPGA_Xilinx_Kintex7:XC7K355T-FFG901 +FPGA_Xilinx_Kintex7:XC7K410T-FBG676 +FPGA_Xilinx_Kintex7:XC7K410T-FBG900 +FPGA_Xilinx_Kintex7:XC7K410T-FFG676 +FPGA_Xilinx_Kintex7:XC7K410T-FFG900 +FPGA_Xilinx_Kintex7:XC7K420T-FFG1156 +FPGA_Xilinx_Kintex7:XC7K420T-FFG901 +FPGA_Xilinx_Kintex7:XC7K480T-FFG1156 +FPGA_Xilinx_Kintex7:XC7K480T-FFG901 +FPGA_Xilinx_Kintex7:XC7K70T-FBG484 +FPGA_Xilinx_Kintex7:XC7K70T-FBG676 +FPGA_Xilinx_Spartan6:XC6SLX100-CSG484 +FPGA_Xilinx_Spartan6:XC6SLX100-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX100-FGG676 +FPGA_Xilinx_Spartan6:XC6SLX100T-CSG484 +FPGA_Xilinx_Spartan6:XC6SLX100T-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX100T-FGG676 +FPGA_Xilinx_Spartan6:XC6SLX100T-FGG900 +FPGA_Xilinx_Spartan6:XC6SLX150-CSG484 +FPGA_Xilinx_Spartan6:XC6SLX150-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX150-FGG676 +FPGA_Xilinx_Spartan6:XC6SLX150-FGG900 +FPGA_Xilinx_Spartan6:XC6SLX150T-CSG484 +FPGA_Xilinx_Spartan6:XC6SLX150T-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX150T-FGG676 +FPGA_Xilinx_Spartan6:XC6SLX150T-FGG900 +FPGA_Xilinx_Spartan6:XC6SLX16-CPG196 +FPGA_Xilinx_Spartan6:XC6SLX16-CSG225 +FPGA_Xilinx_Spartan6:XC6SLX16-CSG324 +FPGA_Xilinx_Spartan6:XC6SLX16-FTG256 +FPGA_Xilinx_Spartan6:XC6SLX25-CSG324 +FPGA_Xilinx_Spartan6:XC6SLX25-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX25-FTG256 +FPGA_Xilinx_Spartan6:XC6SLX25T-CSG324 +FPGA_Xilinx_Spartan6:XC6SLX25T-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX4-CPG196 +FPGA_Xilinx_Spartan6:XC6SLX4-CSG225 +FPGA_Xilinx_Spartan6:XC6SLX4-TQG144 +FPGA_Xilinx_Spartan6:XC6SLX45-CSG324 +FPGA_Xilinx_Spartan6:XC6SLX45-CSG484 +FPGA_Xilinx_Spartan6:XC6SLX45-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX45-FGG676 +FPGA_Xilinx_Spartan6:XC6SLX45T-CSG324 +FPGA_Xilinx_Spartan6:XC6SLX45T-CSG484 +FPGA_Xilinx_Spartan6:XC6SLX45T-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX75-CSG484 +FPGA_Xilinx_Spartan6:XC6SLX75-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX75-FGG676 +FPGA_Xilinx_Spartan6:XC6SLX75T-CSG484 +FPGA_Xilinx_Spartan6:XC6SLX75T-FGG484 +FPGA_Xilinx_Spartan6:XC6SLX75T-FGG676 +FPGA_Xilinx_Spartan6:XC6SLX9-CPG196 +FPGA_Xilinx_Spartan6:XC6SLX9-CSG225 +FPGA_Xilinx_Spartan6:XC6SLX9-CSG324 +FPGA_Xilinx_Spartan6:XC6SLX9-FTG256 +FPGA_Xilinx_Spartan6:XC6SLX9-TQG144 +FPGA_Xilinx_Virtex5:XC5VFX100T-FF1136 +FPGA_Xilinx_Virtex5:XC5VFX100T-FF1738 +FPGA_Xilinx_Virtex5:XC5VFX130T-FF1738 +FPGA_Xilinx_Virtex5:XC5VFX200T-FF1738 +FPGA_Xilinx_Virtex5:XC5VFX30T-FF665 +FPGA_Xilinx_Virtex5:XC5VFX70T-FF1136 +FPGA_Xilinx_Virtex5:XC5VFX70T-FF665 +FPGA_Xilinx_Virtex5:XC5VLX110-FF1153 +FPGA_Xilinx_Virtex5:XC5VLX110-FF1760 +FPGA_Xilinx_Virtex5:XC5VLX110-FF676 +FPGA_Xilinx_Virtex5:XC5VLX110T-FF1136 +FPGA_Xilinx_Virtex5:XC5VLX110T-FF1738 +FPGA_Xilinx_Virtex5:XC5VLX155-FF1153 +FPGA_Xilinx_Virtex5:XC5VLX155-FF1760 +FPGA_Xilinx_Virtex5:XC5VLX155T-FF1136 +FPGA_Xilinx_Virtex5:XC5VLX155T-FF1738 +FPGA_Xilinx_Virtex5:XC5VLX20T-FF323 +FPGA_Xilinx_Virtex5:XC5VLX220-FF1760 +FPGA_Xilinx_Virtex5:XC5VLX220T-FF1738 +FPGA_Xilinx_Virtex5:XC5VLX30-FF324 +FPGA_Xilinx_Virtex5:XC5VLX30-FF676 +FPGA_Xilinx_Virtex5:XC5VLX30T-FF323 +FPGA_Xilinx_Virtex5:XC5VLX30T-FF665 +FPGA_Xilinx_Virtex5:XC5VLX330-FF1760 +FPGA_Xilinx_Virtex5:XC5VLX330T-FF1738 +FPGA_Xilinx_Virtex5:XC5VLX50-FF1153 +FPGA_Xilinx_Virtex5:XC5VLX50-FF324 +FPGA_Xilinx_Virtex5:XC5VLX50-FF676 +FPGA_Xilinx_Virtex5:XC5VLX50T-FF1136 +FPGA_Xilinx_Virtex5:XC5VLX50T-FF665 +FPGA_Xilinx_Virtex5:XC5VLX85-FF1153 +FPGA_Xilinx_Virtex5:XC5VLX85-FF676 +FPGA_Xilinx_Virtex5:XC5VLX85T-FF1136 +FPGA_Xilinx_Virtex5:XC5VSX240T-FF1738 +FPGA_Xilinx_Virtex5:XC5VSX35T-FF665 +FPGA_Xilinx_Virtex5:XC5VSX50T-FF1136 +FPGA_Xilinx_Virtex5:XC5VSX50T-FF665 +FPGA_Xilinx_Virtex5:XC5VSX95T-FF1136 +FPGA_Xilinx_Virtex5:XC5VTX150T-FF1156 +FPGA_Xilinx_Virtex5:XC5VTX150T-FF1759 +FPGA_Xilinx_Virtex5:XC5VTX240T-FF1759 +FPGA_Xilinx_Virtex6:XC6VHX250T-FF1154 +FPGA_Xilinx_Virtex6:XC6VHX255T-FF1155 +FPGA_Xilinx_Virtex6:XC6VHX255T-FF1923 +FPGA_Xilinx_Virtex6:XC6VHX380T-FF1154 +FPGA_Xilinx_Virtex6:XC6VHX380T-FF1155 +FPGA_Xilinx_Virtex6:XC6VHX380T-FF1923 +FPGA_Xilinx_Virtex6:XC6VHX380T-FF1924 +FPGA_Xilinx_Virtex6:XC6VHX565T-FF1923 +FPGA_Xilinx_Virtex6:XC6VHX565T-FF1924 +FPGA_Xilinx_Virtex6:XC6VLX130T-FF1156 +FPGA_Xilinx_Virtex6:XC6VLX130T-FF484 +FPGA_Xilinx_Virtex6:XC6VLX130T-FF784 +FPGA_Xilinx_Virtex6:XC6VLX195T-FF1156 +FPGA_Xilinx_Virtex6:XC6VLX195T-FF784 +FPGA_Xilinx_Virtex6:XC6VLX240T-FF1156 +FPGA_Xilinx_Virtex6:XC6VLX240T-FF1759 +FPGA_Xilinx_Virtex6:XC6VLX240T-FF784 +FPGA_Xilinx_Virtex6:XC6VLX365T-FF1156 +FPGA_Xilinx_Virtex6:XC6VLX365T-FF1759 +FPGA_Xilinx_Virtex6:XC6VLX550T-FF1759 +FPGA_Xilinx_Virtex6:XC6VLX550T-FF1760 +FPGA_Xilinx_Virtex6:XC6VLX75T-FF484 +FPGA_Xilinx_Virtex6:XC6VLX75T-FF784 +FPGA_Xilinx_Virtex6:XC6VLX760-FF1760 +FPGA_Xilinx_Virtex6:XC6VSX315T-FF1156 +FPGA_Xilinx_Virtex6:XC6VSX315T-FF1759 +FPGA_Xilinx_Virtex6:XC6VSX475T-FF1156 +FPGA_Xilinx_Virtex6:XC6VSX475T-FF1759 +FPGA_Xilinx_Virtex7:XC7V2000T-FHG1761 +FPGA_Xilinx_Virtex7:XC7V2000T-FLG1925 +FPGA_Xilinx_Virtex7:XC7V585T-FFG1157 +FPGA_Xilinx_Virtex7:XC7V585T-FFG1761 +FPGA_Xilinx_Virtex7:XC7VH580T-FLG1155 +FPGA_Xilinx_Virtex7:XC7VH580T-FLG1931 +FPGA_Xilinx_Virtex7:XC7VH580T-HCG1155 +FPGA_Xilinx_Virtex7:XC7VH580T-HCG1931 +FPGA_Xilinx_Virtex7:XC7VH870T-FLG1932 +FPGA_Xilinx_Virtex7:XC7VH870T-HCG1932 +FPGA_Xilinx_Virtex7:XC7VX1140T-FLG1926 +FPGA_Xilinx_Virtex7:XC7VX1140T-FLG1928 +FPGA_Xilinx_Virtex7:XC7VX1140T-FLG1930 +FPGA_Xilinx_Virtex7:XC7VX330T-FFG1157 +FPGA_Xilinx_Virtex7:XC7VX330T-FFG1761 +FPGA_Xilinx_Virtex7:XC7VX415T-FFG1157 +FPGA_Xilinx_Virtex7:XC7VX415T-FFG1158 +FPGA_Xilinx_Virtex7:XC7VX415T-FFG1927 +FPGA_Xilinx_Virtex7:XC7VX485T-FFG1157 +FPGA_Xilinx_Virtex7:XC7VX485T-FFG1158 +FPGA_Xilinx_Virtex7:XC7VX485T-FFG1761 +FPGA_Xilinx_Virtex7:XC7VX485T-FFG1927 +FPGA_Xilinx_Virtex7:XC7VX485T-FFG1930 +FPGA_Xilinx_Virtex7:XC7VX550T-FFG1158 +FPGA_Xilinx_Virtex7:XC7VX550T-FFG1927 +FPGA_Xilinx_Virtex7:XC7VX690T-FFG1157 +FPGA_Xilinx_Virtex7:XC7VX690T-FFG1158 +FPGA_Xilinx_Virtex7:XC7VX690T-FFG1761 +FPGA_Xilinx_Virtex7:XC7VX690T-FFG1926 +FPGA_Xilinx_Virtex7:XC7VX690T-FFG1927 +FPGA_Xilinx_Virtex7:XC7VX690T-FFG1930 +FPGA_Xilinx_Virtex7:XC7VX980T-FFG1926 +FPGA_Xilinx_Virtex7:XC7VX980T-FFG1928 +FPGA_Xilinx_Virtex7:XC7VX980T-FFG1930 +GPU:MC6845 +GPU:MC68A45 +GPU:MC68B45 +Graphic:Logo_Open_Hardware_Large +Graphic:Logo_Open_Hardware_Small +Graphic:SYM_Arrow45_Large +Graphic:SYM_Arrow45_Normal +Graphic:SYM_Arrow45_Small +Graphic:SYM_Arrow45_Tiny +Graphic:SYM_Arrow45_XLarge +Graphic:SYM_Arrow_Large +Graphic:SYM_Arrow_Normal +Graphic:SYM_Arrow_Small +Graphic:SYM_Arrow_Tiny +Graphic:SYM_Arrow_XLarge +Graphic:SYM_ESD_Large +Graphic:SYM_ESD_Small +Graphic:SYM_Earth_Protective_Large +Graphic:SYM_Earth_Protective_Small +Graphic:SYM_EasterEgg_42x60mm +Graphic:SYM_Flash_Large +Graphic:SYM_Flash_Small +Graphic:SYM_Flash_XLarge +Graphic:SYM_Hot_Large +Graphic:SYM_Hot_Small +Graphic:SYM_LASER_Large +Graphic:SYM_LASER_Small +Graphic:SYM_Magnet_Large +Graphic:SYM_Magnet_Small +Graphic:SYM_Radio_Waves_Large +Graphic:SYM_Radio_Waves_Small +Graphic:SYM_Radioactive_Large +Graphic:SYM_Radioactive_Radiation_Small +Interface:5PB1108PGxx +Interface:6821 +Interface:6822 +Interface:68230 +Interface:68681 +Interface:68901_PLCC +Interface:8237 +Interface:8255 +Interface:8255A +Interface:8259 +Interface:8259A +Interface:8259A-2 +Interface:8288 +Interface:82C55A +Interface:82C55A_PLCC +Interface:88SE9125C0-NAA +Interface:AD9833xRM +Interface:AD9834 +Interface:AD9850 +Interface:AD9851 +Interface:AD9910 +Interface:AD9912 +Interface:AD9951 +Interface:AD9954 +Interface:AM26LS31CD +Interface:AM26LS31CDB +Interface:AM26LS31CN +Interface:AM26LS31MJ +Interface:AM26LS31xNS +Interface:AM26LV32xD +Interface:AM26LV32xNS +Interface:CDCLVP1102RGT +Interface:CH376T +Interface:DS90C124 +Interface:DS90C241 +Interface:DS90C402 +Interface:DS90LV011A +Interface:DS90LV027A +Interface:FD1771 +Interface:FIN1019M +Interface:FIN1019MTC +Interface:HT12D +Interface:HT12E +Interface:LTC1518 +Interface:LTC1519 +Interface:LTC1688 +Interface:LTC1689 +Interface:LTC6957xDD-1 +Interface:LTC6957xDD-2 +Interface:LTC6957xDD-3 +Interface:LTC6957xDD-4 +Interface:LTC6957xMS-1 +Interface:LTC6957xMS-2 +Interface:LTC6957xMS-3 +Interface:LTC6957xMS-4 +Interface:MAX6816 +Interface:MC100EPT22D +Interface:MC100EPT22DT +Interface:MC100LVELT22D +Interface:MC100LVELT22DT +Interface:MC6840 +Interface:MC6843 +Interface:MC6844 +Interface:MC68A21 +Interface:MC68A40 +Interface:MC68A44 +Interface:MC68B21 +Interface:MC68B40 +Interface:MC68B44 +Interface:NB3N551MN +Interface:ONET1191PRGT +Interface:PCA9306 +Interface:PCA9306D +Interface:PCA9306DC +Interface:PCA9306DC1 +Interface:PCA9306DP +Interface:PCA9600D +Interface:PCA9600DP +Interface:PCA9615DP +Interface:PCI9030-PQFP176 +Interface:S5933_PQ160 +Interface:SI9986 +Interface:SLB9660xT +Interface:SLB9665xT +Interface:SN65LVDS047D +Interface:SN65LVDS047PW +Interface:SN65LVDS1D +Interface:SN65LVDS1DBV +Interface:SN65LVDS2D +Interface:SN65LVDS2DBV +Interface:SN65LVDT2D +Interface:SN65LVDT2DBV +Interface:SN74LV8153N +Interface:SN74LV8153PW +Interface:SN75160BDW +Interface:SN75160BN +Interface:TB5D1MD +Interface:TB5D1MDW +Interface:TB5D2H +Interface:TB5D2HDW +Interface:TB5R1D +Interface:TB5R1DW +Interface:TB5R2D +Interface:TB5R2DW +Interface:TCA9406DC +Interface:TCA9800 +Interface:TCA9801 +Interface:TCA9802 +Interface:TCA9803 +Interface:U2270B +Interface:WD2791 +Interface:WD2793 +Interface:WD2795 +Interface:WD2797 +Interface:Z8420 +Interface:Z84C20 +Interface_CAN_LIN:ADM3053 +Interface_CAN_LIN:ADM3057ExRW +Interface_CAN_LIN:CA-IF1042LVS +Interface_CAN_LIN:ISO1044BD +Interface_CAN_LIN:ISO1050DUB +Interface_CAN_LIN:ISOW1044 +Interface_CAN_LIN:LTC2875-DD +Interface_CAN_LIN:LTC2875-S8 +Interface_CAN_LIN:MCP2021A-xxxxMD +Interface_CAN_LIN:MCP2021A-xxxxP +Interface_CAN_LIN:MCP2021A-xxxxSN +Interface_CAN_LIN:MCP2022A-xxxxP +Interface_CAN_LIN:MCP2022A-xxxxSL +Interface_CAN_LIN:MCP2022A-xxxxST +Interface_CAN_LIN:MCP2050-330-EMQ +Interface_CAN_LIN:MCP2050-330-EP +Interface_CAN_LIN:MCP2050-330-ESL +Interface_CAN_LIN:MCP2050-500-EMQ +Interface_CAN_LIN:MCP2050-500-EP +Interface_CAN_LIN:MCP2050-500-ESL +Interface_CAN_LIN:MCP2515-xSO +Interface_CAN_LIN:MCP2515-xST +Interface_CAN_LIN:MCP2517FD-xJHA +Interface_CAN_LIN:MCP2517FD-xSL +Interface_CAN_LIN:MCP251863T-E-9PX +Interface_CAN_LIN:MCP251863T-H-SS +Interface_CAN_LIN:MCP2518FD-xQBB +Interface_CAN_LIN:MCP2542FDxMF +Interface_CAN_LIN:MCP2542WFDxMF +Interface_CAN_LIN:MCP2551-I-P +Interface_CAN_LIN:MCP2551-I-SN +Interface_CAN_LIN:MCP2557FD-xMF +Interface_CAN_LIN:MCP2557FD-xMNY +Interface_CAN_LIN:MCP2557FD-xSN +Interface_CAN_LIN:MCP2558FD-xMF +Interface_CAN_LIN:MCP2558FD-xMNY +Interface_CAN_LIN:MCP2558FD-xSN +Interface_CAN_LIN:MCP2561-E-MF +Interface_CAN_LIN:MCP2561-E-P +Interface_CAN_LIN:MCP2561-E-SN +Interface_CAN_LIN:MCP2561-H-MF +Interface_CAN_LIN:MCP2561-H-P +Interface_CAN_LIN:MCP2561-H-SN +Interface_CAN_LIN:MCP2562-E-MF +Interface_CAN_LIN:MCP2562-E-P +Interface_CAN_LIN:MCP2562-E-SN +Interface_CAN_LIN:MCP2562-H-MF +Interface_CAN_LIN:MCP2562-H-P +Interface_CAN_LIN:MCP2562-H-SN +Interface_CAN_LIN:MCP25625-x-SS +Interface_CAN_LIN:PCA82C251 +Interface_CAN_LIN:SN65HVD1050D +Interface_CAN_LIN:SN65HVD230 +Interface_CAN_LIN:SN65HVD231 +Interface_CAN_LIN:SN65HVD232 +Interface_CAN_LIN:SN65HVD233 +Interface_CAN_LIN:SN65HVD234 +Interface_CAN_LIN:SN65HVD235 +Interface_CAN_LIN:SN65HVD255D +Interface_CAN_LIN:SN65HVD256D +Interface_CAN_LIN:SN65HVD257D +Interface_CAN_LIN:TCAN1043xDxQ1 +Interface_CAN_LIN:TCAN330 +Interface_CAN_LIN:TCAN330G +Interface_CAN_LIN:TCAN332 +Interface_CAN_LIN:TCAN332G +Interface_CAN_LIN:TCAN334 +Interface_CAN_LIN:TCAN334G +Interface_CAN_LIN:TCAN337 +Interface_CAN_LIN:TCAN337G +Interface_CAN_LIN:TCAN4550RGY +Interface_CAN_LIN:TCAN4551RGYRQ1 +Interface_CAN_LIN:TJA1021T +Interface_CAN_LIN:TJA1021TK +Interface_CAN_LIN:TJA1029T +Interface_CAN_LIN:TJA1029TK +Interface_CAN_LIN:TJA1042T +Interface_CAN_LIN:TJA1042T-3 +Interface_CAN_LIN:TJA1042TK-3 +Interface_CAN_LIN:TJA1043T +Interface_CAN_LIN:TJA1043TK +Interface_CAN_LIN:TJA1049T +Interface_CAN_LIN:TJA1049T-3 +Interface_CAN_LIN:TJA1049TK +Interface_CAN_LIN:TJA1049TK-3 +Interface_CAN_LIN:TJA1051T +Interface_CAN_LIN:TJA1051T-3 +Interface_CAN_LIN:TJA1051T-E +Interface_CAN_LIN:TJA1051TK-3 +Interface_CAN_LIN:TJA1052i-1 +Interface_CAN_LIN:TJA1052i-2 +Interface_CAN_LIN:TJA1052i-5 +Interface_CAN_LIN:TJA1145T +Interface_CAN_LIN:TJA1145T-FD +Interface_CAN_LIN:TJA1145TK +Interface_CAN_LIN:TJA1145TK-FD +Interface_CurrentLoop:XTR111AxDGQ +Interface_CurrentLoop:XTR115U +Interface_CurrentLoop:XTR116U +Interface_Ethernet:DP83848C +Interface_Ethernet:DP83848I +Interface_Ethernet:ENC28J60x-ML +Interface_Ethernet:ENC28J60x-SO +Interface_Ethernet:ENC28J60x-SP +Interface_Ethernet:ENC28J60x-SS +Interface_Ethernet:ENC424J600-ML +Interface_Ethernet:ENC424J600-PT +Interface_Ethernet:KSZ8081MLX +Interface_Ethernet:KSZ8081RNA +Interface_Ethernet:KSZ8081RND +Interface_Ethernet:KSZ9031RNXCA +Interface_Ethernet:KSZ9563RNX +Interface_Ethernet:KSZ9893RNX +Interface_Ethernet:LAN7500-ABJZ +Interface_Ethernet:LAN8710A +Interface_Ethernet:LAN8720A +Interface_Ethernet:LAN8742A +Interface_Ethernet:LAN9303 +Interface_Ethernet:LAN9303i +Interface_Ethernet:LAN9512 +Interface_Ethernet:LAN9512i +Interface_Ethernet:LAN9513 +Interface_Ethernet:LAN9513i +Interface_Ethernet:LAN9514 +Interface_Ethernet:LAN9514i +Interface_Ethernet:RTL8211EG-VB-CG +Interface_Ethernet:VSC8541XMV-0x +Interface_Ethernet:W5100 +Interface_Ethernet:W5100S-L +Interface_Ethernet:W5100S-Q +Interface_Ethernet:W5500 +Interface_Ethernet:W6100-L +Interface_Ethernet:W6100-Q +Interface_Ethernet:WGI210AT +Interface_Expansion:AS1115-BQFT +Interface_Expansion:AS1115-BSST +Interface_Expansion:AW9523B +Interface_Expansion:LTC4314xGN +Interface_Expansion:LTC4314xUDC +Interface_Expansion:LTC4316xDD +Interface_Expansion:LTC4317 +Interface_Expansion:MAX31910xUI +Interface_Expansion:MAX31911xUI +Interface_Expansion:MAX31912xUI +Interface_Expansion:MAX31913xUI +Interface_Expansion:MAX7325AEG+ +Interface_Expansion:MCP23008-xML +Interface_Expansion:MCP23008-xP +Interface_Expansion:MCP23008-xSO +Interface_Expansion:MCP23008-xSS +Interface_Expansion:MCP23017_ML +Interface_Expansion:MCP23017_SO +Interface_Expansion:MCP23017_SP +Interface_Expansion:MCP23017_SS +Interface_Expansion:MCP23S17_ML +Interface_Expansion:MCP23S17_SO +Interface_Expansion:MCP23S17_SP +Interface_Expansion:MCP23S17_SS +Interface_Expansion:P82B96 +Interface_Expansion:PCA9506BS +Interface_Expansion:PCA9516 +Interface_Expansion:PCA9536D +Interface_Expansion:PCA9536DP +Interface_Expansion:PCA9537 +Interface_Expansion:PCA9544AD +Interface_Expansion:PCA9544APW +Interface_Expansion:PCA9547BS +Interface_Expansion:PCA9547D +Interface_Expansion:PCA9547PW +Interface_Expansion:PCA9548ADB +Interface_Expansion:PCA9548ADW +Interface_Expansion:PCA9548APW +Interface_Expansion:PCA9548ARGE +Interface_Expansion:PCA9555D +Interface_Expansion:PCA9555DB +Interface_Expansion:PCA9555PW +Interface_Expansion:PCA9557BS +Interface_Expansion:PCA9557D +Interface_Expansion:PCA9557PW +Interface_Expansion:PCA9847PW +Interface_Expansion:PCAL6416AHF +Interface_Expansion:PCAL6416APW +Interface_Expansion:PCAL6534EV +Interface_Expansion:PCF8574AP +Interface_Expansion:PCF8574AT +Interface_Expansion:PCF8574ATS +Interface_Expansion:PCF8574P +Interface_Expansion:PCF8574T +Interface_Expansion:PCF8574TS +Interface_Expansion:PCF8575DBR +Interface_Expansion:PCF8584 +Interface_Expansion:PCF8591 +Interface_Expansion:STMPE1600 +Interface_Expansion:TCA9534 +Interface_Expansion:TCA9535DBR +Interface_Expansion:TCA9535DBT +Interface_Expansion:TCA9535MRGER +Interface_Expansion:TCA9535PWR +Interface_Expansion:TCA9535RGER +Interface_Expansion:TCA9535RTWR +Interface_Expansion:TCA9544A +Interface_Expansion:TCA9548AMRGER +Interface_Expansion:TCA9548APWR +Interface_Expansion:TCA9548ARGER +Interface_Expansion:TCA9554DB +Interface_Expansion:TCA9554DBQ +Interface_Expansion:TCA9554DW +Interface_Expansion:TCA9554PW +Interface_Expansion:TCA9555DBR +Interface_Expansion:TCA9555DBT +Interface_Expansion:TCA9555PWR +Interface_Expansion:TCA9555RGER +Interface_Expansion:TCA9555RTWR +Interface_Expansion:TPIC6595 +Interface_Expansion:XRA1201IG24 +Interface_Expansion:XRA1201IL24 +Interface_Expansion:XRA1201PIG24 +Interface_Expansion:XRA1201PIL24 +Interface_HDMI:ADV7611 +Interface_HDMI:TPD12S520DBT +Interface_HID:JoyWarrior24A10L +Interface_HID:JoyWarrior24A8L +Interface_HID:SpinWarrior24A3 +Interface_HID:SpinWarrior24R4 +Interface_HID:SpinWarrior24R6 +Interface_LineDriver:DS7820 +Interface_LineDriver:DS7830 +Interface_LineDriver:DS8830 +Interface_LineDriver:DS89C21 +Interface_LineDriver:EL7242C +Interface_LineDriver:MC3486N +Interface_LineDriver:MC3487DX +Interface_LineDriver:MC3487N +Interface_LineDriver:UA9637 +Interface_LineDriver:UA9638CD +Interface_LineDriver:UA9638CDE4 +Interface_LineDriver:UA9638CDG4 +Interface_LineDriver:UA9638CDR +Interface_LineDriver:UA9638CDRG4 +Interface_LineDriver:UA9638CP +Interface_LineDriver:UA9638CPE4 +Interface_Optical:IRM-H6xxT +Interface_Optical:IS471F +Interface_Optical:IS485 +Interface_Optical:IS486 +Interface_Optical:QSE159 +Interface_Optical:SFP +Interface_Optical:SFP+ +Interface_Optical:TSDP341xx +Interface_Optical:TSDP343xx +Interface_Optical:TSMP58000 +Interface_Optical:TSMP58138 +Interface_Optical:TSOP17xx +Interface_Optical:TSOP21xx +Interface_Optical:TSOP23xx +Interface_Optical:TSOP25xx +Interface_Optical:TSOP312xx +Interface_Optical:TSOP314xx +Interface_Optical:TSOP321xx +Interface_Optical:TSOP323xx +Interface_Optical:TSOP325xx +Interface_Optical:TSOP32S40F +Interface_Optical:TSOP331xx +Interface_Optical:TSOP333xx +Interface_Optical:TSOP335xx +Interface_Optical:TSOP341xx +Interface_Optical:TSOP343xx +Interface_Optical:TSOP345xx +Interface_Optical:TSOP348xx +Interface_Optical:TSOP34S40F +Interface_Optical:TSOP382xx +Interface_Optical:TSOP384xx +Interface_Optical:TSOP38G36 +Interface_Optical:TSOP41xx +Interface_Optical:TSOP43xx +Interface_Optical:TSOP45xx +Interface_Optical:TSOP531xx +Interface_Optical:TSOP533xx +Interface_Optical:TSOP535xx +Interface_Optical:TSOP581xx +Interface_Optical:TSOP582xx +Interface_Optical:TSOP583xx +Interface_Optical:TSOP584xx +Interface_Optical:TSOP585xx +Interface_Telecom:FX614 +Interface_Telecom:HT9170D +Interface_Telecom:Si3210 +Interface_UART:16450 +Interface_UART:16550 +Interface_UART:68C681 +Interface_UART:8250 +Interface_UART:8252 +Interface_UART:ADM101E +Interface_UART:ADM1491EBR +Interface_UART:ADM205 +Interface_UART:ADM206 +Interface_UART:ADM207 +Interface_UART:ADM208 +Interface_UART:ADM209 +Interface_UART:ADM211 +Interface_UART:ADM213 +Interface_UART:ADM222 +Interface_UART:ADM232A +Interface_UART:ADM242 +Interface_UART:ADM2481xRW +Interface_UART:ADM2483xRW +Interface_UART:ADM2484E +Interface_UART:ADM2582E +Interface_UART:ADM2587E +Interface_UART:ADM2682E +Interface_UART:ADM2687E +Interface_UART:ADM3488ExR +Interface_UART:ADM3490ExR +Interface_UART:ADM3491ExR +Interface_UART:AZ75232G +Interface_UART:AZ75232GS +Interface_UART:AZ75232M +Interface_UART:GD65232DB +Interface_UART:GD65232DW +Interface_UART:GD65232PW +Interface_UART:GD75232DB +Interface_UART:GD75232DW +Interface_UART:GD75232N +Interface_UART:GD75232PW +Interface_UART:ICL3232 +Interface_UART:ISL3172E +Interface_UART:ISL3175E +Interface_UART:ISL3178E +Interface_UART:ISL3280ExHZ +Interface_UART:ISL3281ExHZ +Interface_UART:ISL3282ExRHZ +Interface_UART:ISL3283ExHZ +Interface_UART:ISL3284ExHZ +Interface_UART:ISL3295xxH +Interface_UART:ISL3298xxRT +Interface_UART:ISL83491 +Interface_UART:ISO1500 +Interface_UART:ISO3082DW +Interface_UART:ISO3088DW +Interface_UART:LT1080 +Interface_UART:LT1785AxN8 +Interface_UART:LT1785AxS8 +Interface_UART:LT1785xN8 +Interface_UART:LT1785xS8 +Interface_UART:LT1791AxN8 +Interface_UART:LT1791AxS +Interface_UART:LT1791xN8 +Interface_UART:LT1791xS +Interface_UART:LTC2850xDD +Interface_UART:LTC2850xMS8 +Interface_UART:LTC2850xS8 +Interface_UART:LTC2851xDD +Interface_UART:LTC2851xMS8 +Interface_UART:LTC2851xS8 +Interface_UART:LTC2852xDD +Interface_UART:LTC2852xMS +Interface_UART:LTC2852xS +Interface_UART:LTC2856xDD-1 +Interface_UART:LTC2856xDD-2 +Interface_UART:LTC2856xMS8-1 +Interface_UART:LTC2856xMS8-2 +Interface_UART:LTC2857xDD-1 +Interface_UART:LTC2857xDD-2 +Interface_UART:LTC2857xMS8-1 +Interface_UART:LTC2857xMS8-2 +Interface_UART:LTC2858xDD-1 +Interface_UART:LTC2858xDD-2 +Interface_UART:LTC2858xMS-1 +Interface_UART:LTC2858xMS-2 +Interface_UART:LTC2861 +Interface_UART:MAX13432EESD +Interface_UART:MAX13432EETD +Interface_UART:MAX13433EESD +Interface_UART:MAX13433EETD +Interface_UART:MAX14783ExS +Interface_UART:MAX14830 +Interface_UART:MAX1487E +Interface_UART:MAX202 +Interface_UART:MAX232 +Interface_UART:MAX232I +Interface_UART:MAX238xNG+ +Interface_UART:MAX238xWG+ +Interface_UART:MAX3051 +Interface_UART:MAX3072E +Interface_UART:MAX3075E +Interface_UART:MAX3078E +Interface_UART:MAX3218 +Interface_UART:MAX3221 +Interface_UART:MAX3226 +Interface_UART:MAX3227 +Interface_UART:MAX3232 +Interface_UART:MAX3284E +Interface_UART:MAX3483 +Interface_UART:MAX3485 +Interface_UART:MAX3486 +Interface_UART:MAX3488xPA +Interface_UART:MAX3488xSA +Interface_UART:MAX3490xPA +Interface_UART:MAX3490xSA +Interface_UART:MAX481E +Interface_UART:MAX483E +Interface_UART:MAX485E +Interface_UART:MAX487E +Interface_UART:MAX488E +Interface_UART:MAX489E +Interface_UART:MAX490E +Interface_UART:MAX491E +Interface_UART:MC6850 +Interface_UART:MC68A50 +Interface_UART:MC68B50 +Interface_UART:SC16IS740 +Interface_UART:SC16IS750xBS +Interface_UART:SC16IS750xPW +Interface_UART:SC16IS752IBS +Interface_UART:SC16IS752IPW +Interface_UART:SC16IS760xBS +Interface_UART:SC16IS760xPW +Interface_UART:SC16IS762IBS +Interface_UART:SC16IS762IPW +Interface_UART:SN65HVD11HD +Interface_UART:SN65LBC176D +Interface_UART:SN65LBC176P +Interface_UART:SN65LBC176QD +Interface_UART:SN65LBC176QDR +Interface_UART:SN75176AD +Interface_UART:SN75176AP +Interface_UART:SN75LBC176D +Interface_UART:SN75LBC176P +Interface_UART:SNJ55LBC176JG +Interface_UART:SP3481CN +Interface_UART:SP3481CP +Interface_UART:SP3481EN +Interface_UART:SP3481EP +Interface_UART:SP3485CN +Interface_UART:SP3485CP +Interface_UART:SP3485EN +Interface_UART:SP3485EP +Interface_UART:SSP3085 +Interface_UART:ST202ExD +Interface_UART:ST232ExD +Interface_UART:ST485E +Interface_UART:THVD1400D +Interface_UART:THVD1420D +Interface_UART:THVD1450D +Interface_UART:THVD1450DR +Interface_UART:THVD1451D +Interface_UART:THVD1500 +Interface_UART:THVD8000 +Interface_UART:Z8530 +Interface_USB:ADUM3160 +Interface_USB:ADUM4160 +Interface_USB:AP33771 +Interface_USB:BQ24392 +Interface_USB:CH224K +Interface_USB:CH236D +Interface_USB:CH246D +Interface_USB:CH330N +Interface_USB:CH334R +Interface_USB:CH340C +Interface_USB:CH340E +Interface_USB:CH340G +Interface_USB:CH340K +Interface_USB:CH340N +Interface_USB:CH340T +Interface_USB:CH340X +Interface_USB:CH343G +Interface_USB:CH343P +Interface_USB:CH344Q +Interface_USB:CH9102F +Interface_USB:CP2102N-Axx-xQFN20 +Interface_USB:CP2102N-Axx-xQFN24 +Interface_USB:CP2102N-Axx-xQFN28 +Interface_USB:CP2104 +Interface_USB:CP2108-xxx-xM +Interface_USB:CP2112 +Interface_USB:CP2615-xx-xM +Interface_USB:CY7C65211-24LTXI +Interface_USB:CY7C65211A-24LTXI +Interface_USB:CY7C65213-28PVXI +Interface_USB:CY7C65213-32LTXI +Interface_USB:CY7C65213A-28PVXI +Interface_USB:CY7C65213A-32LTXI +Interface_USB:CY7C65215-32LTXI +Interface_USB:CY7C65215A-32LTXI +Interface_USB:CYPD3171-24LQXQ +Interface_USB:CYPD3174-16SXQ +Interface_USB:CYPD3174-24LQXQ +Interface_USB:CYPD3175-24LQXQ +Interface_USB:CYPD3177-24LQ +Interface_USB:FE1.1s +Interface_USB:FSUSB30MUX +Interface_USB:FSUSB42MUX +Interface_USB:FT200XD +Interface_USB:FT201XQ +Interface_USB:FT201XS +Interface_USB:FT220XQ +Interface_USB:FT220XS +Interface_USB:FT221XQ +Interface_USB:FT221XS +Interface_USB:FT2232D +Interface_USB:FT2232HL +Interface_USB:FT2232HQ +Interface_USB:FT230XQ +Interface_USB:FT230XS +Interface_USB:FT231XQ +Interface_USB:FT231XS +Interface_USB:FT232BM +Interface_USB:FT232H +Interface_USB:FT232RL +Interface_USB:FT234XD +Interface_USB:FT240XQ +Interface_USB:FT240XS +Interface_USB:FT245BM +Interface_USB:FT4222HQ +Interface_USB:FT4232H +Interface_USB:FT601Q +Interface_USB:FUSB302B01MPX +Interface_USB:FUSB302B10MPX +Interface_USB:FUSB302B11MPX +Interface_USB:FUSB302BMPX +Interface_USB:FUSB303BTMX +Interface_USB:FUSB307BMPX +Interface_USB:IP2721 +Interface_USB:MA8601 +Interface_USB:MCP2200-E-SS +Interface_USB:MCP2200-I-MQ +Interface_USB:MCP2200-I-SO +Interface_USB:MCP2200-I-SS +Interface_USB:MCP2200T-E-SS +Interface_USB:MCP2200T-I-MQ +Interface_USB:MCP2200T-I-SO +Interface_USB:MCP2200T-I-SS +Interface_USB:MCP2210x-MQ +Interface_USB:MCP2210x-SO +Interface_USB:MCP2210x-SS +Interface_USB:MCP2221AxML +Interface_USB:MCP2221AxP +Interface_USB:MCP2221AxSL +Interface_USB:MCP2221AxST +Interface_USB:MP5034GJ +Interface_USB:STULPI01A +Interface_USB:STULPI01B +Interface_USB:STUSB4500QTR +Interface_USB:TPS2500DRC +Interface_USB:TPS2501DRC +Interface_USB:TPS2513 +Interface_USB:TPS2513A +Interface_USB:TPS2514 +Interface_USB:TPS2514A +Interface_USB:TPS2560 +Interface_USB:TPS2561 +Interface_USB:TPS25730D +Interface_USB:TS3USB30EDGSR +Interface_USB:TS3USB30ERSWR +Interface_USB:TS3USBCA410 +Interface_USB:TS3USBCA420 +Interface_USB:TUSB2036 +Interface_USB:TUSB320 +Interface_USB:TUSB320I +Interface_USB:TUSB321 +Interface_USB:TUSB322I +Interface_USB:TUSB4041I +Interface_USB:TUSB7340 +Interface_USB:TUSB8041 +Interface_USB:UPD720202K8-7x1-BAA +Interface_USB:USB2504 +Interface_USB:USB2514B_Bi +Interface_USB:USB3250-ABZJ +Interface_USB:USB3300-EZK +Interface_USB:USB3341 +Interface_USB:USB3343 +Interface_USB:USB3346 +Interface_USB:USB3347 +Interface_USB:USB3740B-AI2 +Interface_USB:USB3740B-AI9 +Interface_USB:XR21B1424 +Isolator:4N25 +Isolator:4N26 +Isolator:4N27 +Isolator:4N28 +Isolator:4N35 +Isolator:4N36 +Isolator:4N37 +Isolator:6N135 +Isolator:6N135S +Isolator:6N136 +Isolator:6N136S +Isolator:6N137 +Isolator:6N138 +Isolator:6N139 +Isolator:ACPL-214-500E +Isolator:ADN4650 +Isolator:ADN4651 +Isolator:ADN4652 +Isolator:ADuM1200AR +Isolator:ADuM1200BR +Isolator:ADuM1200CR +Isolator:ADuM1200WS +Isolator:ADuM1200WT +Isolator:ADuM1200WU +Isolator:ADuM1201AR +Isolator:ADuM1201BR +Isolator:ADuM1201CR +Isolator:ADuM1201WS +Isolator:ADuM1201WT +Isolator:ADuM1201WU +Isolator:ADuM120N +Isolator:ADuM121N +Isolator:ADuM1250 +Isolator:ADuM1281 +Isolator:ADuM1300xRW +Isolator:ADuM1400xRW +Isolator:ADuM1401xRW +Isolator:ADuM1402xRW +Isolator:ADuM1410 +Isolator:ADuM1411 +Isolator:ADuM1412 +Isolator:ADuM260N +Isolator:ADuM261N +Isolator:ADuM262N +Isolator:ADuM263N +Isolator:ADuM3151 +Isolator:ADuM3152 +Isolator:ADuM3153 +Isolator:ADuM5211 +Isolator:ADuM5401 +Isolator:ADuM5402 +Isolator:ADuM5403 +Isolator:ADuM5404 +Isolator:ADuM5410 +Isolator:ADuM5411 +Isolator:ADuM5412 +Isolator:ADuM7640A +Isolator:ADuM7640C +Isolator:ADuM7641A +Isolator:ADuM7641C +Isolator:ADuM7642A +Isolator:ADuM7642C +Isolator:ADuM7643A +Isolator:ADuM7643C +Isolator:CNY17-1 +Isolator:CNY17-2 +Isolator:CNY17-3 +Isolator:CNY17-4 +Isolator:CPC-5002 +Isolator:EL814 +Isolator:EL817 +Isolator:FODM214 +Isolator:FODM214A +Isolator:FODM217A +Isolator:FODM217B +Isolator:FODM217C +Isolator:FODM217D +Isolator:H11AA1 +Isolator:H11L1 +Isolator:H11L2 +Isolator:H11L3 +Isolator:HCNW2201 +Isolator:HCNW2211 +Isolator:HCPL-0201 +Isolator:HCPL-0211 +Isolator:HCPL-0600 +Isolator:HCPL-0601 +Isolator:HCPL-0611 +Isolator:HCPL-061A +Isolator:HCPL-061N +Isolator:HCPL-0630 +Isolator:HCPL-0631 +Isolator:HCPL-063A +Isolator:HCPL-063N +Isolator:HCPL-0661 +Isolator:HCPL-2201 +Isolator:HCPL-2202 +Isolator:HCPL-2211 +Isolator:HCPL-2212 +Isolator:HCPL-2601 +Isolator:HCPL-2611 +Isolator:HCPL-261A +Isolator:HCPL-261N +Isolator:HCPL-2630 +Isolator:HCPL-2631 +Isolator:HCPL-263A +Isolator:HCPL-263N +Isolator:HCPL-4661 +Isolator:HCPL-9000 +Isolator:HCPL2730 +Isolator:HCPL2731 +Isolator:ILD74 +Isolator:ILQ74 +Isolator:ISO1211 +Isolator:ISO1212 +Isolator:ISO1540 +Isolator:ISO1541 +Isolator:ISO1642DWR +Isolator:ISO1643DWR +Isolator:ISO1644DWR +Isolator:ISO6731 +Isolator:ISO6740 +Isolator:ISO6741 +Isolator:ISO6742 +Isolator:ISO7320C +Isolator:ISO7320FC +Isolator:ISO7321C +Isolator:ISO7321FC +Isolator:ISO7330C +Isolator:ISO7330FC +Isolator:ISO7331C +Isolator:ISO7331FC +Isolator:ISO7340C +Isolator:ISO7340FC +Isolator:ISO7341C +Isolator:ISO7341FC +Isolator:ISO7342C +Isolator:ISO7342FC +Isolator:ISO7760DBQ +Isolator:ISO7760DW +Isolator:ISO7760FDBQ +Isolator:ISO7760FDW +Isolator:ISO7761DBQ +Isolator:ISO7761DW +Isolator:ISO7761FDBQ +Isolator:ISO7761FDW +Isolator:ISO7762DBQ +Isolator:ISO7762DW +Isolator:ISO7762FDBQ +Isolator:ISO7762FDW +Isolator:ISO7763DBQ +Isolator:ISO7763DW +Isolator:ISO7763FDBQ +Isolator:ISO7763FDW +Isolator:ISOW7740 +Isolator:ISOW7741 +Isolator:ISOW7742 +Isolator:ISOW7743 +Isolator:ISOW7744 +Isolator:LTV-247 +Isolator:LTV-352T +Isolator:LTV-354T +Isolator:LTV-355T +Isolator:LTV-356T +Isolator:LTV-357T +Isolator:LTV-358T +Isolator:LTV-814 +Isolator:LTV-817 +Isolator:LTV-817M +Isolator:LTV-817S +Isolator:LTV-824 +Isolator:LTV-827 +Isolator:LTV-827M +Isolator:LTV-827S +Isolator:LTV-844 +Isolator:LTV-847 +Isolator:LTV-847M +Isolator:LTV-847S +Isolator:MAX14850AEE+ +Isolator:MAX14850ASE+ +Isolator:MID400 +Isolator:MOCD207M +Isolator:MOCD208M +Isolator:MOCD211M +Isolator:MOCD213M +Isolator:MOCD217M +Isolator:NSL-32 +Isolator:PC3H4 +Isolator:PC3H4A +Isolator:PC817 +Isolator:PC827 +Isolator:PC837 +Isolator:PC847 +Isolator:PS8802-1 +Isolator:PS8802-2 +Isolator:SFH617A-1 +Isolator:SFH617A-1X001 +Isolator:SFH617A-1X006 +Isolator:SFH617A-1X007T +Isolator:SFH617A-1X016 +Isolator:SFH617A-2 +Isolator:SFH617A-2X001 +Isolator:SFH617A-2X006 +Isolator:SFH617A-2X009T +Isolator:SFH617A-2X016 +Isolator:SFH617A-2X017T +Isolator:SFH617A-2X019T +Isolator:SFH617A-3 +Isolator:SFH617A-3X001 +Isolator:SFH617A-3X006 +Isolator:SFH617A-3X007T +Isolator:SFH617A-3X016 +Isolator:SFH617A-3X017T +Isolator:SFH617A-4 +Isolator:SFH617A-4X001 +Isolator:SFH617A-4X006 +Isolator:SFH617A-4X016 +Isolator:SFH6206-1T +Isolator:SFH6206-2T +Isolator:SFH6206-2X001T +Isolator:SFH6206-3T +Isolator:SFH6206-3X001T +Isolator:SFH620A-1 +Isolator:SFH620A-1X001 +Isolator:SFH620A-1X006 +Isolator:SFH620A-2 +Isolator:SFH620A-2X001 +Isolator:SFH620A-2X006 +Isolator:SFH620A-2X007T +Isolator:SFH620A-2X016 +Isolator:SFH620A-2X017T +Isolator:SFH620A-3 +Isolator:SFH620A-3X001 +Isolator:SFH620A-3X006 +Isolator:SFH620A-3X016 +Isolator:Si8640BA-B-IU +Isolator:Si8640BB-B-IS +Isolator:Si8640BB-B-IS1 +Isolator:Si8640BB-B-IU +Isolator:Si8640BC-B-IS1 +Isolator:Si8640BD-B-IS +Isolator:Si8640BD-B-IS2 +Isolator:Si8640EB-B-IU +Isolator:Si8640EC-B-IS1 +Isolator:Si8640ED-B-IS +Isolator:Si8640ED-B-IS2 +Isolator:Si8641BA-B-IU +Isolator:Si8641BB-B-IS +Isolator:Si8641BB-B-IS1 +Isolator:Si8641BB-B-IU +Isolator:Si8641BC-B-IS1 +Isolator:Si8641BD-B-IS +Isolator:Si8641BD-B-IS2 +Isolator:Si8641EB-B-IU +Isolator:Si8641EC-B-IS1 +Isolator:Si8641ED-B-IS +Isolator:Si8641ED-B-IS2 +Isolator:Si8642BA-B-IU +Isolator:Si8642BB-B-IS +Isolator:Si8642BB-B-IS1 +Isolator:Si8642BB-B-IU +Isolator:Si8642BC-B-IS1 +Isolator:Si8642BD-B-IS +Isolator:Si8642BD-B-IS2 +Isolator:Si8642EA-B-IU +Isolator:Si8642EB-B-IU +Isolator:Si8642EC-B-IS1 +Isolator:Si8642ED-B-IS +Isolator:Si8642ED-B-IS2 +Isolator:Si8645BA-B-IU +Isolator:Si8645BB-B-IS +Isolator:Si8645BB-B-IS1 +Isolator:Si8645BB-B-IU +Isolator:Si8645BC-B-IS1 +Isolator:Si8645BD-B-IS +Isolator:Si8660BA-AS1 +Isolator:Si8660BA-B-IS1 +Isolator:Si8660BB-AS1 +Isolator:Si8660BB-AU +Isolator:Si8660BB-B-IS1 +Isolator:Si8660BB-B-IU +Isolator:Si8660BC-AS1 +Isolator:Si8660BC-B-IS1 +Isolator:Si8660BD-AS +Isolator:Si8660BD-B-IS +Isolator:Si8660EB-AU +Isolator:Si8660EB-B-IU +Isolator:Si8660EC-AS1 +Isolator:Si8660EC-B-IS1 +Isolator:Si8660ED-AS +Isolator:Si8660ED-B-IS +Isolator:Si8661BB-AS1 +Isolator:Si8661BB-AU +Isolator:Si8661BB-B-IS1 +Isolator:Si8661BB-B-IU +Isolator:Si8661BC-AS1 +Isolator:Si8661BC-B-IS1 +Isolator:Si8661BD-AS +Isolator:Si8661BD-AS2 +Isolator:Si8661BD-B-IS +Isolator:Si8661BD-B-IS2 +Isolator:Si8661EB-AU +Isolator:Si8661EB-B-IU +Isolator:Si8661EC-AS1 +Isolator:Si8661EC-B-IS1 +Isolator:Si8661ED-AS +Isolator:Si8661ED-B-IS +Isolator:Si8662BB-AS1 +Isolator:Si8662BB-AU +Isolator:Si8662BB-B-IS1 +Isolator:Si8662BB-B-IU +Isolator:Si8662BC-AS1 +Isolator:Si8662BC-B-IS1 +Isolator:Si8662BD-AS +Isolator:Si8662BD-B-IS +Isolator:Si8662EB-AU +Isolator:Si8662EB-B-IU +Isolator:Si8662EC-AS1 +Isolator:Si8662EC-B-IS1 +Isolator:Si8662ED-AS +Isolator:Si8662ED-B-IS +Isolator:Si8663BB-AS1 +Isolator:Si8663BB-AU +Isolator:Si8663BB-B-IS1 +Isolator:Si8663BB-B-IU +Isolator:Si8663BC-AS1 +Isolator:Si8663BC-B-IS1 +Isolator:Si8663BD-AS +Isolator:Si8663BD-B-IS +Isolator:Si8663EB-AU +Isolator:Si8663EB-B-IU +Isolator:Si8663EC-AS1 +Isolator:Si8663EC-B-IS1 +Isolator:Si8663ED-AS +Isolator:Si8663ED-B-IS +Isolator:TCMT1100 +Isolator:TCMT1101 +Isolator:TCMT1102 +Isolator:TCMT1103 +Isolator:TCMT1104 +Isolator:TCMT1105 +Isolator:TCMT1106 +Isolator:TCMT1107 +Isolator:TCMT1108 +Isolator:TCMT1109 +Isolator:TCMT1600 +Isolator:TCMT4100 +Isolator:TCMT4106 +Isolator:TCMT4600 +Isolator:TCMT4606 +Isolator:TIL111 +Isolator:TLP127 +Isolator:TLP130 +Isolator:TLP131 +Isolator:TLP137 +Isolator:TLP184 +Isolator:TLP184xSE +Isolator:TLP185 +Isolator:TLP185xSE +Isolator:TLP2310 +Isolator:TLP2703 +Isolator:TLP2745 +Isolator:TLP2748 +Isolator:TLP2761 +Isolator:TLP2767 +Isolator:TLP2768A +Isolator:TLP2770 +Isolator:TLP290 +Isolator:TLP290-4 +Isolator:TLP291 +Isolator:TLP291-4 +Isolator:TLP292 +Isolator:TLP292-4 +Isolator:TLP293 +Isolator:TLP293-4 +Isolator:TLP3021 +Isolator:TLP3022 +Isolator:TLP3023 +Isolator:TLP627 +Isolator:TLP627-2 +Isolator:TLP627-4 +Isolator:TLP785 +Isolator:TLP785F +Isolator:VO0600T +Isolator:VO0601T +Isolator:VO0611T +Isolator:VO0630T +Isolator:VO0631T +Isolator:VO0661T +Isolator:VO2601 +Isolator:VO2611 +Isolator:VO2630 +Isolator:VO2631 +Isolator:VO4661 +Isolator:VO615A +Isolator:VO615A-1 +Isolator:VO615A-2 +Isolator:VO615A-3 +Isolator:VO615A-4 +Isolator:VO615A-5 +Isolator:VO615A-6 +Isolator:VO615A-7 +Isolator:VO615A-8 +Isolator:VO615A-9 +Isolator:VOA300 +Isolator:VOS618A +Isolator:VTL5C +Isolator:VTL5Cx2 +Isolator:π120U30 +Isolator:π120U31 +Isolator_Analog:ACPL-C790 +Isolator_Analog:ACPL-C79A +Isolator_Analog:ACPL-C79B +Isolator_Analog:ACPL-C870 +Isolator_Analog:ACPL-C87A +Isolator_Analog:ACPL-C87B +Isolator_Analog:AMC3330 +Isolator_Analog:IL300 +Isolator_Analog:LOC112 +Isolator_Analog:LOC112P +Isolator_Analog:LOC112S +Jumper:Jumper_2_Bridged +Jumper:Jumper_2_Open +Jumper:Jumper_2_Small_Bridged +Jumper:Jumper_2_Small_Open +Jumper:Jumper_3_Bridged12 +Jumper:Jumper_3_Open +Jumper:SolderJumper_2_Bridged +Jumper:SolderJumper_2_Open +Jumper:SolderJumper_3_Bridged12 +Jumper:SolderJumper_3_Bridged123 +Jumper:SolderJumper_3_Open +LED:APA-106-F5 +LED:APA102 +LED:APA102-2020 +LED:APFA3010 +LED:ASMB-MTB0-0A3A2 +LED:ASMB-MTB1-0A3A2 +LED:ASMT-YTB7-0AA02 +LED:ASMT-YTC2-0AA02 +LED:CLS6B-FKW +LED:CLV1L-FKB +LED:CLX6F-FKC +LED:CQY99 +LED:HDSP-4830 +LED:HDSP-4830_2 +LED:HDSP-4832 +LED:HDSP-4832_2 +LED:HDSP-4836 +LED:HDSP-4836_2 +LED:HDSP-4840 +LED:HDSP-4840_2 +LED:HDSP-4850 +LED:HDSP-4850_2 +LED:HLCP-J100 +LED:HLCP-J100_2 +LED:IR204A +LED:IR26-21C_L110_TR8 +LED:IRL81A +LED:Inolux_IN-P55TATRGB +LED:Inolux_IN-PI554FCH +LED:Inolux_IN-PI556FCH +LED:LD271 +LED:LD274 +LED:LED_Cree_XHP50_12V +LED:LED_Cree_XHP50_6V +LED:LED_Cree_XHP70_12V +LED:LED_Cree_XHP70_6V +LED:LTST-C235KGKRKT +LED:LiteOn_LTST-E563C +LED:NeoPixel_THT +LED:QLS6A-FKW +LED:QLS6B-FKW +LED:SFH4346 +LED:SFH4356P +LED:SFH4546 +LED:SFH4550 +LED:SFH460 +LED:SFH480 +LED:SFH482 +LED:SK6805 +LED:SK6812 +LED:SK6812MINI +LED:SMLVN6RGB +LED:TSAL4400 +LED:WS2812 +LED:WS2812B +LED:WS2812B-2020 +LED:WS2812S +LED:WS2813 +LED:WS2822S +Logic_LevelTranslator:74LVC2T45DC +Logic_LevelTranslator:74LVCH2T45DC +Logic_LevelTranslator:FXMA108 +Logic_LevelTranslator:NCN4555MN +Logic_LevelTranslator:NLSV2T244D +Logic_LevelTranslator:NLSV2T244DM +Logic_LevelTranslator:NLSV2T244MU +Logic_LevelTranslator:SN74AUP1T34DCK +Logic_LevelTranslator:SN74AVC4T245PW +Logic_LevelTranslator:SN74AVC8T245PW +Logic_LevelTranslator:SN74LV1T125DBV +Logic_LevelTranslator:SN74LV1T125DCK +Logic_LevelTranslator:SN74LV1T34DBV +Logic_LevelTranslator:SN74LV1T34DCK +Logic_LevelTranslator:SN74LVC1T45DBV +Logic_LevelTranslator:SN74LVC1T45DCK +Logic_LevelTranslator:SN74LVC1T45DRL +Logic_LevelTranslator:SN74LVC245APW +Logic_LevelTranslator:SN74LVC2T45DCUR +Logic_LevelTranslator:SN74LVC2T45YZP +Logic_LevelTranslator:SN74LVC8T245 +Logic_LevelTranslator:TCA9517ADGK +Logic_LevelTranslator:TCA9517D +Logic_LevelTranslator:TXB0101DBV +Logic_LevelTranslator:TXB0101DCK +Logic_LevelTranslator:TXB0101DRL +Logic_LevelTranslator:TXB0101YZP +Logic_LevelTranslator:TXB0102DCT +Logic_LevelTranslator:TXB0102DCU +Logic_LevelTranslator:TXB0102YZP +Logic_LevelTranslator:TXB0104D +Logic_LevelTranslator:TXB0104PW +Logic_LevelTranslator:TXB0104RGY +Logic_LevelTranslator:TXB0104RUT +Logic_LevelTranslator:TXB0104YZT +Logic_LevelTranslator:TXB0104ZXU +Logic_LevelTranslator:TXB0106PW +Logic_LevelTranslator:TXB0106RGY +Logic_LevelTranslator:TXB0108DQSR +Logic_LevelTranslator:TXB0108PW +Logic_LevelTranslator:TXB0108RGY +Logic_LevelTranslator:TXB0304RUT +Logic_LevelTranslator:TXBN0304RUT +Logic_LevelTranslator:TXS0101DBV +Logic_LevelTranslator:TXS0101DCK +Logic_LevelTranslator:TXS0101DRL +Logic_LevelTranslator:TXS0101YZP +Logic_LevelTranslator:TXS0102DCT +Logic_LevelTranslator:TXS0102DCU +Logic_LevelTranslator:TXS0102DQE +Logic_LevelTranslator:TXS0102YZP +Logic_LevelTranslator:TXS0104ED +Logic_LevelTranslator:TXS0104EPW +Logic_LevelTranslator:TXS0108EPW +Logic_LevelTranslator:TXS02612RTW +Logic_Programmable:GAL16V8 +Logic_Programmable:PAL16L8 +Logic_Programmable:PAL20 +Logic_Programmable:PAL20L8 +Logic_Programmable:PAL20RS10 +Logic_Programmable:PAL24 +Logic_Programmable:PEEL22CV10AP +Logic_Programmable:PEEL22CV10AS +MCU_AnalogDevices:ADUC816 +MCU_AnalogDevices:MAX32660GTP +MCU_AnalogDevices:MAX32670GTL +MCU_Cypress:CY7C68013A-56LTX +MCU_Cypress:CY7C68013A-56PVX +MCU_Cypress:CY7C68014A-56LTX +MCU_Cypress:CY7C68014A-56PVX +MCU_Cypress:CY8C4127LQI-BL453 +MCU_Cypress:CY8C4127LQI-BL473 +MCU_Cypress:CY8C4127LQI-BL483 +MCU_Cypress:CY8C4127LQI-BL493 +MCU_Cypress:CY8C4245AXI-M445 +MCU_Cypress:CY8C4245AZI-M445 +MCU_Cypress:CY8C4246AXI-M445 +MCU_Cypress:CY8C4246AZI-M445 +MCU_Cypress:CY8C4246AZI-M475 +MCU_Cypress:CY8C4247AXI-M485 +MCU_Cypress:CY8C4247AZI-M475 +MCU_Cypress:CY8C4247AZI-M485 +MCU_Cypress:CY8C4247LQI-BL453 +MCU_Cypress:CY8C4247LQI-BL463 +MCU_Cypress:CY8C4247LQI-BL473 +MCU_Cypress:CY8C4247LQI-BL483 +MCU_Cypress:CY8C4247LQI-BL493 +MCU_Cypress:CY8C4247LQQ-BL483 +MCU_Cypress:CY8C4xx7LQI-4xx +MCU_Cypress:CYBL10161-56LQXI +MCU_Cypress:CYBL10162-56LQXI +MCU_Cypress:CYBL10163-56LQXI +MCU_Cypress:CYBL10461-56LQXI +MCU_Cypress:CYBL10462-56LQXI +MCU_Cypress:CYBL10463-56LQXI +MCU_Cypress:CYBL10561-56LQXI +MCU_Cypress:CYBL10562-56LQXI +MCU_Cypress:CYBL10563-56LQXI +MCU_Cypress:CYBL10563-56LQXQ +MCU_Cypress:CYBL10563-68FLXIT +MCU_Cypress:CYBL10563-68FNXIT +MCU_Cypress:CYBL10x6x-56LQxx +MCU_Dialog:DA14691 +MCU_Dialog:DA14695 +MCU_Espressif:ESP32-C3 +MCU_Espressif:ESP32-PICO-D4 +MCU_Espressif:ESP32-S2 +MCU_Espressif:ESP32-S3 +MCU_Espressif:ESP8266EX +MCU_Intel:80186 +MCU_Intel:80188 +MCU_Intel:8035 +MCU_Intel:8039 +MCU_Intel:8040 +MCU_Intel:8048 +MCU_Intel:8049 +MCU_Intel:8050 +MCU_Intel:8080 +MCU_Intel:8080A +MCU_Intel:8086_Max_Mode +MCU_Intel:8086_Min_Mode +MCU_Intel:8087 +MCU_Intel:8088 +MCU_Intel:8088_Max_Mode +MCU_Intel:8088_Min_Mode +MCU_Intel:80C186XL +MCU_Intel:80C188 +MCU_Intel:80C188XL +MCU_Intel:8748 +MCU_Intel:8749 +MCU_Intel:I386EX_PQFP +MCU_Intel:IA186XLPLC68IR2 +MCU_Intel:IA188XLPLC68IR2 +MCU_Intel:M80C186 +MCU_Intel:M80C186XL +MCU_Intel:P8031AH +MCU_Intel:P8051AH +MCU_Intel:P8052AH +MCU_Intel:P8751BH +MCU_Intel:P8752BH +MCU_Microchip_8051:AT89C2051-12P +MCU_Microchip_8051:AT89C2051-12S +MCU_Microchip_8051:AT89C2051-24P +MCU_Microchip_8051:AT89C2051-24S +MCU_Microchip_8051:AT89C4051-12P +MCU_Microchip_8051:AT89C4051-12S +MCU_Microchip_8051:AT89C4051-24P +MCU_Microchip_8051:AT89C4051-24S +MCU_Microchip_8051:AT89S2051-24P +MCU_Microchip_8051:AT89S2051-24S +MCU_Microchip_8051:AT89S4051-24P +MCU_Microchip_8051:AT89S4051-24S +MCU_Microchip_8051:AT89x51xxA +MCU_Microchip_8051:AT89x51xxJ +MCU_Microchip_8051:AT89x51xxP +MCU_Microchip_ATmega:ATmega128-16A +MCU_Microchip_ATmega:ATmega128-16M +MCU_Microchip_ATmega:ATmega1280-16A +MCU_Microchip_ATmega:ATmega1280-16C +MCU_Microchip_ATmega:ATmega1280V-8A +MCU_Microchip_ATmega:ATmega1280V-8C +MCU_Microchip_ATmega:ATmega1281-16A +MCU_Microchip_ATmega:ATmega1281-16M +MCU_Microchip_ATmega:ATmega1281V-8A +MCU_Microchip_ATmega:ATmega1281V-8M +MCU_Microchip_ATmega:ATmega1284-A +MCU_Microchip_ATmega:ATmega1284-M +MCU_Microchip_ATmega:ATmega1284-P +MCU_Microchip_ATmega:ATmega1284P-A +MCU_Microchip_ATmega:ATmega1284P-M +MCU_Microchip_ATmega:ATmega1284P-P +MCU_Microchip_ATmega:ATmega128A-A +MCU_Microchip_ATmega:ATmega128A-M +MCU_Microchip_ATmega:ATmega128L-8A +MCU_Microchip_ATmega:ATmega128L-8M +MCU_Microchip_ATmega:ATmega16-16A +MCU_Microchip_ATmega:ATmega16-16M +MCU_Microchip_ATmega:ATmega16-16P +MCU_Microchip_ATmega:ATmega162-16A +MCU_Microchip_ATmega:ATmega162-16M +MCU_Microchip_ATmega:ATmega162-16P +MCU_Microchip_ATmega:ATmega162V-8A +MCU_Microchip_ATmega:ATmega162V-8M +MCU_Microchip_ATmega:ATmega162V-8P +MCU_Microchip_ATmega:ATmega164A-A +MCU_Microchip_ATmega:ATmega164A-C +MCU_Microchip_ATmega:ATmega164A-M +MCU_Microchip_ATmega:ATmega164A-MC +MCU_Microchip_ATmega:ATmega164A-P +MCU_Microchip_ATmega:ATmega164P-20A +MCU_Microchip_ATmega:ATmega164P-20M +MCU_Microchip_ATmega:ATmega164P-20P +MCU_Microchip_ATmega:ATmega164PA-A +MCU_Microchip_ATmega:ATmega164PA-C +MCU_Microchip_ATmega:ATmega164PA-M +MCU_Microchip_ATmega:ATmega164PA-MC +MCU_Microchip_ATmega:ATmega164PA-P +MCU_Microchip_ATmega:ATmega164PV-10A +MCU_Microchip_ATmega:ATmega164PV-10M +MCU_Microchip_ATmega:ATmega164PV-10P +MCU_Microchip_ATmega:ATmega165A-A +MCU_Microchip_ATmega:ATmega165A-M +MCU_Microchip_ATmega:ATmega165P-16A +MCU_Microchip_ATmega:ATmega165P-16M +MCU_Microchip_ATmega:ATmega165PA-A +MCU_Microchip_ATmega:ATmega165PA-M +MCU_Microchip_ATmega:ATmega165PV-8A +MCU_Microchip_ATmega:ATmega165PV-8M +MCU_Microchip_ATmega:ATmega168-20A +MCU_Microchip_ATmega:ATmega168-20M +MCU_Microchip_ATmega:ATmega168-20P +MCU_Microchip_ATmega:ATmega168A-A +MCU_Microchip_ATmega:ATmega168A-CC +MCU_Microchip_ATmega:ATmega168A-M +MCU_Microchip_ATmega:ATmega168A-MM +MCU_Microchip_ATmega:ATmega168A-P +MCU_Microchip_ATmega:ATmega168P-20A +MCU_Microchip_ATmega:ATmega168P-20M +MCU_Microchip_ATmega:ATmega168P-20P +MCU_Microchip_ATmega:ATmega168PA-A +MCU_Microchip_ATmega:ATmega168PA-CC +MCU_Microchip_ATmega:ATmega168PA-M +MCU_Microchip_ATmega:ATmega168PA-MM +MCU_Microchip_ATmega:ATmega168PA-P +MCU_Microchip_ATmega:ATmega168PB-A +MCU_Microchip_ATmega:ATmega168PB-M +MCU_Microchip_ATmega:ATmega168PV-10A +MCU_Microchip_ATmega:ATmega168PV-10M +MCU_Microchip_ATmega:ATmega168PV-10P +MCU_Microchip_ATmega:ATmega168V-10A +MCU_Microchip_ATmega:ATmega168V-10M +MCU_Microchip_ATmega:ATmega168V-10P +MCU_Microchip_ATmega:ATmega169A-A +MCU_Microchip_ATmega:ATmega169A-M +MCU_Microchip_ATmega:ATmega169A-MC +MCU_Microchip_ATmega:ATmega169P-16A +MCU_Microchip_ATmega:ATmega169P-16M +MCU_Microchip_ATmega:ATmega169P-16MC +MCU_Microchip_ATmega:ATmega169PA-A +MCU_Microchip_ATmega:ATmega169PA-M +MCU_Microchip_ATmega:ATmega169PA-MC +MCU_Microchip_ATmega:ATmega169PV-8A +MCU_Microchip_ATmega:ATmega169PV-8M +MCU_Microchip_ATmega:ATmega169PV-8MC +MCU_Microchip_ATmega:ATmega16A-A +MCU_Microchip_ATmega:ATmega16A-M +MCU_Microchip_ATmega:ATmega16A-P +MCU_Microchip_ATmega:ATmega16L-8A +MCU_Microchip_ATmega:ATmega16L-8M +MCU_Microchip_ATmega:ATmega16L-8P +MCU_Microchip_ATmega:ATmega16M1-A +MCU_Microchip_ATmega:ATmega16M1-M +MCU_Microchip_ATmega:ATmega16U2-A +MCU_Microchip_ATmega:ATmega16U2-M +MCU_Microchip_ATmega:ATmega16U4-A +MCU_Microchip_ATmega:ATmega16U4-M +MCU_Microchip_ATmega:ATmega16U4RC-A +MCU_Microchip_ATmega:ATmega16U4RC-M +MCU_Microchip_ATmega:ATmega2560-16A +MCU_Microchip_ATmega:ATmega2560-16C +MCU_Microchip_ATmega:ATmega2560V-8A +MCU_Microchip_ATmega:ATmega2560V-8C +MCU_Microchip_ATmega:ATmega2561-16A +MCU_Microchip_ATmega:ATmega2561-16M +MCU_Microchip_ATmega:ATmega2561V-8A +MCU_Microchip_ATmega:ATmega2561V-8M +MCU_Microchip_ATmega:ATmega32-16A +MCU_Microchip_ATmega:ATmega32-16M +MCU_Microchip_ATmega:ATmega32-16P +MCU_Microchip_ATmega:ATmega3208-A +MCU_Microchip_ATmega:ATmega3208-M +MCU_Microchip_ATmega:ATmega3208-X +MCU_Microchip_ATmega:ATmega3209-A +MCU_Microchip_ATmega:ATmega3209-M +MCU_Microchip_ATmega:ATmega324A-A +MCU_Microchip_ATmega:ATmega324A-C +MCU_Microchip_ATmega:ATmega324A-M +MCU_Microchip_ATmega:ATmega324A-MC +MCU_Microchip_ATmega:ATmega324A-P +MCU_Microchip_ATmega:ATmega324P-20A +MCU_Microchip_ATmega:ATmega324P-20M +MCU_Microchip_ATmega:ATmega324P-20P +MCU_Microchip_ATmega:ATmega324PA-A +MCU_Microchip_ATmega:ATmega324PA-C +MCU_Microchip_ATmega:ATmega324PA-M +MCU_Microchip_ATmega:ATmega324PA-MC +MCU_Microchip_ATmega:ATmega324PA-P +MCU_Microchip_ATmega:ATmega324PB-A +MCU_Microchip_ATmega:ATmega324PB-M +MCU_Microchip_ATmega:ATmega324PV-10A +MCU_Microchip_ATmega:ATmega324PV-10M +MCU_Microchip_ATmega:ATmega324PV-10P +MCU_Microchip_ATmega:ATmega325-16A +MCU_Microchip_ATmega:ATmega325-16M +MCU_Microchip_ATmega:ATmega3250-16A +MCU_Microchip_ATmega:ATmega3250A-A +MCU_Microchip_ATmega:ATmega3250P-20A +MCU_Microchip_ATmega:ATmega3250PA-A +MCU_Microchip_ATmega:ATmega3250PV-10A +MCU_Microchip_ATmega:ATmega3250V-8A +MCU_Microchip_ATmega:ATmega325A-A +MCU_Microchip_ATmega:ATmega325A-M +MCU_Microchip_ATmega:ATmega325P-20A +MCU_Microchip_ATmega:ATmega325P-20M +MCU_Microchip_ATmega:ATmega325PA-A +MCU_Microchip_ATmega:ATmega325PA-M +MCU_Microchip_ATmega:ATmega325PV-10A +MCU_Microchip_ATmega:ATmega325PV-10M +MCU_Microchip_ATmega:ATmega325V-8A +MCU_Microchip_ATmega:ATmega325V-8M +MCU_Microchip_ATmega:ATmega328-A +MCU_Microchip_ATmega:ATmega328-M +MCU_Microchip_ATmega:ATmega328-MM +MCU_Microchip_ATmega:ATmega328-P +MCU_Microchip_ATmega:ATmega328P-A +MCU_Microchip_ATmega:ATmega328P-M +MCU_Microchip_ATmega:ATmega328P-MM +MCU_Microchip_ATmega:ATmega328P-P +MCU_Microchip_ATmega:ATmega328PB-A +MCU_Microchip_ATmega:ATmega328PB-M +MCU_Microchip_ATmega:ATmega329-16A +MCU_Microchip_ATmega:ATmega329-16M +MCU_Microchip_ATmega:ATmega3290-16A +MCU_Microchip_ATmega:ATmega3290A-A +MCU_Microchip_ATmega:ATmega3290P-20A +MCU_Microchip_ATmega:ATmega3290PA-A +MCU_Microchip_ATmega:ATmega3290PV-10A +MCU_Microchip_ATmega:ATmega3290V-8A +MCU_Microchip_ATmega:ATmega329A-A +MCU_Microchip_ATmega:ATmega329A-M +MCU_Microchip_ATmega:ATmega329P-20A +MCU_Microchip_ATmega:ATmega329P-20M +MCU_Microchip_ATmega:ATmega329PA-A +MCU_Microchip_ATmega:ATmega329PA-M +MCU_Microchip_ATmega:ATmega329PV-10A +MCU_Microchip_ATmega:ATmega329PV-10M +MCU_Microchip_ATmega:ATmega329V-8A +MCU_Microchip_ATmega:ATmega329V-8M +MCU_Microchip_ATmega:ATmega32A-A +MCU_Microchip_ATmega:ATmega32A-M +MCU_Microchip_ATmega:ATmega32A-P +MCU_Microchip_ATmega:ATmega32L-8A +MCU_Microchip_ATmega:ATmega32L-8M +MCU_Microchip_ATmega:ATmega32L-8P +MCU_Microchip_ATmega:ATmega32M1-A +MCU_Microchip_ATmega:ATmega32M1-M +MCU_Microchip_ATmega:ATmega32U2-A +MCU_Microchip_ATmega:ATmega32U2-M +MCU_Microchip_ATmega:ATmega32U4-A +MCU_Microchip_ATmega:ATmega32U4-M +MCU_Microchip_ATmega:ATmega32U4RC-A +MCU_Microchip_ATmega:ATmega32U4RC-M +MCU_Microchip_ATmega:ATmega406-1AA +MCU_Microchip_ATmega:ATmega48-20A +MCU_Microchip_ATmega:ATmega48-20M +MCU_Microchip_ATmega:ATmega48-20MM +MCU_Microchip_ATmega:ATmega48-20P +MCU_Microchip_ATmega:ATmega4808-A +MCU_Microchip_ATmega:ATmega4808-M +MCU_Microchip_ATmega:ATmega4808-X +MCU_Microchip_ATmega:ATmega4809-A +MCU_Microchip_ATmega:ATmega4809-M +MCU_Microchip_ATmega:ATmega48A-A +MCU_Microchip_ATmega:ATmega48A-CC +MCU_Microchip_ATmega:ATmega48A-M +MCU_Microchip_ATmega:ATmega48A-MM +MCU_Microchip_ATmega:ATmega48A-P +MCU_Microchip_ATmega:ATmega48P-20A +MCU_Microchip_ATmega:ATmega48P-20M +MCU_Microchip_ATmega:ATmega48P-20MM +MCU_Microchip_ATmega:ATmega48P-20P +MCU_Microchip_ATmega:ATmega48PA-A +MCU_Microchip_ATmega:ATmega48PA-CC +MCU_Microchip_ATmega:ATmega48PA-M +MCU_Microchip_ATmega:ATmega48PA-MM +MCU_Microchip_ATmega:ATmega48PA-P +MCU_Microchip_ATmega:ATmega48PB-A +MCU_Microchip_ATmega:ATmega48PB-M +MCU_Microchip_ATmega:ATmega48PV-10A +MCU_Microchip_ATmega:ATmega48PV-10M +MCU_Microchip_ATmega:ATmega48PV-10MM +MCU_Microchip_ATmega:ATmega48PV-10P +MCU_Microchip_ATmega:ATmega48V-10A +MCU_Microchip_ATmega:ATmega48V-10M +MCU_Microchip_ATmega:ATmega48V-10MM +MCU_Microchip_ATmega:ATmega48V-10P +MCU_Microchip_ATmega:ATmega64-16A +MCU_Microchip_ATmega:ATmega64-16M +MCU_Microchip_ATmega:ATmega640-16A +MCU_Microchip_ATmega:ATmega640-16C +MCU_Microchip_ATmega:ATmega640V-8A +MCU_Microchip_ATmega:ATmega640V-8C +MCU_Microchip_ATmega:ATmega644-20A +MCU_Microchip_ATmega:ATmega644-20M +MCU_Microchip_ATmega:ATmega644-20P +MCU_Microchip_ATmega:ATmega644A-A +MCU_Microchip_ATmega:ATmega644A-M +MCU_Microchip_ATmega:ATmega644A-P +MCU_Microchip_ATmega:ATmega644P-20A +MCU_Microchip_ATmega:ATmega644P-20M +MCU_Microchip_ATmega:ATmega644P-20P +MCU_Microchip_ATmega:ATmega644PA-A +MCU_Microchip_ATmega:ATmega644PA-M +MCU_Microchip_ATmega:ATmega644PA-P +MCU_Microchip_ATmega:ATmega644PV-10A +MCU_Microchip_ATmega:ATmega644PV-10M +MCU_Microchip_ATmega:ATmega644PV-10P +MCU_Microchip_ATmega:ATmega644V-10A +MCU_Microchip_ATmega:ATmega644V-10M +MCU_Microchip_ATmega:ATmega644V-10P +MCU_Microchip_ATmega:ATmega645-16A +MCU_Microchip_ATmega:ATmega645-16M +MCU_Microchip_ATmega:ATmega6450-16A +MCU_Microchip_ATmega:ATmega6450A-A +MCU_Microchip_ATmega:ATmega6450P-A +MCU_Microchip_ATmega:ATmega6450V-8A +MCU_Microchip_ATmega:ATmega645A-A +MCU_Microchip_ATmega:ATmega645A-M +MCU_Microchip_ATmega:ATmega645P-A +MCU_Microchip_ATmega:ATmega645P-M +MCU_Microchip_ATmega:ATmega645V-8A +MCU_Microchip_ATmega:ATmega645V-8M +MCU_Microchip_ATmega:ATmega649-16A +MCU_Microchip_ATmega:ATmega649-16M +MCU_Microchip_ATmega:ATmega6490-16A +MCU_Microchip_ATmega:ATmega6490A-A +MCU_Microchip_ATmega:ATmega6490P-A +MCU_Microchip_ATmega:ATmega6490V-8A +MCU_Microchip_ATmega:ATmega649A-A +MCU_Microchip_ATmega:ATmega649A-M +MCU_Microchip_ATmega:ATmega649P-A +MCU_Microchip_ATmega:ATmega649P-M +MCU_Microchip_ATmega:ATmega649V-8A +MCU_Microchip_ATmega:ATmega649V-8M +MCU_Microchip_ATmega:ATmega64A-A +MCU_Microchip_ATmega:ATmega64A-M +MCU_Microchip_ATmega:ATmega64L-8A +MCU_Microchip_ATmega:ATmega64L-8M +MCU_Microchip_ATmega:ATmega64M1-A +MCU_Microchip_ATmega:ATmega64M1-M +MCU_Microchip_ATmega:ATmega8-16A +MCU_Microchip_ATmega:ATmega8-16M +MCU_Microchip_ATmega:ATmega8-16P +MCU_Microchip_ATmega:ATmega8515-16A +MCU_Microchip_ATmega:ATmega8515-16J +MCU_Microchip_ATmega:ATmega8515-16M +MCU_Microchip_ATmega:ATmega8515-16P +MCU_Microchip_ATmega:ATmega8515L-8A +MCU_Microchip_ATmega:ATmega8515L-8J +MCU_Microchip_ATmega:ATmega8515L-8M +MCU_Microchip_ATmega:ATmega8515L-8P +MCU_Microchip_ATmega:ATmega8535-16A +MCU_Microchip_ATmega:ATmega8535-16J +MCU_Microchip_ATmega:ATmega8535-16M +MCU_Microchip_ATmega:ATmega8535-16P +MCU_Microchip_ATmega:ATmega8535L-8A +MCU_Microchip_ATmega:ATmega8535L-8J +MCU_Microchip_ATmega:ATmega8535L-8M +MCU_Microchip_ATmega:ATmega8535L-8P +MCU_Microchip_ATmega:ATmega88-20A +MCU_Microchip_ATmega:ATmega88-20M +MCU_Microchip_ATmega:ATmega88-20P +MCU_Microchip_ATmega:ATmega88A-A +MCU_Microchip_ATmega:ATmega88A-CC +MCU_Microchip_ATmega:ATmega88A-M +MCU_Microchip_ATmega:ATmega88A-MM +MCU_Microchip_ATmega:ATmega88A-P +MCU_Microchip_ATmega:ATmega88P-20A +MCU_Microchip_ATmega:ATmega88P-20M +MCU_Microchip_ATmega:ATmega88P-20P +MCU_Microchip_ATmega:ATmega88PA-A +MCU_Microchip_ATmega:ATmega88PA-CC +MCU_Microchip_ATmega:ATmega88PA-M +MCU_Microchip_ATmega:ATmega88PA-MM +MCU_Microchip_ATmega:ATmega88PA-P +MCU_Microchip_ATmega:ATmega88PB-A +MCU_Microchip_ATmega:ATmega88PB-M +MCU_Microchip_ATmega:ATmega88PV-10A +MCU_Microchip_ATmega:ATmega88PV-10M +MCU_Microchip_ATmega:ATmega88PV-10P +MCU_Microchip_ATmega:ATmega88V-10A +MCU_Microchip_ATmega:ATmega88V-10M +MCU_Microchip_ATmega:ATmega88V-10P +MCU_Microchip_ATmega:ATmega8A-A +MCU_Microchip_ATmega:ATmega8A-M +MCU_Microchip_ATmega:ATmega8A-P +MCU_Microchip_ATmega:ATmega8L-8A +MCU_Microchip_ATmega:ATmega8L-8M +MCU_Microchip_ATmega:ATmega8L-8P +MCU_Microchip_ATmega:ATmega8U2-A +MCU_Microchip_ATmega:ATmega8U2-M +MCU_Microchip_ATmega:ATxmega128A1-A +MCU_Microchip_ATmega:ATxmega128A1-C +MCU_Microchip_ATmega:ATxmega128A1-C7 +MCU_Microchip_ATmega:ATxmega128A1U-A +MCU_Microchip_ATmega:ATxmega128A1U-C +MCU_Microchip_ATmega:ATxmega128A1U-C7 +MCU_Microchip_ATmega:ATxmega128A3-A +MCU_Microchip_ATmega:ATxmega128A3-M +MCU_Microchip_ATmega:ATxmega128A3U-A +MCU_Microchip_ATmega:ATxmega128A3U-M +MCU_Microchip_ATmega:ATxmega128A4U-A +MCU_Microchip_ATmega:ATxmega128A4U-C +MCU_Microchip_ATmega:ATxmega128A4U-M +MCU_Microchip_ATmega:ATxmega128B1-A +MCU_Microchip_ATmega:ATxmega128B1-C +MCU_Microchip_ATmega:ATxmega128B3-A +MCU_Microchip_ATmega:ATxmega128B3-M +MCU_Microchip_ATmega:ATxmega128B3-MC +MCU_Microchip_ATmega:ATxmega128C3-A +MCU_Microchip_ATmega:ATxmega128C3-M +MCU_Microchip_ATmega:ATxmega128D3-A +MCU_Microchip_ATmega:ATxmega128D3-M +MCU_Microchip_ATmega:ATxmega128D4-A +MCU_Microchip_ATmega:ATxmega128D4-C +MCU_Microchip_ATmega:ATxmega128D4-M +MCU_Microchip_ATmega:ATxmega16A4U-A +MCU_Microchip_ATmega:ATxmega16A4U-C +MCU_Microchip_ATmega:ATxmega16A4U-M +MCU_Microchip_ATmega:ATxmega16C4-A +MCU_Microchip_ATmega:ATxmega16C4-C +MCU_Microchip_ATmega:ATxmega16C4-M +MCU_Microchip_ATmega:ATxmega16D4-A +MCU_Microchip_ATmega:ATxmega16D4-C +MCU_Microchip_ATmega:ATxmega16D4-M +MCU_Microchip_ATmega:ATxmega16E5-A +MCU_Microchip_ATmega:ATxmega16E5-M +MCU_Microchip_ATmega:ATxmega16E5-M4 +MCU_Microchip_ATmega:ATxmega192A3-A +MCU_Microchip_ATmega:ATxmega192A3-M +MCU_Microchip_ATmega:ATxmega192A3U-A +MCU_Microchip_ATmega:ATxmega192A3U-M +MCU_Microchip_ATmega:ATxmega192C3-A +MCU_Microchip_ATmega:ATxmega192C3-M +MCU_Microchip_ATmega:ATxmega192D3-A +MCU_Microchip_ATmega:ATxmega192D3-M +MCU_Microchip_ATmega:ATxmega256A3-A +MCU_Microchip_ATmega:ATxmega256A3-M +MCU_Microchip_ATmega:ATxmega256A3B-A +MCU_Microchip_ATmega:ATxmega256A3B-M +MCU_Microchip_ATmega:ATxmega256A3BU-A +MCU_Microchip_ATmega:ATxmega256A3BU-M +MCU_Microchip_ATmega:ATxmega256A3U-A +MCU_Microchip_ATmega:ATxmega256A3U-M +MCU_Microchip_ATmega:ATxmega256C3-A +MCU_Microchip_ATmega:ATxmega256C3-M +MCU_Microchip_ATmega:ATxmega256D3-A +MCU_Microchip_ATmega:ATxmega256D3-M +MCU_Microchip_ATmega:ATxmega32A4U-A +MCU_Microchip_ATmega:ATxmega32A4U-C +MCU_Microchip_ATmega:ATxmega32A4U-M +MCU_Microchip_ATmega:ATxmega32C3-A +MCU_Microchip_ATmega:ATxmega32C3-M +MCU_Microchip_ATmega:ATxmega32C4-A +MCU_Microchip_ATmega:ATxmega32C4-C +MCU_Microchip_ATmega:ATxmega32C4-M +MCU_Microchip_ATmega:ATxmega32D3-A +MCU_Microchip_ATmega:ATxmega32D3-M +MCU_Microchip_ATmega:ATxmega32D4-A +MCU_Microchip_ATmega:ATxmega32D4-C +MCU_Microchip_ATmega:ATxmega32D4-M +MCU_Microchip_ATmega:ATxmega32E5-A +MCU_Microchip_ATmega:ATxmega32E5-M +MCU_Microchip_ATmega:ATxmega32E5-M4 +MCU_Microchip_ATmega:ATxmega384C3-A +MCU_Microchip_ATmega:ATxmega384C3-M +MCU_Microchip_ATmega:ATxmega384D3-A +MCU_Microchip_ATmega:ATxmega384D3-M +MCU_Microchip_ATmega:ATxmega64A1-A +MCU_Microchip_ATmega:ATxmega64A1-C +MCU_Microchip_ATmega:ATxmega64A1-C7 +MCU_Microchip_ATmega:ATxmega64A1U-A +MCU_Microchip_ATmega:ATxmega64A1U-C +MCU_Microchip_ATmega:ATxmega64A1U-C7 +MCU_Microchip_ATmega:ATxmega64A3-A +MCU_Microchip_ATmega:ATxmega64A3-M +MCU_Microchip_ATmega:ATxmega64A3U-A +MCU_Microchip_ATmega:ATxmega64A3U-M +MCU_Microchip_ATmega:ATxmega64A4U-A +MCU_Microchip_ATmega:ATxmega64A4U-C +MCU_Microchip_ATmega:ATxmega64A4U-M +MCU_Microchip_ATmega:ATxmega64B1-A +MCU_Microchip_ATmega:ATxmega64B1-C +MCU_Microchip_ATmega:ATxmega64B3-A +MCU_Microchip_ATmega:ATxmega64B3-M +MCU_Microchip_ATmega:ATxmega64C3-A +MCU_Microchip_ATmega:ATxmega64C3-M +MCU_Microchip_ATmega:ATxmega64D3-A +MCU_Microchip_ATmega:ATxmega64D3-M +MCU_Microchip_ATmega:ATxmega64D4-A +MCU_Microchip_ATmega:ATxmega64D4-C +MCU_Microchip_ATmega:ATxmega64D4-M +MCU_Microchip_ATmega:ATxmega8E5-A +MCU_Microchip_ATmega:ATxmega8E5-M +MCU_Microchip_ATmega:ATxmega8E5-M4 +MCU_Microchip_ATtiny:ATtiny10-MA +MCU_Microchip_ATtiny:ATtiny10-TS +MCU_Microchip_ATtiny:ATtiny102-M +MCU_Microchip_ATtiny:ATtiny102-SS +MCU_Microchip_ATtiny:ATtiny104-SS +MCU_Microchip_ATtiny:ATtiny13-20M +MCU_Microchip_ATtiny:ATtiny13-20MM +MCU_Microchip_ATtiny:ATtiny13-20P +MCU_Microchip_ATtiny:ATtiny13-20S +MCU_Microchip_ATtiny:ATtiny13-20SS +MCU_Microchip_ATtiny:ATtiny13A-M +MCU_Microchip_ATtiny:ATtiny13A-MM +MCU_Microchip_ATtiny:ATtiny13A-P +MCU_Microchip_ATtiny:ATtiny13A-S +MCU_Microchip_ATtiny:ATtiny13A-SS +MCU_Microchip_ATtiny:ATtiny13V-10M +MCU_Microchip_ATtiny:ATtiny13V-10MM +MCU_Microchip_ATtiny:ATtiny13V-10P +MCU_Microchip_ATtiny:ATtiny13V-10S +MCU_Microchip_ATtiny:ATtiny13V-10SS +MCU_Microchip_ATtiny:ATtiny1604-SS +MCU_Microchip_ATtiny:ATtiny1606-M +MCU_Microchip_ATtiny:ATtiny1606-S +MCU_Microchip_ATtiny:ATtiny1607-M +MCU_Microchip_ATtiny:ATtiny1614-SS +MCU_Microchip_ATtiny:ATtiny1616-M +MCU_Microchip_ATtiny:ATtiny1616-S +MCU_Microchip_ATtiny:ATtiny1617-M +MCU_Microchip_ATtiny:ATtiny1624-SS +MCU_Microchip_ATtiny:ATtiny1624-X +MCU_Microchip_ATtiny:ATtiny1626-M +MCU_Microchip_ATtiny:ATtiny1626-S +MCU_Microchip_ATtiny:ATtiny1626-X +MCU_Microchip_ATtiny:ATtiny1627-M +MCU_Microchip_ATtiny:ATtiny1634-M +MCU_Microchip_ATtiny:ATtiny1634-S +MCU_Microchip_ATtiny:ATtiny167-M +MCU_Microchip_ATtiny:ATtiny167-S +MCU_Microchip_ATtiny:ATtiny167-X +MCU_Microchip_ATtiny:ATtiny20-CC +MCU_Microchip_ATtiny:ATtiny20-MM +MCU_Microchip_ATtiny:ATtiny20-SS +MCU_Microchip_ATtiny:ATtiny20-U +MCU_Microchip_ATtiny:ATtiny20-X +MCU_Microchip_ATtiny:ATtiny202-SS +MCU_Microchip_ATtiny:ATtiny204-SS +MCU_Microchip_ATtiny:ATtiny212-SS +MCU_Microchip_ATtiny:ATtiny214-SS +MCU_Microchip_ATtiny:ATtiny2313-20M +MCU_Microchip_ATtiny:ATtiny2313-20P +MCU_Microchip_ATtiny:ATtiny2313-20S +MCU_Microchip_ATtiny:ATtiny2313A-M +MCU_Microchip_ATtiny:ATtiny2313A-MM +MCU_Microchip_ATtiny:ATtiny2313A-P +MCU_Microchip_ATtiny:ATtiny2313A-S +MCU_Microchip_ATtiny:ATtiny2313V-10M +MCU_Microchip_ATtiny:ATtiny2313V-10P +MCU_Microchip_ATtiny:ATtiny2313V-10S +MCU_Microchip_ATtiny:ATtiny24-20M +MCU_Microchip_ATtiny:ATtiny24-20P +MCU_Microchip_ATtiny:ATtiny24-20SS +MCU_Microchip_ATtiny:ATtiny24A-CC +MCU_Microchip_ATtiny:ATtiny24A-M +MCU_Microchip_ATtiny:ATtiny24A-MM +MCU_Microchip_ATtiny:ATtiny24A-P +MCU_Microchip_ATtiny:ATtiny24A-SS +MCU_Microchip_ATtiny:ATtiny24V-10M +MCU_Microchip_ATtiny:ATtiny24V-10P +MCU_Microchip_ATtiny:ATtiny24V-10SS +MCU_Microchip_ATtiny:ATtiny25-20M +MCU_Microchip_ATtiny:ATtiny25-20P +MCU_Microchip_ATtiny:ATtiny25-20S +MCU_Microchip_ATtiny:ATtiny25-20SS +MCU_Microchip_ATtiny:ATtiny25V-10M +MCU_Microchip_ATtiny:ATtiny25V-10P +MCU_Microchip_ATtiny:ATtiny25V-10S +MCU_Microchip_ATtiny:ATtiny25V-10SS +MCU_Microchip_ATtiny:ATtiny26-16M +MCU_Microchip_ATtiny:ATtiny26-16P +MCU_Microchip_ATtiny:ATtiny26-16S +MCU_Microchip_ATtiny:ATtiny261A-M +MCU_Microchip_ATtiny:ATtiny261A-P +MCU_Microchip_ATtiny:ATtiny261A-S +MCU_Microchip_ATtiny:ATtiny261A-X +MCU_Microchip_ATtiny:ATtiny26L-8M +MCU_Microchip_ATtiny:ATtiny26L-8P +MCU_Microchip_ATtiny:ATtiny26L-8S +MCU_Microchip_ATtiny:ATtiny28L-4A +MCU_Microchip_ATtiny:ATtiny28L-4M +MCU_Microchip_ATtiny:ATtiny28L-4P +MCU_Microchip_ATtiny:ATtiny28V-1A +MCU_Microchip_ATtiny:ATtiny28V-1M +MCU_Microchip_ATtiny:ATtiny28V-1P +MCU_Microchip_ATtiny:ATtiny3216-M +MCU_Microchip_ATtiny:ATtiny3216-S +MCU_Microchip_ATtiny:ATtiny3217-M +MCU_Microchip_ATtiny:ATtiny3224-SS +MCU_Microchip_ATtiny:ATtiny3224-X +MCU_Microchip_ATtiny:ATtiny3226-M +MCU_Microchip_ATtiny:ATtiny3226-S +MCU_Microchip_ATtiny:ATtiny3226-X +MCU_Microchip_ATtiny:ATtiny3227-M +MCU_Microchip_ATtiny:ATtiny4-MA +MCU_Microchip_ATtiny:ATtiny4-TS +MCU_Microchip_ATtiny:ATtiny40-MM +MCU_Microchip_ATtiny:ATtiny40-S +MCU_Microchip_ATtiny:ATtiny40-X +MCU_Microchip_ATtiny:ATtiny402-SS +MCU_Microchip_ATtiny:ATtiny404-SS +MCU_Microchip_ATtiny:ATtiny406-M +MCU_Microchip_ATtiny:ATtiny406-S +MCU_Microchip_ATtiny:ATtiny412-SS +MCU_Microchip_ATtiny:ATtiny414-SS +MCU_Microchip_ATtiny:ATtiny416-M +MCU_Microchip_ATtiny:ATtiny416-S +MCU_Microchip_ATtiny:ATtiny417-M +MCU_Microchip_ATtiny:ATtiny424-SS +MCU_Microchip_ATtiny:ATtiny424-X +MCU_Microchip_ATtiny:ATtiny426-M +MCU_Microchip_ATtiny:ATtiny426-S +MCU_Microchip_ATtiny:ATtiny426-X +MCU_Microchip_ATtiny:ATtiny427-M +MCU_Microchip_ATtiny:ATtiny4313-M +MCU_Microchip_ATtiny:ATtiny4313-MM +MCU_Microchip_ATtiny:ATtiny4313-P +MCU_Microchip_ATtiny:ATtiny4313-S +MCU_Microchip_ATtiny:ATtiny43U-M +MCU_Microchip_ATtiny:ATtiny43U-S +MCU_Microchip_ATtiny:ATtiny44-20M +MCU_Microchip_ATtiny:ATtiny44-20P +MCU_Microchip_ATtiny:ATtiny44-20SS +MCU_Microchip_ATtiny:ATtiny441-M +MCU_Microchip_ATtiny:ATtiny441-MM +MCU_Microchip_ATtiny:ATtiny441-SS +MCU_Microchip_ATtiny:ATtiny44A-CC +MCU_Microchip_ATtiny:ATtiny44A-M +MCU_Microchip_ATtiny:ATtiny44A-MM +MCU_Microchip_ATtiny:ATtiny44A-P +MCU_Microchip_ATtiny:ATtiny44A-SS +MCU_Microchip_ATtiny:ATtiny44V-10M +MCU_Microchip_ATtiny:ATtiny44V-10P +MCU_Microchip_ATtiny:ATtiny44V-10SS +MCU_Microchip_ATtiny:ATtiny45-20M +MCU_Microchip_ATtiny:ATtiny45-20P +MCU_Microchip_ATtiny:ATtiny45-20S +MCU_Microchip_ATtiny:ATtiny45-20X +MCU_Microchip_ATtiny:ATtiny45V-10M +MCU_Microchip_ATtiny:ATtiny45V-10P +MCU_Microchip_ATtiny:ATtiny45V-10S +MCU_Microchip_ATtiny:ATtiny45V-10X +MCU_Microchip_ATtiny:ATtiny461-20M +MCU_Microchip_ATtiny:ATtiny461-20P +MCU_Microchip_ATtiny:ATtiny461-20S +MCU_Microchip_ATtiny:ATtiny461A-M +MCU_Microchip_ATtiny:ATtiny461A-P +MCU_Microchip_ATtiny:ATtiny461A-S +MCU_Microchip_ATtiny:ATtiny461A-X +MCU_Microchip_ATtiny:ATtiny461V-10M +MCU_Microchip_ATtiny:ATtiny461V-10P +MCU_Microchip_ATtiny:ATtiny461V-10S +MCU_Microchip_ATtiny:ATtiny48-A +MCU_Microchip_ATtiny:ATtiny48-CC +MCU_Microchip_ATtiny:ATtiny48-M +MCU_Microchip_ATtiny:ATtiny48-MM +MCU_Microchip_ATtiny:ATtiny48-P +MCU_Microchip_ATtiny:ATtiny5-MA +MCU_Microchip_ATtiny:ATtiny5-TS +MCU_Microchip_ATtiny:ATtiny804-SS +MCU_Microchip_ATtiny:ATtiny806-M +MCU_Microchip_ATtiny:ATtiny806-S +MCU_Microchip_ATtiny:ATtiny807-M +MCU_Microchip_ATtiny:ATtiny814-SS +MCU_Microchip_ATtiny:ATtiny816-M +MCU_Microchip_ATtiny:ATtiny816-S +MCU_Microchip_ATtiny:ATtiny817-M +MCU_Microchip_ATtiny:ATtiny824-SS +MCU_Microchip_ATtiny:ATtiny824-X +MCU_Microchip_ATtiny:ATtiny826-M +MCU_Microchip_ATtiny:ATtiny826-S +MCU_Microchip_ATtiny:ATtiny826-X +MCU_Microchip_ATtiny:ATtiny827-M +MCU_Microchip_ATtiny:ATtiny828-A +MCU_Microchip_ATtiny:ATtiny828-M +MCU_Microchip_ATtiny:ATtiny84-20M +MCU_Microchip_ATtiny:ATtiny84-20P +MCU_Microchip_ATtiny:ATtiny84-20SS +MCU_Microchip_ATtiny:ATtiny841-M +MCU_Microchip_ATtiny:ATtiny841-MM +MCU_Microchip_ATtiny:ATtiny841-SS +MCU_Microchip_ATtiny:ATtiny84A-CC +MCU_Microchip_ATtiny:ATtiny84A-M +MCU_Microchip_ATtiny:ATtiny84A-MM +MCU_Microchip_ATtiny:ATtiny84A-P +MCU_Microchip_ATtiny:ATtiny84A-SS +MCU_Microchip_ATtiny:ATtiny84V-10M +MCU_Microchip_ATtiny:ATtiny84V-10P +MCU_Microchip_ATtiny:ATtiny84V-10SS +MCU_Microchip_ATtiny:ATtiny85-20M +MCU_Microchip_ATtiny:ATtiny85-20P +MCU_Microchip_ATtiny:ATtiny85-20S +MCU_Microchip_ATtiny:ATtiny85V-10M +MCU_Microchip_ATtiny:ATtiny85V-10P +MCU_Microchip_ATtiny:ATtiny85V-10S +MCU_Microchip_ATtiny:ATtiny861-20M +MCU_Microchip_ATtiny:ATtiny861-20P +MCU_Microchip_ATtiny:ATtiny861-20S +MCU_Microchip_ATtiny:ATtiny861A-M +MCU_Microchip_ATtiny:ATtiny861A-P +MCU_Microchip_ATtiny:ATtiny861A-S +MCU_Microchip_ATtiny:ATtiny861A-X +MCU_Microchip_ATtiny:ATtiny861V-10M +MCU_Microchip_ATtiny:ATtiny861V-10P +MCU_Microchip_ATtiny:ATtiny861V-10S +MCU_Microchip_ATtiny:ATtiny87-M +MCU_Microchip_ATtiny:ATtiny87-S +MCU_Microchip_ATtiny:ATtiny87-X +MCU_Microchip_ATtiny:ATtiny88-A +MCU_Microchip_ATtiny:ATtiny88-CC +MCU_Microchip_ATtiny:ATtiny88-M +MCU_Microchip_ATtiny:ATtiny88-MM +MCU_Microchip_ATtiny:ATtiny88-P +MCU_Microchip_ATtiny:ATtiny9-MA +MCU_Microchip_ATtiny:ATtiny9-TS +MCU_Microchip_AVR:AT90CAN128-16A +MCU_Microchip_AVR:AT90CAN128-16M +MCU_Microchip_AVR:AT90CAN32-16A +MCU_Microchip_AVR:AT90CAN32-16M +MCU_Microchip_AVR:AT90CAN64-16A +MCU_Microchip_AVR:AT90CAN64-16M +MCU_Microchip_AVR:AT90PWM1-16M +MCU_Microchip_AVR:AT90PWM1-16S +MCU_Microchip_AVR:AT90USB1286-A +MCU_Microchip_AVR:AT90USB1286-M +MCU_Microchip_AVR:AT90USB1287-A +MCU_Microchip_AVR:AT90USB1287-M +MCU_Microchip_AVR:AT90USB162-16A +MCU_Microchip_AVR:AT90USB162-16M +MCU_Microchip_AVR:AT90USB646-A +MCU_Microchip_AVR:AT90USB646-M +MCU_Microchip_AVR:AT90USB647-A +MCU_Microchip_AVR:AT90USB647-M +MCU_Microchip_AVR:AT90USB82-16M +MCU_Microchip_AVR_Dx:AVR128DA28x-xSO +MCU_Microchip_AVR_Dx:AVR128DA28x-xSP +MCU_Microchip_AVR_Dx:AVR128DA28x-xSS +MCU_Microchip_AVR_Dx:AVR128DA32x-xPT +MCU_Microchip_AVR_Dx:AVR128DA32x-xRXB +MCU_Microchip_AVR_Dx:AVR128DA48x-x6LX +MCU_Microchip_AVR_Dx:AVR128DA48x-xPT +MCU_Microchip_AVR_Dx:AVR128DA64x-xMR +MCU_Microchip_AVR_Dx:AVR128DA64x-xPT +MCU_Microchip_AVR_Dx:AVR128DB28x-xSO +MCU_Microchip_AVR_Dx:AVR128DB28x-xSP +MCU_Microchip_AVR_Dx:AVR128DB28x-xSS +MCU_Microchip_AVR_Dx:AVR128DB32x-xPT +MCU_Microchip_AVR_Dx:AVR128DB32x-xRXB +MCU_Microchip_AVR_Dx:AVR128DB48x-x6LX +MCU_Microchip_AVR_Dx:AVR128DB48x-xPT +MCU_Microchip_AVR_Dx:AVR128DB64x-xMR +MCU_Microchip_AVR_Dx:AVR128DB64x-xPT +MCU_Microchip_AVR_Dx:AVR32DA28x-xSO +MCU_Microchip_AVR_Dx:AVR32DA28x-xSP +MCU_Microchip_AVR_Dx:AVR32DA28x-xSS +MCU_Microchip_AVR_Dx:AVR32DA32x-xPT +MCU_Microchip_AVR_Dx:AVR32DA32x-xRXB +MCU_Microchip_AVR_Dx:AVR32DA48x-x6LX +MCU_Microchip_AVR_Dx:AVR32DA48x-xPT +MCU_Microchip_AVR_Dx:AVR32DB28x-xSO +MCU_Microchip_AVR_Dx:AVR32DB28x-xSP +MCU_Microchip_AVR_Dx:AVR32DB28x-xSS +MCU_Microchip_AVR_Dx:AVR32DB32x-xPT +MCU_Microchip_AVR_Dx:AVR32DB32x-xRXB +MCU_Microchip_AVR_Dx:AVR32DB48x-x6LX +MCU_Microchip_AVR_Dx:AVR32DB48x-xPT +MCU_Microchip_AVR_Dx:AVR64DA28x-xSO +MCU_Microchip_AVR_Dx:AVR64DA28x-xSP +MCU_Microchip_AVR_Dx:AVR64DA28x-xSS +MCU_Microchip_AVR_Dx:AVR64DA32x-xPT +MCU_Microchip_AVR_Dx:AVR64DA32x-xRXB +MCU_Microchip_AVR_Dx:AVR64DA48x-x6LX +MCU_Microchip_AVR_Dx:AVR64DA48x-xPT +MCU_Microchip_AVR_Dx:AVR64DA64x-xMR +MCU_Microchip_AVR_Dx:AVR64DA64x-xPT +MCU_Microchip_AVR_Dx:AVR64DB28x-xSO +MCU_Microchip_AVR_Dx:AVR64DB28x-xSP +MCU_Microchip_AVR_Dx:AVR64DB28x-xSS +MCU_Microchip_AVR_Dx:AVR64DB32x-xPT +MCU_Microchip_AVR_Dx:AVR64DB32x-xRXB +MCU_Microchip_AVR_Dx:AVR64DB48x-x6LX +MCU_Microchip_AVR_Dx:AVR64DB48x-xPT +MCU_Microchip_AVR_Dx:AVR64DB64x-xMR +MCU_Microchip_AVR_Dx:AVR64DB64x-xPT +MCU_Microchip_PIC10:PIC10F200-IMC +MCU_Microchip_PIC10:PIC10F200-IOT +MCU_Microchip_PIC10:PIC10F200-IP +MCU_Microchip_PIC10:PIC10F202-IMC +MCU_Microchip_PIC10:PIC10F202-IOT +MCU_Microchip_PIC10:PIC10F202-IP +MCU_Microchip_PIC10:PIC10F204-IMC +MCU_Microchip_PIC10:PIC10F204-IOT +MCU_Microchip_PIC10:PIC10F204-IP +MCU_Microchip_PIC10:PIC10F206-IMC +MCU_Microchip_PIC10:PIC10F206-IOT +MCU_Microchip_PIC10:PIC10F206-IP +MCU_Microchip_PIC10:PIC10F220-IMC +MCU_Microchip_PIC10:PIC10F220-IOT +MCU_Microchip_PIC10:PIC10F220-IP +MCU_Microchip_PIC10:PIC10F222-IMC +MCU_Microchip_PIC10:PIC10F222-IOT +MCU_Microchip_PIC10:PIC10F222-IP +MCU_Microchip_PIC10:PIC10F320-IMC +MCU_Microchip_PIC10:PIC10F320-IOT +MCU_Microchip_PIC10:PIC10F320-IP +MCU_Microchip_PIC10:PIC10F322-IMC +MCU_Microchip_PIC10:PIC10F322-IOT +MCU_Microchip_PIC10:PIC10F322-IP +MCU_Microchip_PIC12:PIC12C508-xJW +MCU_Microchip_PIC12:PIC12C508-xP +MCU_Microchip_PIC12:PIC12C508-xSM +MCU_Microchip_PIC12:PIC12C508A-xJW +MCU_Microchip_PIC12:PIC12C508A-xP +MCU_Microchip_PIC12:PIC12C508A-xSM +MCU_Microchip_PIC12:PIC12C508A-xSN +MCU_Microchip_PIC12:PIC12C509-xJW +MCU_Microchip_PIC12:PIC12C509-xP +MCU_Microchip_PIC12:PIC12C509-xSM +MCU_Microchip_PIC12:PIC12C509A-xJW +MCU_Microchip_PIC12:PIC12C509A-xP +MCU_Microchip_PIC12:PIC12C509A-xSM +MCU_Microchip_PIC12:PIC12C509A-xSN +MCU_Microchip_PIC12:PIC12C671-xJW +MCU_Microchip_PIC12:PIC12C671-xP +MCU_Microchip_PIC12:PIC12C671-xSN +MCU_Microchip_PIC12:PIC12C672-xJW +MCU_Microchip_PIC12:PIC12C672-xP +MCU_Microchip_PIC12:PIC12C672-xSN +MCU_Microchip_PIC12:PIC12CE518-xJW +MCU_Microchip_PIC12:PIC12CE518-xP +MCU_Microchip_PIC12:PIC12CE518-xSM +MCU_Microchip_PIC12:PIC12CE518-xSN +MCU_Microchip_PIC12:PIC12CE519-xJW +MCU_Microchip_PIC12:PIC12CE519-xP +MCU_Microchip_PIC12:PIC12CE519-xSM +MCU_Microchip_PIC12:PIC12CE519-xSN +MCU_Microchip_PIC12:PIC12CE673-xJW +MCU_Microchip_PIC12:PIC12CE673-xP +MCU_Microchip_PIC12:PIC12CE674-xJW +MCU_Microchip_PIC12:PIC12CE674-xP +MCU_Microchip_PIC12:PIC12CR509A-xP +MCU_Microchip_PIC12:PIC12CR509A-xSM +MCU_Microchip_PIC12:PIC12CR509A-xSN +MCU_Microchip_PIC12:PIC12F1501-xMC +MCU_Microchip_PIC12:PIC12F1501-xMS +MCU_Microchip_PIC12:PIC12F1501-xP +MCU_Microchip_PIC12:PIC12F1501-xSN +MCU_Microchip_PIC12:PIC12F1822-xMC +MCU_Microchip_PIC12:PIC12F1822-xP +MCU_Microchip_PIC12:PIC12F1822-xSN +MCU_Microchip_PIC12:PIC12F1840-xMC +MCU_Microchip_PIC12:PIC12F1840-xP +MCU_Microchip_PIC12:PIC12F1840-xSN +MCU_Microchip_PIC12:PIC12F508-xMC +MCU_Microchip_PIC12:PIC12F508-xMS +MCU_Microchip_PIC12:PIC12F508-xP +MCU_Microchip_PIC12:PIC12F508-xSN +MCU_Microchip_PIC12:PIC12F509-xMC +MCU_Microchip_PIC12:PIC12F509-xMS +MCU_Microchip_PIC12:PIC12F509-xP +MCU_Microchip_PIC12:PIC12F509-xSN +MCU_Microchip_PIC12:PIC12F510-xMC +MCU_Microchip_PIC12:PIC12F510-xMS +MCU_Microchip_PIC12:PIC12F510-xP +MCU_Microchip_PIC12:PIC12F510-xSN +MCU_Microchip_PIC12:PIC12F519-xMC +MCU_Microchip_PIC12:PIC12F519-xMS +MCU_Microchip_PIC12:PIC12F519-xP +MCU_Microchip_PIC12:PIC12F519-xSN +MCU_Microchip_PIC12:PIC12F609-xMC +MCU_Microchip_PIC12:PIC12F609-xMS +MCU_Microchip_PIC12:PIC12F609-xP +MCU_Microchip_PIC12:PIC12F609-xSN +MCU_Microchip_PIC12:PIC12F615-xMC +MCU_Microchip_PIC12:PIC12F615-xMS +MCU_Microchip_PIC12:PIC12F615-xP +MCU_Microchip_PIC12:PIC12F615-xSN +MCU_Microchip_PIC12:PIC12F617-xMC +MCU_Microchip_PIC12:PIC12F617-xMS +MCU_Microchip_PIC12:PIC12F617-xP +MCU_Microchip_PIC12:PIC12F617-xSN +MCU_Microchip_PIC12:PIC12F629-xMC +MCU_Microchip_PIC12:PIC12F629-xMS +MCU_Microchip_PIC12:PIC12F629-xP +MCU_Microchip_PIC12:PIC12F629-xSN +MCU_Microchip_PIC12:PIC12F635-xMC +MCU_Microchip_PIC12:PIC12F635-xMS +MCU_Microchip_PIC12:PIC12F635-xP +MCU_Microchip_PIC12:PIC12F635-xSN +MCU_Microchip_PIC12:PIC12F675-xMC +MCU_Microchip_PIC12:PIC12F675-xMS +MCU_Microchip_PIC12:PIC12F675-xP +MCU_Microchip_PIC12:PIC12F675-xSN +MCU_Microchip_PIC12:PIC12F683-xMC +MCU_Microchip_PIC12:PIC12F683-xMS +MCU_Microchip_PIC12:PIC12F683-xP +MCU_Microchip_PIC12:PIC12F683-xSN +MCU_Microchip_PIC12:PIC12F752-xMC +MCU_Microchip_PIC12:PIC12F752-xP +MCU_Microchip_PIC12:PIC12F752-xSN +MCU_Microchip_PIC12:PIC12HV609-xMC +MCU_Microchip_PIC12:PIC12HV609-xMS +MCU_Microchip_PIC12:PIC12HV609-xP +MCU_Microchip_PIC12:PIC12HV609-xSN +MCU_Microchip_PIC12:PIC12HV615-xMC +MCU_Microchip_PIC12:PIC12HV615-xMS +MCU_Microchip_PIC12:PIC12HV615-xP +MCU_Microchip_PIC12:PIC12HV615-xSN +MCU_Microchip_PIC12:PIC12HV752-xMC +MCU_Microchip_PIC12:PIC12HV752-xP +MCU_Microchip_PIC12:PIC12HV752-xSN +MCU_Microchip_PIC12:PIC12LF1501-xMC +MCU_Microchip_PIC12:PIC12LF1501-xMS +MCU_Microchip_PIC12:PIC12LF1501-xP +MCU_Microchip_PIC12:PIC12LF1501-xSN +MCU_Microchip_PIC12:PIC12LF1822-xMC +MCU_Microchip_PIC12:PIC12LF1822-xP +MCU_Microchip_PIC12:PIC12LF1822-xSN +MCU_Microchip_PIC12:PIC12LF1840-xMC +MCU_Microchip_PIC12:PIC12LF1840-xP +MCU_Microchip_PIC12:PIC12LF1840-xSN +MCU_Microchip_PIC12:PIC12LF1840T48-xST +MCU_Microchip_PIC16:PIC16C505-IP +MCU_Microchip_PIC16:PIC16C505-ISL +MCU_Microchip_PIC16:PIC16C505-IST +MCU_Microchip_PIC16:PIC16F1454-IML +MCU_Microchip_PIC16:PIC16F1454-IP +MCU_Microchip_PIC16:PIC16F1454-ISL +MCU_Microchip_PIC16:PIC16F1454-ISS +MCU_Microchip_PIC16:PIC16F1454-IST +MCU_Microchip_PIC16:PIC16F1455-IML +MCU_Microchip_PIC16:PIC16F1455-IP +MCU_Microchip_PIC16:PIC16F1455-ISL +MCU_Microchip_PIC16:PIC16F1455-ISS +MCU_Microchip_PIC16:PIC16F1455-IST +MCU_Microchip_PIC16:PIC16F1459-IML +MCU_Microchip_PIC16:PIC16F1459-IP +MCU_Microchip_PIC16:PIC16F1459-ISO +MCU_Microchip_PIC16:PIC16F1459-ISS +MCU_Microchip_PIC16:PIC16F1459-IST +MCU_Microchip_PIC16:PIC16F1503-IMG +MCU_Microchip_PIC16:PIC16F1503-IP +MCU_Microchip_PIC16:PIC16F1503-ISL +MCU_Microchip_PIC16:PIC16F1503-IST +MCU_Microchip_PIC16:PIC16F1507-IML +MCU_Microchip_PIC16:PIC16F1507-IP +MCU_Microchip_PIC16:PIC16F1507-ISO +MCU_Microchip_PIC16:PIC16F1507-ISS +MCU_Microchip_PIC16:PIC16F1508-IML +MCU_Microchip_PIC16:PIC16F1508-IP +MCU_Microchip_PIC16:PIC16F1508-ISO +MCU_Microchip_PIC16:PIC16F1508-ISS +MCU_Microchip_PIC16:PIC16F1509-IML +MCU_Microchip_PIC16:PIC16F1509-IP +MCU_Microchip_PIC16:PIC16F1509-ISO +MCU_Microchip_PIC16:PIC16F1509-ISS +MCU_Microchip_PIC16:PIC16F1512-IMV +MCU_Microchip_PIC16:PIC16F1512-ISO +MCU_Microchip_PIC16:PIC16F1512-ISP +MCU_Microchip_PIC16:PIC16F1512-ISS +MCU_Microchip_PIC16:PIC16F1513-IMV +MCU_Microchip_PIC16:PIC16F1513-ISO +MCU_Microchip_PIC16:PIC16F1513-ISP +MCU_Microchip_PIC16:PIC16F1513-ISS +MCU_Microchip_PIC16:PIC16F1516-IMV +MCU_Microchip_PIC16:PIC16F1516-ISO +MCU_Microchip_PIC16:PIC16F1516-ISP +MCU_Microchip_PIC16:PIC16F1516-ISS +MCU_Microchip_PIC16:PIC16F1517-IMV +MCU_Microchip_PIC16:PIC16F1517-IP +MCU_Microchip_PIC16:PIC16F1517-IPT +MCU_Microchip_PIC16:PIC16F1518-IMV +MCU_Microchip_PIC16:PIC16F1518-ISO +MCU_Microchip_PIC16:PIC16F1518-ISP +MCU_Microchip_PIC16:PIC16F1518-ISS +MCU_Microchip_PIC16:PIC16F1519-IMV +MCU_Microchip_PIC16:PIC16F1519-IP +MCU_Microchip_PIC16:PIC16F1519-IPT +MCU_Microchip_PIC16:PIC16F1526-IMR +MCU_Microchip_PIC16:PIC16F1526-IPT +MCU_Microchip_PIC16:PIC16F1527-IMR +MCU_Microchip_PIC16:PIC16F1527-IPT +MCU_Microchip_PIC16:PIC16F15323-xSL +MCU_Microchip_PIC16:PIC16F15356-xML +MCU_Microchip_PIC16:PIC16F15356-xMV +MCU_Microchip_PIC16:PIC16F15356-xSO +MCU_Microchip_PIC16:PIC16F15356-xSP +MCU_Microchip_PIC16:PIC16F15356-xSS +MCU_Microchip_PIC16:PIC16F15375-xML +MCU_Microchip_PIC16:PIC16F15375-xMV +MCU_Microchip_PIC16:PIC16F15375-xP +MCU_Microchip_PIC16:PIC16F15375-xPT +MCU_Microchip_PIC16:PIC16F15376-xML +MCU_Microchip_PIC16:PIC16F15376-xMV +MCU_Microchip_PIC16:PIC16F15376-xP +MCU_Microchip_PIC16:PIC16F15376-xPT +MCU_Microchip_PIC16:PIC16F15385-xMV +MCU_Microchip_PIC16:PIC16F15385-xPT +MCU_Microchip_PIC16:PIC16F15386-xMV +MCU_Microchip_PIC16:PIC16F15386-xPT +MCU_Microchip_PIC16:PIC16F1619-xGZ +MCU_Microchip_PIC16:PIC16F1619-xML +MCU_Microchip_PIC16:PIC16F1619-xP +MCU_Microchip_PIC16:PIC16F1619-xSO +MCU_Microchip_PIC16:PIC16F1619-xSS +MCU_Microchip_PIC16:PIC16F1786-xML +MCU_Microchip_PIC16:PIC16F1786-xP +MCU_Microchip_PIC16:PIC16F1786-xSO +MCU_Microchip_PIC16:PIC16F1786-xSP +MCU_Microchip_PIC16:PIC16F1786-xSS +MCU_Microchip_PIC16:PIC16F1829-IML +MCU_Microchip_PIC16:PIC16F1829-IP +MCU_Microchip_PIC16:PIC16F1829-ISL +MCU_Microchip_PIC16:PIC16F1829-ISO +MCU_Microchip_PIC16:PIC16F1829-ISS +MCU_Microchip_PIC16:PIC16F1829-IST +MCU_Microchip_PIC16:PIC16F1829LIN-ESS +MCU_Microchip_PIC16:PIC16F18324-xSL +MCU_Microchip_PIC16:PIC16F18325-ISL +MCU_Microchip_PIC16:PIC16F18325-xGZ +MCU_Microchip_PIC16:PIC16F18325-xJQ +MCU_Microchip_PIC16:PIC16F18344-GZ +MCU_Microchip_PIC16:PIC16F18344-P +MCU_Microchip_PIC16:PIC16F18344-SO +MCU_Microchip_PIC16:PIC16F18344-SS +MCU_Microchip_PIC16:PIC16F18344-xSL +MCU_Microchip_PIC16:PIC16F18346-GZ +MCU_Microchip_PIC16:PIC16F18346-P +MCU_Microchip_PIC16:PIC16F18346-SO +MCU_Microchip_PIC16:PIC16F18346-SS_0 +MCU_Microchip_PIC16:PIC16F18854-xSO +MCU_Microchip_PIC16:PIC16F18855-xMV +MCU_Microchip_PIC16:PIC16F18855-xSO +MCU_Microchip_PIC16:PIC16F19195-x5LX +MCU_Microchip_PIC16:PIC16F19195-xMR +MCU_Microchip_PIC16:PIC16F19195-xPT +MCU_Microchip_PIC16:PIC16F19196-x5LX +MCU_Microchip_PIC16:PIC16F19196-xMR +MCU_Microchip_PIC16:PIC16F19196-xPT +MCU_Microchip_PIC16:PIC16F19197-x5LX +MCU_Microchip_PIC16:PIC16F19197-xMR +MCU_Microchip_PIC16:PIC16F19197-xPT +MCU_Microchip_PIC16:PIC16F1934-IML +MCU_Microchip_PIC16:PIC16F1934-IPT +MCU_Microchip_PIC16:PIC16F1937-IML +MCU_Microchip_PIC16:PIC16F1937-IPT +MCU_Microchip_PIC16:PIC16F1939-IML +MCU_Microchip_PIC16:PIC16F1939-IPT +MCU_Microchip_PIC16:PIC16F505-IMG +MCU_Microchip_PIC16:PIC16F505-IP +MCU_Microchip_PIC16:PIC16F505-ISL +MCU_Microchip_PIC16:PIC16F505-IST +MCU_Microchip_PIC16:PIC16F54-IP +MCU_Microchip_PIC16:PIC16F54-ISO +MCU_Microchip_PIC16:PIC16F54-ISS +MCU_Microchip_PIC16:PIC16F610-IML +MCU_Microchip_PIC16:PIC16F610-IP +MCU_Microchip_PIC16:PIC16F616-IML +MCU_Microchip_PIC16:PIC16F616-IP +MCU_Microchip_PIC16:PIC16F627-xxIP +MCU_Microchip_PIC16:PIC16F627-xxISO +MCU_Microchip_PIC16:PIC16F627-xxISS +MCU_Microchip_PIC16:PIC16F627A-IP +MCU_Microchip_PIC16:PIC16F627A-ISO +MCU_Microchip_PIC16:PIC16F627A-ISS +MCU_Microchip_PIC16:PIC16F628-xxIP +MCU_Microchip_PIC16:PIC16F628-xxISO +MCU_Microchip_PIC16:PIC16F628-xxISS +MCU_Microchip_PIC16:PIC16F628A-IP +MCU_Microchip_PIC16:PIC16F628A-ISO +MCU_Microchip_PIC16:PIC16F628A-ISS +MCU_Microchip_PIC16:PIC16F631-IP +MCU_Microchip_PIC16:PIC16F631-ISO +MCU_Microchip_PIC16:PIC16F631-ISS +MCU_Microchip_PIC16:PIC16F648A-IP +MCU_Microchip_PIC16:PIC16F648A-ISO +MCU_Microchip_PIC16:PIC16F648A-ISS +MCU_Microchip_PIC16:PIC16F677-IP +MCU_Microchip_PIC16:PIC16F677-ISO +MCU_Microchip_PIC16:PIC16F677-ISS +MCU_Microchip_PIC16:PIC16F684-IML +MCU_Microchip_PIC16:PIC16F684-IP +MCU_Microchip_PIC16:PIC16F685-IP +MCU_Microchip_PIC16:PIC16F685-ISO +MCU_Microchip_PIC16:PIC16F685-ISS +MCU_Microchip_PIC16:PIC16F687-IP +MCU_Microchip_PIC16:PIC16F687-ISO +MCU_Microchip_PIC16:PIC16F687-ISS +MCU_Microchip_PIC16:PIC16F689-IP +MCU_Microchip_PIC16:PIC16F689-ISO +MCU_Microchip_PIC16:PIC16F689-ISS +MCU_Microchip_PIC16:PIC16F690-IP +MCU_Microchip_PIC16:PIC16F690-ISO +MCU_Microchip_PIC16:PIC16F690-ISS +MCU_Microchip_PIC16:PIC16F716-IP +MCU_Microchip_PIC16:PIC16F716-ISO +MCU_Microchip_PIC16:PIC16F716-ISS +MCU_Microchip_PIC16:PIC16F73-IML +MCU_Microchip_PIC16:PIC16F73-ISO +MCU_Microchip_PIC16:PIC16F73-ISP +MCU_Microchip_PIC16:PIC16F73-ISS +MCU_Microchip_PIC16:PIC16F74-IP +MCU_Microchip_PIC16:PIC16F76-IML +MCU_Microchip_PIC16:PIC16F76-ISO +MCU_Microchip_PIC16:PIC16F76-ISP +MCU_Microchip_PIC16:PIC16F76-ISS +MCU_Microchip_PIC16:PIC16F77-IP +MCU_Microchip_PIC16:PIC16F818-IML +MCU_Microchip_PIC16:PIC16F818-IP +MCU_Microchip_PIC16:PIC16F818-ISO +MCU_Microchip_PIC16:PIC16F818-ISS +MCU_Microchip_PIC16:PIC16F819-IML +MCU_Microchip_PIC16:PIC16F819-IP +MCU_Microchip_PIC16:PIC16F819-ISO +MCU_Microchip_PIC16:PIC16F819-ISS +MCU_Microchip_PIC16:PIC16F83-XXP +MCU_Microchip_PIC16:PIC16F83-XXSO +MCU_Microchip_PIC16:PIC16F84-XXP +MCU_Microchip_PIC16:PIC16F84-XXSO +MCU_Microchip_PIC16:PIC16F84A-XXP +MCU_Microchip_PIC16:PIC16F84A-XXSO +MCU_Microchip_PIC16:PIC16F84A-XXSS +MCU_Microchip_PIC16:PIC16F870-ISO +MCU_Microchip_PIC16:PIC16F870-ISP +MCU_Microchip_PIC16:PIC16F870-ISS +MCU_Microchip_PIC16:PIC16F871-IL +MCU_Microchip_PIC16:PIC16F871-IP +MCU_Microchip_PIC16:PIC16F871-IPT +MCU_Microchip_PIC16:PIC16F873-XXISO +MCU_Microchip_PIC16:PIC16F873-XXISP +MCU_Microchip_PIC16:PIC16F874-XXIP +MCU_Microchip_PIC16:PIC16F874A-IP +MCU_Microchip_PIC16:PIC16F874A-IPT +MCU_Microchip_PIC16:PIC16F876-XXISO +MCU_Microchip_PIC16:PIC16F876-XXISP +MCU_Microchip_PIC16:PIC16F877-XXIP +MCU_Microchip_PIC16:PIC16F877A-IP +MCU_Microchip_PIC16:PIC16F877A-IPT +MCU_Microchip_PIC16:PIC16F88-IML +MCU_Microchip_PIC16:PIC16F88-IP +MCU_Microchip_PIC16:PIC16F882-IP +MCU_Microchip_PIC16:PIC16F883-IP +MCU_Microchip_PIC16:PIC16F884-IP +MCU_Microchip_PIC16:PIC16F886-IP +MCU_Microchip_PIC16:PIC16F887-IP +MCU_Microchip_PIC16:PIC16LF15356-xML +MCU_Microchip_PIC16:PIC16LF15356-xMV +MCU_Microchip_PIC16:PIC16LF15356-xSO +MCU_Microchip_PIC16:PIC16LF15356-xSP +MCU_Microchip_PIC16:PIC16LF15356-xSS +MCU_Microchip_PIC16:PIC16LF15375-xML +MCU_Microchip_PIC16:PIC16LF15375-xMV +MCU_Microchip_PIC16:PIC16LF15375-xP +MCU_Microchip_PIC16:PIC16LF15375-xPT +MCU_Microchip_PIC16:PIC16LF15376-xML +MCU_Microchip_PIC16:PIC16LF15376-xMV +MCU_Microchip_PIC16:PIC16LF15376-xP +MCU_Microchip_PIC16:PIC16LF15376-xPT +MCU_Microchip_PIC16:PIC16LF15385-xMV +MCU_Microchip_PIC16:PIC16LF15385-xPT +MCU_Microchip_PIC16:PIC16LF15386-xMV +MCU_Microchip_PIC16:PIC16LF15386-xPT +MCU_Microchip_PIC16:PIC16LF1786-xML +MCU_Microchip_PIC16:PIC16LF1786-xP +MCU_Microchip_PIC16:PIC16LF1786-xSO +MCU_Microchip_PIC16:PIC16LF1786-xSP +MCU_Microchip_PIC16:PIC16LF1786-xSS +MCU_Microchip_PIC16:PIC16LF18325-ISL +MCU_Microchip_PIC16:PIC16LF18325-xGZ +MCU_Microchip_PIC16:PIC16LF18325-xJQ +MCU_Microchip_PIC16:PIC16LF1904-IP +MCU_Microchip_PIC16:PIC16LF1907-IP +MCU_Microchip_PIC16:PIC16LF19195-x5LX +MCU_Microchip_PIC16:PIC16LF19195-xMR +MCU_Microchip_PIC16:PIC16LF19195-xPT +MCU_Microchip_PIC16:PIC16LF19196-x5LX +MCU_Microchip_PIC16:PIC16LF19196-xMR +MCU_Microchip_PIC16:PIC16LF19196-xPT +MCU_Microchip_PIC16:PIC16LF19197-x5LX +MCU_Microchip_PIC16:PIC16LF19197-xMR +MCU_Microchip_PIC16:PIC16LF19197-xPT +MCU_Microchip_PIC18:PIC18F1220-SO +MCU_Microchip_PIC18:PIC18F1320-SO +MCU_Microchip_PIC18:PIC18F13K50-EP +MCU_Microchip_PIC18:PIC18F13K50-ESO +MCU_Microchip_PIC18:PIC18F13K50-ESS +MCU_Microchip_PIC18:PIC18F14K50-EP +MCU_Microchip_PIC18:PIC18F14K50-ESO +MCU_Microchip_PIC18:PIC18F14K50-ESS +MCU_Microchip_PIC18:PIC18F2331-IML +MCU_Microchip_PIC18:PIC18F2331-ISO +MCU_Microchip_PIC18:PIC18F2331-ISP +MCU_Microchip_PIC18:PIC18F23K20_ISS +MCU_Microchip_PIC18:PIC18F23K22-xSO +MCU_Microchip_PIC18:PIC18F23K22-xSP +MCU_Microchip_PIC18:PIC18F2420-xML +MCU_Microchip_PIC18:PIC18F2420-xSP +MCU_Microchip_PIC18:PIC18F2431-IML +MCU_Microchip_PIC18:PIC18F2431-ISO +MCU_Microchip_PIC18:PIC18F2431-ISP +MCU_Microchip_PIC18:PIC18F2450-IML +MCU_Microchip_PIC18:PIC18F2450-ISO +MCU_Microchip_PIC18:PIC18F2450-ISP +MCU_Microchip_PIC18:PIC18F2455-ISO +MCU_Microchip_PIC18:PIC18F2455-ISP +MCU_Microchip_PIC18:PIC18F24K20_ISS +MCU_Microchip_PIC18:PIC18F24K22-xSO +MCU_Microchip_PIC18:PIC18F24K22-xSP +MCU_Microchip_PIC18:PIC18F24K50-xML +MCU_Microchip_PIC18:PIC18F24K50-xSO +MCU_Microchip_PIC18:PIC18F24K50-xSP +MCU_Microchip_PIC18:PIC18F24K50-xSS +MCU_Microchip_PIC18:PIC18F2520-xML +MCU_Microchip_PIC18:PIC18F2520-xSP +MCU_Microchip_PIC18:PIC18F2550-ISO +MCU_Microchip_PIC18:PIC18F2550-ISP +MCU_Microchip_PIC18:PIC18F25K20_ISS +MCU_Microchip_PIC18:PIC18F25K22-xSO +MCU_Microchip_PIC18:PIC18F25K22-xSP +MCU_Microchip_PIC18:PIC18F25K50-xML +MCU_Microchip_PIC18:PIC18F25K50-xSO +MCU_Microchip_PIC18:PIC18F25K50-xSP +MCU_Microchip_PIC18:PIC18F25K50-xSS +MCU_Microchip_PIC18:PIC18F25K80_IML +MCU_Microchip_PIC18:PIC18F25K80_ISS +MCU_Microchip_PIC18:PIC18F25K83-xSP +MCU_Microchip_PIC18:PIC18F26K20_ISS +MCU_Microchip_PIC18:PIC18F26K22-xSO +MCU_Microchip_PIC18:PIC18F26K22-xSP +MCU_Microchip_PIC18:PIC18F26K80_IML +MCU_Microchip_PIC18:PIC18F26K80_ISS +MCU_Microchip_PIC18:PIC18F26K83-xSP +MCU_Microchip_PIC18:PIC18F27J53_ISS +MCU_Microchip_PIC18:PIC18F4331-IML +MCU_Microchip_PIC18:PIC18F4331-IP +MCU_Microchip_PIC18:PIC18F4331-IPT +MCU_Microchip_PIC18:PIC18F442-IP +MCU_Microchip_PIC18:PIC18F442-IPT +MCU_Microchip_PIC18:PIC18F4420-xP +MCU_Microchip_PIC18:PIC18F4431-IML +MCU_Microchip_PIC18:PIC18F4431-IP +MCU_Microchip_PIC18:PIC18F4431-IPT +MCU_Microchip_PIC18:PIC18F4450-IML +MCU_Microchip_PIC18:PIC18F4450-IP +MCU_Microchip_PIC18:PIC18F4450-IPT +MCU_Microchip_PIC18:PIC18F4455-IML +MCU_Microchip_PIC18:PIC18F4455-IP +MCU_Microchip_PIC18:PIC18F4455-IPT +MCU_Microchip_PIC18:PIC18F4458-IML +MCU_Microchip_PIC18:PIC18F4458-IP +MCU_Microchip_PIC18:PIC18F4458-IPT +MCU_Microchip_PIC18:PIC18F448-IP +MCU_Microchip_PIC18:PIC18F4480-IP +MCU_Microchip_PIC18:PIC18F44J10-IP +MCU_Microchip_PIC18:PIC18F452-IP +MCU_Microchip_PIC18:PIC18F452-IPT +MCU_Microchip_PIC18:PIC18F4520-xP +MCU_Microchip_PIC18:PIC18F4550-IML +MCU_Microchip_PIC18:PIC18F4550-IP +MCU_Microchip_PIC18:PIC18F4550-IPT +MCU_Microchip_PIC18:PIC18F4553-IML +MCU_Microchip_PIC18:PIC18F4553-IP +MCU_Microchip_PIC18:PIC18F4553-IPT +MCU_Microchip_PIC18:PIC18F458-IP +MCU_Microchip_PIC18:PIC18F4580-IP +MCU_Microchip_PIC18:PIC18F45J10-IP +MCU_Microchip_PIC18:PIC18F45K50_QFP +MCU_Microchip_PIC18:PIC18F45K80-IML +MCU_Microchip_PIC18:PIC18F45K80-IPT +MCU_Microchip_PIC18:PIC18F46K22-xPT +MCU_Microchip_PIC18:PIC18F46K80-IML +MCU_Microchip_PIC18:PIC18F46K80-IPT +MCU_Microchip_PIC18:PIC18F66J60-IPT +MCU_Microchip_PIC18:PIC18F66J65-IPT +MCU_Microchip_PIC18:PIC18F67J60-IPT +MCU_Microchip_PIC18:PIC18F87K22-xPT +MCU_Microchip_PIC18:PIC18F96J60-IPF +MCU_Microchip_PIC18:PIC18F96J60-IPT +MCU_Microchip_PIC18:PIC18F96J65-IPF +MCU_Microchip_PIC18:PIC18F96J65-IPT +MCU_Microchip_PIC18:PIC18F97J60-IPF +MCU_Microchip_PIC18:PIC18F97J60-IPT +MCU_Microchip_PIC18:PIC18LF1220-SO +MCU_Microchip_PIC18:PIC18LF1320-SO +MCU_Microchip_PIC18:PIC18LF13K50-EP +MCU_Microchip_PIC18:PIC18LF13K50-ESO +MCU_Microchip_PIC18:PIC18LF13K50-ESS +MCU_Microchip_PIC18:PIC18LF14K50-EP +MCU_Microchip_PIC18:PIC18LF14K50-ESO +MCU_Microchip_PIC18:PIC18LF14K50-ESS +MCU_Microchip_PIC18:PIC18LF2331-IML +MCU_Microchip_PIC18:PIC18LF2331-ISO +MCU_Microchip_PIC18:PIC18LF2331-ISP +MCU_Microchip_PIC18:PIC18LF2431-IML +MCU_Microchip_PIC18:PIC18LF2431-ISO +MCU_Microchip_PIC18:PIC18LF2431-ISP +MCU_Microchip_PIC18:PIC18LF2450-IML +MCU_Microchip_PIC18:PIC18LF2450-ISO +MCU_Microchip_PIC18:PIC18LF2450-ISP +MCU_Microchip_PIC18:PIC18LF2455-ISO +MCU_Microchip_PIC18:PIC18LF2455-ISP +MCU_Microchip_PIC18:PIC18LF24K50-xML +MCU_Microchip_PIC18:PIC18LF24K50-xSO +MCU_Microchip_PIC18:PIC18LF24K50-xSP +MCU_Microchip_PIC18:PIC18LF24K50-xSS +MCU_Microchip_PIC18:PIC18LF2550-ISO +MCU_Microchip_PIC18:PIC18LF2550-ISP +MCU_Microchip_PIC18:PIC18LF25K50-xML +MCU_Microchip_PIC18:PIC18LF25K50-xSO +MCU_Microchip_PIC18:PIC18LF25K50-xSP +MCU_Microchip_PIC18:PIC18LF25K50-xSS +MCU_Microchip_PIC18:PIC18LF25K80_IML +MCU_Microchip_PIC18:PIC18LF25K80_ISS +MCU_Microchip_PIC18:PIC18LF25K83-xSP +MCU_Microchip_PIC18:PIC18LF26K80_IML +MCU_Microchip_PIC18:PIC18LF26K80_ISS +MCU_Microchip_PIC18:PIC18LF26K83-xSP +MCU_Microchip_PIC18:PIC18LF4331-IML +MCU_Microchip_PIC18:PIC18LF4331-IP +MCU_Microchip_PIC18:PIC18LF4331-IPT +MCU_Microchip_PIC18:PIC18LF442-IP +MCU_Microchip_PIC18:PIC18LF442-IPT +MCU_Microchip_PIC18:PIC18LF4431-IML +MCU_Microchip_PIC18:PIC18LF4431-IP +MCU_Microchip_PIC18:PIC18LF4431-IPT +MCU_Microchip_PIC18:PIC18LF4450-IML +MCU_Microchip_PIC18:PIC18LF4450-IP +MCU_Microchip_PIC18:PIC18LF4450-IPT +MCU_Microchip_PIC18:PIC18LF4455-IML +MCU_Microchip_PIC18:PIC18LF4455-IP +MCU_Microchip_PIC18:PIC18LF4455-IPT +MCU_Microchip_PIC18:PIC18LF4458-IML +MCU_Microchip_PIC18:PIC18LF4458-IP +MCU_Microchip_PIC18:PIC18LF4458-IPT +MCU_Microchip_PIC18:PIC18LF448-IP +MCU_Microchip_PIC18:PIC18LF4480-IP +MCU_Microchip_PIC18:PIC18LF44J10-IP +MCU_Microchip_PIC18:PIC18LF452-IP +MCU_Microchip_PIC18:PIC18LF452-IPT +MCU_Microchip_PIC18:PIC18LF4550-IML +MCU_Microchip_PIC18:PIC18LF4550-IP +MCU_Microchip_PIC18:PIC18LF4550-IPT +MCU_Microchip_PIC18:PIC18LF4553-IML +MCU_Microchip_PIC18:PIC18LF4553-IP +MCU_Microchip_PIC18:PIC18LF4553-IPT +MCU_Microchip_PIC18:PIC18LF458-IP +MCU_Microchip_PIC18:PIC18LF4580-IP +MCU_Microchip_PIC18:PIC18LF45J10-IP +MCU_Microchip_PIC18:PIC18LF45K50_QFP +MCU_Microchip_PIC18:PIC18LF45K80-IML +MCU_Microchip_PIC18:PIC18LF45K80-IPT +MCU_Microchip_PIC18:PIC18LF46K80-IML +MCU_Microchip_PIC18:PIC18LF46K80-IPT +MCU_Microchip_PIC24:PIC24FJ128GA306-xMR +MCU_Microchip_PIC24:PIC24FJ128GA306-xPT +MCU_Microchip_PIC24:PIC24FJ256DA210-xBG +MCU_Microchip_PIC24:PIC24FJ256DA210-xPT +MCU_Microchip_PIC24:PIC24FJ64GA306-xMR +MCU_Microchip_PIC24:PIC24FJ64GA306-xPT +MCU_Microchip_PIC24:PIC24FV32KA304-IPT +MCU_Microchip_PIC32:PIC32MK1024GPD100-xPT +MCU_Microchip_PIC32:PIC32MK1024GPE100-xPT +MCU_Microchip_PIC32:PIC32MM0064GPL028x-ML +MCU_Microchip_PIC32:PIC32MX110F016D-IPT +MCU_Microchip_PIC32:PIC32MX120F032D-IPT +MCU_Microchip_PIC32:PIC32MX130F064D-IPT +MCU_Microchip_PIC32:PIC32MX150F128D-IPT +MCU_Microchip_PIC32:PIC32MX170F256D-IPT +MCU_Microchip_PIC32:PIC32MX210F016D-IPT +MCU_Microchip_PIC32:PIC32MX220F032D-IPT +MCU_Microchip_PIC32:PIC32MX230F064D-IPT +MCU_Microchip_PIC32:PIC32MX250F128D-IPT +MCU_Microchip_PIC32:PIC32MX270F256D-IPT +MCU_Microchip_PIC32:PIC32MX575F256H +MCU_Microchip_PIC32:PIC32MX575F512H +MCU_Microchip_PIC32:PIC32MX795F512L-80x-PF +MCU_Microchip_PIC32:PIC32MX795F512L-80x-PT +MCU_Microchip_SAMA:ATSAMA5D21 +MCU_Microchip_SAMD:ATSAMD09C13A-SS +MCU_Microchip_SAMD:ATSAMD09D14A-M +MCU_Microchip_SAMD:ATSAMD10C13A-SS +MCU_Microchip_SAMD:ATSAMD10C14A-SS +MCU_Microchip_SAMD:ATSAMD10D13A-M +MCU_Microchip_SAMD:ATSAMD10D13A-SS +MCU_Microchip_SAMD:ATSAMD10D14A-M +MCU_Microchip_SAMD:ATSAMD10D14A-SS +MCU_Microchip_SAMD:ATSAMD10D14A-U +MCU_Microchip_SAMD:ATSAMD11C14A-SS +MCU_Microchip_SAMD:ATSAMD11D14A-M +MCU_Microchip_SAMD:ATSAMD11D14A-SS +MCU_Microchip_SAMD:ATSAMD11D14A-U +MCU_Microchip_SAMD:ATSAMD21E15A-A +MCU_Microchip_SAMD:ATSAMD21E15A-M +MCU_Microchip_SAMD:ATSAMD21E15B-A +MCU_Microchip_SAMD:ATSAMD21E15B-M +MCU_Microchip_SAMD:ATSAMD21E15L-A +MCU_Microchip_SAMD:ATSAMD21E15L-M +MCU_Microchip_SAMD:ATSAMD21E16A-A +MCU_Microchip_SAMD:ATSAMD21E16A-M +MCU_Microchip_SAMD:ATSAMD21E16B-A +MCU_Microchip_SAMD:ATSAMD21E16B-M +MCU_Microchip_SAMD:ATSAMD21E16L-A +MCU_Microchip_SAMD:ATSAMD21E16L-M +MCU_Microchip_SAMD:ATSAMD21E17A-A +MCU_Microchip_SAMD:ATSAMD21E17A-M +MCU_Microchip_SAMD:ATSAMD21E17D-A +MCU_Microchip_SAMD:ATSAMD21E17D-M +MCU_Microchip_SAMD:ATSAMD21E17L-A +MCU_Microchip_SAMD:ATSAMD21E17L-M +MCU_Microchip_SAMD:ATSAMD21E18A-A +MCU_Microchip_SAMD:ATSAMD21E18A-M +MCU_Microchip_SAMD:ATSAMD21G15A-A +MCU_Microchip_SAMD:ATSAMD21G15A-M +MCU_Microchip_SAMD:ATSAMD21G15B-A +MCU_Microchip_SAMD:ATSAMD21G15B-M +MCU_Microchip_SAMD:ATSAMD21G16A-A +MCU_Microchip_SAMD:ATSAMD21G16A-M +MCU_Microchip_SAMD:ATSAMD21G16B-A +MCU_Microchip_SAMD:ATSAMD21G16B-M +MCU_Microchip_SAMD:ATSAMD21G16L-M +MCU_Microchip_SAMD:ATSAMD21G17A-A +MCU_Microchip_SAMD:ATSAMD21G17A-M +MCU_Microchip_SAMD:ATSAMD21G17D-A +MCU_Microchip_SAMD:ATSAMD21G17D-M +MCU_Microchip_SAMD:ATSAMD21G17L-M +MCU_Microchip_SAMD:ATSAMD21G18A-A +MCU_Microchip_SAMD:ATSAMD21G18A-M +MCU_Microchip_SAMD:ATSAMD21J15A-A +MCU_Microchip_SAMD:ATSAMD21J15A-M +MCU_Microchip_SAMD:ATSAMD21J15B-A +MCU_Microchip_SAMD:ATSAMD21J15B-C +MCU_Microchip_SAMD:ATSAMD21J15B-M +MCU_Microchip_SAMD:ATSAMD21J16A-A +MCU_Microchip_SAMD:ATSAMD21J16A-M +MCU_Microchip_SAMD:ATSAMD21J16B-A +MCU_Microchip_SAMD:ATSAMD21J16B-C +MCU_Microchip_SAMD:ATSAMD21J16B-M +MCU_Microchip_SAMD:ATSAMD21J17A-A +MCU_Microchip_SAMD:ATSAMD21J17A-M +MCU_Microchip_SAMD:ATSAMD21J17D-A +MCU_Microchip_SAMD:ATSAMD21J17D-C +MCU_Microchip_SAMD:ATSAMD21J17D-M +MCU_Microchip_SAMD:ATSAMD21J18A-A +MCU_Microchip_SAMD:ATSAMD21J18A-M +MCU_Microchip_SAMD:ATSAMD51J18A-A +MCU_Microchip_SAMD:ATSAMD51J18A-M +MCU_Microchip_SAMD:ATSAMD51J19A-A +MCU_Microchip_SAMD:ATSAMD51J19A-M +MCU_Microchip_SAMD:ATSAMD51J20A-A +MCU_Microchip_SAMD:ATSAMD51J20A-M +MCU_Microchip_SAMD:ATSAMDA1E14B-A +MCU_Microchip_SAMD:ATSAMDA1E14B-M +MCU_Microchip_SAMD:ATSAMDA1E15B-A +MCU_Microchip_SAMD:ATSAMDA1E15B-M +MCU_Microchip_SAMD:ATSAMDA1E16B-A +MCU_Microchip_SAMD:ATSAMDA1E16B-M +MCU_Microchip_SAMD:ATSAMDA1G14B-A +MCU_Microchip_SAMD:ATSAMDA1G14B-M +MCU_Microchip_SAMD:ATSAMDA1G15B-A +MCU_Microchip_SAMD:ATSAMDA1G15B-M +MCU_Microchip_SAMD:ATSAMDA1G16B-A +MCU_Microchip_SAMD:ATSAMDA1G16B-M +MCU_Microchip_SAMD:ATSAMDA1J14B-A +MCU_Microchip_SAMD:ATSAMDA1J15B-A +MCU_Microchip_SAMD:ATSAMDA1J16B-A +MCU_Microchip_SAME:ATSAME51J18A-A +MCU_Microchip_SAME:ATSAME51J19A-A +MCU_Microchip_SAME:ATSAME51J20A-A +MCU_Microchip_SAME:ATSAME53J18A-M +MCU_Microchip_SAME:ATSAME53J19A-M +MCU_Microchip_SAME:ATSAME53J20A-M +MCU_Microchip_SAME:ATSAME54N19A-A +MCU_Microchip_SAME:ATSAME70J19A-AN +MCU_Microchip_SAME:ATSAME70J20A-AN +MCU_Microchip_SAME:ATSAME70J21A-AN +MCU_Microchip_SAME:ATSAME70N19A-AN +MCU_Microchip_SAME:ATSAME70N20A-AN +MCU_Microchip_SAME:ATSAME70N21A-AN +MCU_Microchip_SAME:ATSAME70Q19A-AN +MCU_Microchip_SAME:ATSAME70Q20A-AN +MCU_Microchip_SAME:ATSAME70Q21A-AN +MCU_Microchip_SAML:ATSAML21E15B-AUT +MCU_Microchip_SAML:ATSAML21E15B-MUT +MCU_Microchip_SAML:ATSAML21E16B-AUT +MCU_Microchip_SAML:ATSAML21E16B-MUT +MCU_Microchip_SAML:ATSAML21E17B-AUT +MCU_Microchip_SAML:ATSAML21E17B-MUT +MCU_Microchip_SAML:ATSAML21E18B-AUT +MCU_Microchip_SAML:ATSAML21E18B-MUT +MCU_Microchip_SAML:ATSAML21G16B-AUT +MCU_Microchip_SAML:ATSAML21G16B-MUT +MCU_Microchip_SAML:ATSAML21G17B-AUT +MCU_Microchip_SAML:ATSAML21G17B-MUT +MCU_Microchip_SAML:ATSAML21G18B-AUT +MCU_Microchip_SAML:ATSAML21G18B-MUT +MCU_Microchip_SAML:ATSAML21J16B-AUT +MCU_Microchip_SAML:ATSAML21J16B-MUT +MCU_Microchip_SAML:ATSAML21J17B-AUT +MCU_Microchip_SAML:ATSAML21J17B-MUT +MCU_Microchip_SAML:ATSAML21J18B-AUT +MCU_Microchip_SAML:ATSAML21J18B-MUT +MCU_Microchip_SAMV:ATSAMV71Q19B-A +MCU_Microchip_SAMV:ATSAMV71Q20B-A +MCU_Microchip_SAMV:ATSAMV71Q21B-A +MCU_Module:Adafruit_Feather_32u4_BluefruitLE +MCU_Module:Adafruit_Feather_Generic +MCU_Module:Adafruit_Feather_HUZZAH32_ESP32 +MCU_Module:Adafruit_Feather_HUZZAH_ESP8266 +MCU_Module:Adafruit_Feather_M0_Adalogger +MCU_Module:Adafruit_Feather_M0_Basic_Proto +MCU_Module:Adafruit_Feather_M0_BluefruitLE +MCU_Module:Adafruit_Feather_M0_Express +MCU_Module:Adafruit_Feather_M0_RFM69HCW_Packet_Radio +MCU_Module:Adafruit_Feather_M0_RFM9x_LoRa_Radio +MCU_Module:Adafruit_Feather_M0_Wifi +MCU_Module:Adafruit_Feather_WICED_Wifi +MCU_Module:Adafruit_HUZZAH_ESP8266_breakout +MCU_Module:Arduino_Leonardo +MCU_Module:Arduino_Nano_ESP32 +MCU_Module:Arduino_Nano_Every +MCU_Module:Arduino_Nano_RP2040_Connect +MCU_Module:Arduino_Nano_v2.x +MCU_Module:Arduino_Nano_v3.x +MCU_Module:Arduino_UNO_R2 +MCU_Module:Arduino_UNO_R3 +MCU_Module:CHIP +MCU_Module:CHIP-PRO +MCU_Module:Carambola2 +MCU_Module:Electrosmith_Daisy_Seed_Rev4 +MCU_Module:Google_Coral +MCU_Module:Maple_Mini +MCU_Module:NUCLEO144-F207ZG +MCU_Module:NUCLEO144-F412ZG +MCU_Module:NUCLEO144-F413ZH +MCU_Module:NUCLEO144-F429ZI +MCU_Module:NUCLEO144-F439ZI +MCU_Module:NUCLEO144-F446ZE +MCU_Module:NUCLEO144-F722ZE +MCU_Module:NUCLEO144-F746ZG +MCU_Module:NUCLEO144-F756ZG +MCU_Module:NUCLEO144-F767ZI +MCU_Module:NUCLEO144-H743ZI +MCU_Module:NUCLEO64-F411RE +MCU_Module:OPOS6UL +MCU_Module:OPOS6UL_NANO +MCU_Module:Olimex_MOD-WIFI-ESP8266-DEV +MCU_Module:Omega2+ +MCU_Module:Omega2S +MCU_Module:Omega2S+ +MCU_Module:PocketBeagle +MCU_Module:RaspberryPi-CM1 +MCU_Module:RaspberryPi-CM3 +MCU_Module:RaspberryPi-CM3+ +MCU_Module:RaspberryPi-CM3+L +MCU_Module:RaspberryPi-CM3-L +MCU_Module:RaspberryPi_Pico +MCU_Module:RaspberryPi_Pico_Debug +MCU_Module:RaspberryPi_Pico_Extensive +MCU_Module:RaspberryPi_Pico_W +MCU_Module:RaspberryPi_Pico_W_Debug +MCU_Module:RaspberryPi_Pico_W_Extensive +MCU_Module:Sipeed-M1 +MCU_Module:Sipeed-M1W +MCU_Module:VisionSOM-6UL +MCU_Module:VisionSOM-6ULL +MCU_Module:VisionSOM-RT +MCU_Module:VisionSOM-STM32MP1 +MCU_Nordic:nRF51x22-QFxx +MCU_Nordic:nRF52810-QCxx +MCU_Nordic:nRF52810-QFxx +MCU_Nordic:nRF52811-QCxx +MCU_Nordic:nRF52820-QDxx +MCU_Nordic:nRF52832-QFxx +MCU_Nordic:nRF52833_QDxx +MCU_Nordic:nRF52833_QIxx +MCU_Nordic:nRF52840 +MCU_Nordic:nRF5340-QKxx +MCU_Nordic:nRF9160-SIxA +MCU_NXP_ColdFire:MCF5211CAE66 +MCU_NXP_ColdFire:MCF5212CAE66 +MCU_NXP_ColdFire:MCF5213-LQFP100 +MCU_NXP_ColdFire:MCF5282 +MCU_NXP_ColdFire:MCF5328-BGA256 +MCU_NXP_ColdFire:MCF5407 +MCU_NXP_HC11:68HC11 +MCU_NXP_HC11:68HC11A8 +MCU_NXP_HC11:68HC11F1 +MCU_NXP_HC11:68HC11_PLCC +MCU_NXP_HC11:68HC711_PLCC +MCU_NXP_HC11:MC68HC11A0CC +MCU_NXP_HC11:MC68HC11A1CC +MCU_NXP_HC11:MC68HC11A7CC +MCU_NXP_HC11:MC68HC11A8CC +MCU_NXP_HC11:MC68HC11F1CC +MCU_NXP_HC12:MC68HC812A4 +MCU_NXP_HC12:MC68HC912 +MCU_NXP_HCS12:MC9S12DT256 +MCU_NXP_Kinetis:MK20DN128VFM5 +MCU_NXP_Kinetis:MK20DN32VFM5 +MCU_NXP_Kinetis:MK20DN64VFM5 +MCU_NXP_Kinetis:MK20DX128VFM5 +MCU_NXP_Kinetis:MK20DX32VFM5 +MCU_NXP_Kinetis:MK20DX64VFM5 +MCU_NXP_Kinetis:MK20FN1M0VMD12 +MCU_NXP_Kinetis:MK20FX512VMD12 +MCU_NXP_Kinetis:MK26FN2M0VMD18 +MCU_NXP_Kinetis:MKE02Z16VLC4 +MCU_NXP_Kinetis:MKE02Z16VLD4 +MCU_NXP_Kinetis:MKE02Z32VLC4 +MCU_NXP_Kinetis:MKE02Z32VLD4 +MCU_NXP_Kinetis:MKE02Z32VLH4 +MCU_NXP_Kinetis:MKE02Z32VQH4 +MCU_NXP_Kinetis:MKE02Z64VLC4 +MCU_NXP_Kinetis:MKE02Z64VLD4 +MCU_NXP_Kinetis:MKE02Z64VLH4 +MCU_NXP_Kinetis:MKE02Z64VQH4 +MCU_NXP_Kinetis:MKE16Z64VLF4 +MCU_NXP_Kinetis:MKL02Z16VFG4 +MCU_NXP_Kinetis:MKL02Z16VFK4 +MCU_NXP_Kinetis:MKL02Z16VFM4 +MCU_NXP_Kinetis:MKL02Z32CAF4 +MCU_NXP_Kinetis:MKL02Z32VFG4 +MCU_NXP_Kinetis:MKL02Z32VFK4 +MCU_NXP_Kinetis:MKL02Z32VFM4 +MCU_NXP_Kinetis:MKL02Z8VFG4 +MCU_NXP_Kinetis:MKL03Z16VFG4 +MCU_NXP_Kinetis:MKL03Z16VFK4 +MCU_NXP_Kinetis:MKL03Z32CAF4 +MCU_NXP_Kinetis:MKL03Z32CBF4 +MCU_NXP_Kinetis:MKL03Z32VFG4 +MCU_NXP_Kinetis:MKL03Z32VFK4 +MCU_NXP_Kinetis:MKL03Z8VFG4 +MCU_NXP_Kinetis:MKL03Z8VFK4 +MCU_NXP_Kinetis:MKL04Z16VFK4 +MCU_NXP_Kinetis:MKL04Z16VFM4 +MCU_NXP_Kinetis:MKL04Z16VLC4 +MCU_NXP_Kinetis:MKL04Z16VLF4 +MCU_NXP_Kinetis:MKL04Z32VFK4 +MCU_NXP_Kinetis:MKL04Z32VFM4 +MCU_NXP_Kinetis:MKL04Z32VLC4 +MCU_NXP_Kinetis:MKL04Z32VLF4 +MCU_NXP_Kinetis:MKL04Z8VFK4 +MCU_NXP_Kinetis:MKL04Z8VFM4 +MCU_NXP_Kinetis:MKL04Z8VLC4 +MCU_NXP_Kinetis:MKL05Z16VFK4 +MCU_NXP_Kinetis:MKL05Z16VFM4 +MCU_NXP_Kinetis:MKL05Z16VLC4 +MCU_NXP_Kinetis:MKL05Z16VLF4 +MCU_NXP_Kinetis:MKL05Z32VFK4 +MCU_NXP_Kinetis:MKL05Z32VFM4 +MCU_NXP_Kinetis:MKL05Z32VLC4 +MCU_NXP_Kinetis:MKL05Z32VLF4 +MCU_NXP_Kinetis:MKL05Z8VFK4 +MCU_NXP_Kinetis:MKL05Z8VFM4 +MCU_NXP_Kinetis:MKL05Z8VLC4 +MCU_NXP_Kinetis:MKL16Z128VFM4 +MCU_NXP_Kinetis:MKL16Z128VFT4 +MCU_NXP_Kinetis:MKL16Z128VLH4 +MCU_NXP_Kinetis:MKL16Z256VLH4 +MCU_NXP_Kinetis:MKL16Z256VMP4 +MCU_NXP_Kinetis:MKL16Z32VFM4 +MCU_NXP_Kinetis:MKL16Z32VFT4 +MCU_NXP_Kinetis:MKL16Z32VLH4 +MCU_NXP_Kinetis:MKL16Z64VFM4 +MCU_NXP_Kinetis:MKL16Z64VFT4 +MCU_NXP_Kinetis:MKL16Z64VLH4 +MCU_NXP_Kinetis:MKL17Z128VFM4 +MCU_NXP_Kinetis:MKL17Z128VFT4 +MCU_NXP_Kinetis:MKL17Z128VLH4 +MCU_NXP_Kinetis:MKL17Z128VMP4 +MCU_NXP_Kinetis:MKL17Z256CAL4 +MCU_NXP_Kinetis:MKL17Z256VFM4 +MCU_NXP_Kinetis:MKL17Z256VFT4 +MCU_NXP_Kinetis:MKL17Z256VLH4 +MCU_NXP_Kinetis:MKL17Z256VMP4 +MCU_NXP_Kinetis:MKL17Z32VDA4 +MCU_NXP_Kinetis:MKL17Z32VFM4 +MCU_NXP_Kinetis:MKL17Z32VFT4 +MCU_NXP_Kinetis:MKL17Z32VLH4 +MCU_NXP_Kinetis:MKL17Z32VMP4 +MCU_NXP_Kinetis:MKL17Z64VDA4 +MCU_NXP_Kinetis:MKL17Z64VFM4 +MCU_NXP_Kinetis:MKL17Z64VFT4 +MCU_NXP_Kinetis:MKL17Z64VLH4 +MCU_NXP_Kinetis:MKL17Z64VMP4 +MCU_NXP_Kinetis:MKL24Z32VFM4 +MCU_NXP_Kinetis:MKL24Z32VFT4 +MCU_NXP_Kinetis:MKL24Z32VLH4 +MCU_NXP_Kinetis:MKL24Z32VLK4 +MCU_NXP_Kinetis:MKL24Z64VFM4 +MCU_NXP_Kinetis:MKL24Z64VFT4 +MCU_NXP_Kinetis:MKL24Z64VLH4 +MCU_NXP_Kinetis:MKL24Z64VLK4 +MCU_NXP_Kinetis:MKL25Z128VFM4 +MCU_NXP_Kinetis:MKL25Z128VFT4 +MCU_NXP_Kinetis:MKL25Z128VLH4 +MCU_NXP_Kinetis:MKL25Z128VLK4 +MCU_NXP_Kinetis:MKL25Z32VFM4 +MCU_NXP_Kinetis:MKL25Z32VFT4 +MCU_NXP_Kinetis:MKL25Z32VLH4 +MCU_NXP_Kinetis:MKL25Z32VLK4 +MCU_NXP_Kinetis:MKL25Z64VFM4 +MCU_NXP_Kinetis:MKL25Z64VFT4 +MCU_NXP_Kinetis:MKL25Z64VLH4 +MCU_NXP_Kinetis:MKL25Z64VLK4 +MCU_NXP_Kinetis:MKL26Z128CAL4 +MCU_NXP_Kinetis:MKL26Z128VFM4 +MCU_NXP_Kinetis:MKL26Z128VFT4 +MCU_NXP_Kinetis:MKL26Z128VLH4 +MCU_NXP_Kinetis:MKL26Z128VLL4 +MCU_NXP_Kinetis:MKL26Z128VMC4 +MCU_NXP_Kinetis:MKL26Z256VLH4 +MCU_NXP_Kinetis:MKL26Z256VLL4 +MCU_NXP_Kinetis:MKL26Z256VMC4 +MCU_NXP_Kinetis:MKL26Z256VMP4 +MCU_NXP_Kinetis:MKL26Z32VFM4 +MCU_NXP_Kinetis:MKL26Z32VFT4 +MCU_NXP_Kinetis:MKL26Z32VLH4 +MCU_NXP_Kinetis:MKL26Z64VFM4 +MCU_NXP_Kinetis:MKL26Z64VFT4 +MCU_NXP_Kinetis:MKL26Z64VLH4 +MCU_NXP_Kinetis:MKL27Z128VFT4 +MCU_NXP_Kinetis:MKL27Z128VLH4 +MCU_NXP_Kinetis:MKL27Z256VFT4 +MCU_NXP_Kinetis:MKL27Z256VLH4 +MCU_NXP_Kinetis:MKL27Z32VFM4 +MCU_NXP_Kinetis:MKL27Z32VFT4 +MCU_NXP_Kinetis:MKL27Z32VLH4 +MCU_NXP_Kinetis:MKL27Z64VFM4 +MCU_NXP_Kinetis:MKL27Z64VFT4 +MCU_NXP_Kinetis:MKL27Z64VLH4 +MCU_NXP_Kinetis:MKL28Z512VDC7 +MCU_NXP_Kinetis:MKL28Z512VLL7 +MCU_NXP_Kinetis:MKL43Z128VLH4 +MCU_NXP_Kinetis:MKL43Z128VMP4 +MCU_NXP_Kinetis:MKL43Z256VLH4 +MCU_NXP_Kinetis:MKL43Z256VMP4 +MCU_NXP_Kinetis:MKL46Z128VLH4 +MCU_NXP_Kinetis:MKL46Z128VLL4 +MCU_NXP_Kinetis:MKL46Z128VMC4 +MCU_NXP_Kinetis:MKL46Z256VLH4 +MCU_NXP_Kinetis:MKL46Z256VLL4 +MCU_NXP_Kinetis:MKL46Z256VMC4 +MCU_NXP_Kinetis:MKL46Z256VMP4 +MCU_NXP_Kinetis:MKV11Z128VLF7 +MCU_NXP_Kinetis:MKV11Z128VLH7 +MCU_NXP_Kinetis:MKW21Z256VHT +MCU_NXP_Kinetis:MKW21Z512VHT +MCU_NXP_Kinetis:MKW31Z256VHT +MCU_NXP_Kinetis:MKW31Z512VHT +MCU_NXP_Kinetis:MKW41Z256VHT +MCU_NXP_Kinetis:MKW41Z512VHT +MCU_NXP_LPC:LPC1102UK +MCU_NXP_LPC:LPC1104UK +MCU_NXP_LPC:LPC1111FHN33-101 +MCU_NXP_LPC:LPC1111FHN33-102 +MCU_NXP_LPC:LPC1111FHN33-103 +MCU_NXP_LPC:LPC1111FHN33-201 +MCU_NXP_LPC:LPC1111FHN33-202 +MCU_NXP_LPC:LPC1111FHN33-203 +MCU_NXP_LPC:LPC1111JHN33-103 +MCU_NXP_LPC:LPC1111JHN33-203 +MCU_NXP_LPC:LPC1112FHI33-102 +MCU_NXP_LPC:LPC1112FHI33-202 +MCU_NXP_LPC:LPC1112FHI33-203 +MCU_NXP_LPC:LPC1112FHN33-101 +MCU_NXP_LPC:LPC1112FHN33-102 +MCU_NXP_LPC:LPC1112FHN33-103 +MCU_NXP_LPC:LPC1112FHN33-201 +MCU_NXP_LPC:LPC1112FHN33-202 +MCU_NXP_LPC:LPC1112FHN33-203 +MCU_NXP_LPC:LPC1112JHI33-203 +MCU_NXP_LPC:LPC1112JHN33-103 +MCU_NXP_LPC:LPC1112JHN33-203 +MCU_NXP_LPC:LPC1113FBD48-301 +MCU_NXP_LPC:LPC1113FBD48-302 +MCU_NXP_LPC:LPC1113FBD48-303 +MCU_NXP_LPC:LPC1113FHN33-201 +MCU_NXP_LPC:LPC1113FHN33-202 +MCU_NXP_LPC:LPC1113FHN33-203 +MCU_NXP_LPC:LPC1113FHN33-301 +MCU_NXP_LPC:LPC1113FHN33-302 +MCU_NXP_LPC:LPC1113FHN33-303 +MCU_NXP_LPC:LPC1113JBD48-303 +MCU_NXP_LPC:LPC1113JHN33-203 +MCU_NXP_LPC:LPC1113JHN33-303 +MCU_NXP_LPC:LPC1114FBD48-301 +MCU_NXP_LPC:LPC1114FBD48-302 +MCU_NXP_LPC:LPC1114FBD48-303 +MCU_NXP_LPC:LPC1114FBD48-323 +MCU_NXP_LPC:LPC1114FBD48-333 +MCU_NXP_LPC:LPC1114FHI33-302 +MCU_NXP_LPC:LPC1114FHI33-303 +MCU_NXP_LPC:LPC1114FHN33-201 +MCU_NXP_LPC:LPC1114FHN33-202 +MCU_NXP_LPC:LPC1114FHN33-203 +MCU_NXP_LPC:LPC1114FHN33-301 +MCU_NXP_LPC:LPC1114FHN33-302 +MCU_NXP_LPC:LPC1114FHN33-303 +MCU_NXP_LPC:LPC1114FHN33-333 +MCU_NXP_LPC:LPC1114JBD48-303 +MCU_NXP_LPC:LPC1114JBD48-323 +MCU_NXP_LPC:LPC1114JBD48-333 +MCU_NXP_LPC:LPC1114JHI33-303 +MCU_NXP_LPC:LPC1114JHN33-203 +MCU_NXP_LPC:LPC1115FBD48-303 +MCU_NXP_LPC:LPC1115JBD48-303 +MCU_NXP_LPC:LPC11E12FBD48-201 +MCU_NXP_LPC:LPC11E13FBD48-301 +MCU_NXP_LPC:LPC11E14FBD48-401 +MCU_NXP_LPC:LPC11U12FBD48-201 +MCU_NXP_LPC:LPC11U13FBD48-201 +MCU_NXP_LPC:LPC11U14FBD48-201 +MCU_NXP_LPC:LPC11U22FBD48-301 +MCU_NXP_LPC:LPC11U23FBD48-301 +MCU_NXP_LPC:LPC11U24FBD48-301 +MCU_NXP_LPC:LPC11U24FBD48-401 +MCU_NXP_LPC:LPC11U34FBD48-311 +MCU_NXP_LPC:LPC11U34FBD48-421 +MCU_NXP_LPC:LPC11U35FBD48-401 +MCU_NXP_LPC:LPC11U36FBD48-401 +MCU_NXP_LPC:LPC11U37FBD48-401_ +MCU_NXP_LPC:LPC1224FBD48-101 +MCU_NXP_LPC:LPC1224FBD48-121 +MCU_NXP_LPC:LPC1224FBD64-101 +MCU_NXP_LPC:LPC1224FBD64-121 +MCU_NXP_LPC:LPC1225FBD48-301 +MCU_NXP_LPC:LPC1225FBD48-321 +MCU_NXP_LPC:LPC1225FBD64-301 +MCU_NXP_LPC:LPC1225FBD64-321 +MCU_NXP_LPC:LPC1226FBD48-301 +MCU_NXP_LPC:LPC1226FBD64-301 +MCU_NXP_LPC:LPC1227FBD48-301 +MCU_NXP_LPC:LPC1227FBD64-301 +MCU_NXP_LPC:LPC1763FBD100 +MCU_NXP_LPC:LPC1764FBD100 +MCU_NXP_LPC:LPC1765FBD100 +MCU_NXP_LPC:LPC1766FBD100 +MCU_NXP_LPC:LPC1767FBD100 +MCU_NXP_LPC:LPC1768FBD100 +MCU_NXP_LPC:LPC1769FBD100 +MCU_NXP_LPC:LPC2141FBD64 +MCU_NXP_LPC:LPC2142FBD64 +MCU_NXP_LPC:LPC2144FBD64 +MCU_NXP_LPC:LPC2146FBD64 +MCU_NXP_LPC:LPC2148FBD64 +MCU_NXP_LPC:LPC811M001JDH16 +MCU_NXP_LPC:LPC812M001JDH16 +MCU_NXP_LPC:LPC812M101JD20 +MCU_NXP_LPC:LPC812M101JDH20 +MCU_NXP_LPC:LPC812M101JTB16 +MCU_NXP_LPC:LPC822M101JDH20 +MCU_NXP_LPC:LPC822M101JHI33 +MCU_NXP_LPC:LPC824M201JDH20 +MCU_NXP_LPC:LPC824M201JHI33 +MCU_NXP_LPC:LPC832M101FDH20 +MCU_NXP_LPC:LPC834M101FHI33 +MCU_NXP_MAC7100:MAC7101 +MCU_NXP_MAC7100:MAC7111 +MCU_NXP_MCore:MMC2114CFCPU +MCU_NXP_NTAG:NHS3100 +MCU_NXP_S08:MC9S08AC128xFDE +MCU_NXP_S08:MC9S08AC128xFGE +MCU_NXP_S08:MC9S08AC128xFUE +MCU_NXP_S08:MC9S08AC128xLKE +MCU_NXP_S08:MC9S08AC128xPUE +MCU_NXP_S08:MC9S08AC16xFDE +MCU_NXP_S08:MC9S08AC16xFGE +MCU_NXP_S08:MC9S08AC16xFJE +MCU_NXP_S08:MC9S08AC32xFDE +MCU_NXP_S08:MC9S08AC32xFGE +MCU_NXP_S08:MC9S08AC32xFJE +MCU_NXP_S08:MC9S08AC32xFUE +MCU_NXP_S08:MC9S08AC32xPUE +MCU_NXP_S08:MC9S08AC48xFDE +MCU_NXP_S08:MC9S08AC48xFGE +MCU_NXP_S08:MC9S08AC48xFJE +MCU_NXP_S08:MC9S08AC48xFUE +MCU_NXP_S08:MC9S08AC48xPUE +MCU_NXP_S08:MC9S08AC60xFDE +MCU_NXP_S08:MC9S08AC60xFGE +MCU_NXP_S08:MC9S08AC60xFJE +MCU_NXP_S08:MC9S08AC60xFUE +MCU_NXP_S08:MC9S08AC60xPUE +MCU_NXP_S08:MC9S08AC8xFDE +MCU_NXP_S08:MC9S08AC8xFGE +MCU_NXP_S08:MC9S08AC8xFJE +MCU_NXP_S08:MC9S08AC96xFDE +MCU_NXP_S08:MC9S08AC96xFGE +MCU_NXP_S08:MC9S08AC96xFUE +MCU_NXP_S08:MC9S08AC96xLKE +MCU_NXP_S08:MC9S08AC96xPUE +MCU_NXP_S08:MC9S08AW16AE0xLC +MCU_NXP_S08:MC9S08AW16xFDE +MCU_NXP_S08:MC9S08AW16xFGE +MCU_NXP_S08:MC9S08AW16xFUE +MCU_NXP_S08:MC9S08AW16xPUE +MCU_NXP_S08:MC9S08AW32xFDE +MCU_NXP_S08:MC9S08AW32xFGE +MCU_NXP_S08:MC9S08AW32xFUE +MCU_NXP_S08:MC9S08AW32xPUE +MCU_NXP_S08:MC9S08AW48xFDE +MCU_NXP_S08:MC9S08AW48xFGE +MCU_NXP_S08:MC9S08AW48xFUE +MCU_NXP_S08:MC9S08AW48xPUE +MCU_NXP_S08:MC9S08AW60xFDE +MCU_NXP_S08:MC9S08AW60xFGE +MCU_NXP_S08:MC9S08AW60xFUE +MCU_NXP_S08:MC9S08AW60xPUE +MCU_NXP_S08:MC9S08AW8AE0xLC +MCU_NXP_S08:MC9S08DN16xLC +MCU_NXP_S08:MC9S08DN16xLF +MCU_NXP_S08:MC9S08DN32xLC +MCU_NXP_S08:MC9S08DN32xLF +MCU_NXP_S08:MC9S08DN32xLH +MCU_NXP_S08:MC9S08DN48xLC +MCU_NXP_S08:MC9S08DN48xLF +MCU_NXP_S08:MC9S08DN48xLH +MCU_NXP_S08:MC9S08DN60xLC +MCU_NXP_S08:MC9S08DN60xLF +MCU_NXP_S08:MC9S08DN60xLH +MCU_NXP_S08:MC9S08DV16xLC +MCU_NXP_S08:MC9S08DV16xLF +MCU_NXP_S08:MC9S08DV32xLC +MCU_NXP_S08:MC9S08DV32xLF +MCU_NXP_S08:MC9S08DV32xLH +MCU_NXP_S08:MC9S08DV48xLC +MCU_NXP_S08:MC9S08DV48xLF +MCU_NXP_S08:MC9S08DV48xLH +MCU_NXP_S08:MC9S08DV60xLC +MCU_NXP_S08:MC9S08DV60xLF +MCU_NXP_S08:MC9S08DV60xLH +MCU_NXP_S08:MC9S08DZ128xLF +MCU_NXP_S08:MC9S08DZ128xLH +MCU_NXP_S08:MC9S08DZ128xLL +MCU_NXP_S08:MC9S08DZ16xLC +MCU_NXP_S08:MC9S08DZ16xLF +MCU_NXP_S08:MC9S08DZ32xLC +MCU_NXP_S08:MC9S08DZ32xLF +MCU_NXP_S08:MC9S08DZ32xLH +MCU_NXP_S08:MC9S08DZ48xLC +MCU_NXP_S08:MC9S08DZ48xLF +MCU_NXP_S08:MC9S08DZ48xLH +MCU_NXP_S08:MC9S08DZ60xLC +MCU_NXP_S08:MC9S08DZ60xLF +MCU_NXP_S08:MC9S08DZ60xLH +MCU_NXP_S08:MC9S08DZ96xLF +MCU_NXP_S08:MC9S08DZ96xLH +MCU_NXP_S08:MC9S08DZ96xLL +MCU_NXP_S08:MC9S08EL16xTJ +MCU_NXP_S08:MC9S08EL16xTL +MCU_NXP_S08:MC9S08EL32xTJ +MCU_NXP_S08:MC9S08EL32xTL +MCU_NXP_S08:MC9S08FL16xLC +MCU_NXP_S08:MC9S08FL8xLC +MCU_NXP_S08:MC9S08JM16xGT +MCU_NXP_S08:MC9S08JM16xLC +MCU_NXP_S08:MC9S08JM16xLD +MCU_NXP_S08:MC9S08JM32xGT +MCU_NXP_S08:MC9S08JM32xLD +MCU_NXP_S08:MC9S08JM32xLH +MCU_NXP_S08:MC9S08JM60xGT +MCU_NXP_S08:MC9S08JM60xLD +MCU_NXP_S08:MC9S08JM60xLH +MCU_NXP_S08:MC9S08JM8xGT +MCU_NXP_S08:MC9S08JM8xLC +MCU_NXP_S08:MC9S08JM8xLD +MCU_NXP_S08:MC9S08JS16CFK +MCU_NXP_S08:MC9S08JS16CWJ +MCU_NXP_S08:MC9S08JS8CFK +MCU_NXP_S08:MC9S08JS8CWJ +MCU_NXP_S08:MC9S08LG32J0xLF +MCU_NXP_S08:MC9S08LG32J0xLH +MCU_NXP_S08:MC9S08LG32J0xLK +MCU_NXP_S08:MC9S08MP16xLC +MCU_NXP_S08:MC9S08MP16xLF +MCU_NXP_S08:MC9S08MP16xWL +MCU_NXP_S08:MC9S08QA2CDNE +MCU_NXP_S08:MC9S08QA2CFQE +MCU_NXP_S08:MC9S08QA2CPAE +MCU_NXP_S08:MC9S08QA4CDNE +MCU_NXP_S08:MC9S08QA4CFQE +MCU_NXP_S08:MC9S08QA4CPAE +MCU_NXP_S08:MC9S08QB4xGK +MCU_NXP_S08:MC9S08QB4xTG +MCU_NXP_S08:MC9S08QB4xWL +MCU_NXP_S08:MC9S08QB8xGK +MCU_NXP_S08:MC9S08QB8xTG +MCU_NXP_S08:MC9S08QB8xWL +MCU_NXP_S08:MC9S08QD2xPC +MCU_NXP_S08:MC9S08QD2xSC +MCU_NXP_S08:MC9S08QD4xPC +MCU_NXP_S08:MC9S08QD4xSC +MCU_NXP_S08:MC9S08QG4xDNE +MCU_NXP_S08:MC9S08QG4xDTE +MCU_NXP_S08:MC9S08QG4xFKE +MCU_NXP_S08:MC9S08QG4xFQE +MCU_NXP_S08:MC9S08QG4xPAE +MCU_NXP_S08:MC9S08QG8xDNE +MCU_NXP_S08:MC9S08QG8xDTE +MCU_NXP_S08:MC9S08QG8xFKE +MCU_NXP_S08:MC9S08QG8xFQE +MCU_NXP_S08:MC9S08QG8xPBE +MCU_NXP_S08:MC9S08SC4xTG +MCU_NXP_S08:MC9S08SE4xRL +MCU_NXP_S08:MC9S08SE4xTG +MCU_NXP_S08:MC9S08SE4xWL +MCU_NXP_S08:MC9S08SE8xRL +MCU_NXP_S08:MC9S08SE8xTG +MCU_NXP_S08:MC9S08SE8xWL +MCU_NXP_S08:MC9S08SF4xTG +MCU_NXP_S08:MC9S08SF4xTJ +MCU_NXP_S08:MC9S08SG16xTG +MCU_NXP_S08:MC9S08SG16xTJ +MCU_NXP_S08:MC9S08SG16xTL +MCU_NXP_S08:MC9S08SG32xTG +MCU_NXP_S08:MC9S08SG32xTJ +MCU_NXP_S08:MC9S08SG32xTL +MCU_NXP_S08:MC9S08SG4xSC +MCU_NXP_S08:MC9S08SG4xTG +MCU_NXP_S08:MC9S08SG4xTJ +MCU_NXP_S08:MC9S08SG8xSC +MCU_NXP_S08:MC9S08SG8xTG +MCU_NXP_S08:MC9S08SG8xTJ +MCU_NXP_S08:MC9S08SH16xTG +MCU_NXP_S08:MC9S08SH16xTJ +MCU_NXP_S08:MC9S08SH16xTL +MCU_NXP_S08:MC9S08SH16xWL +MCU_NXP_S08:MC9S08SH32xTG +MCU_NXP_S08:MC9S08SH32xTJ +MCU_NXP_S08:MC9S08SH32xTL +MCU_NXP_S08:MC9S08SH32xWL +MCU_NXP_S08:MC9S08SH4xFK +MCU_NXP_S08:MC9S08SH4xPJ +MCU_NXP_S08:MC9S08SH4xSC +MCU_NXP_S08:MC9S08SH4xTG +MCU_NXP_S08:MC9S08SH4xTJ +MCU_NXP_S08:MC9S08SH4xWJ +MCU_NXP_S08:MC9S08SH8xFK +MCU_NXP_S08:MC9S08SH8xPJ +MCU_NXP_S08:MC9S08SH8xSC +MCU_NXP_S08:MC9S08SH8xTG +MCU_NXP_S08:MC9S08SH8xTJ +MCU_NXP_S08:MC9S08SH8xWJ +MCU_NXP_S08:MC9S08SL16xTJ +MCU_NXP_S08:MC9S08SL16xTL +MCU_NXP_S08:MC9S08SL32xTJ +MCU_NXP_S08:MC9S08SL32xTL +MCU_NXP_S08:MC9S08SV16CLC +MCU_NXP_S08:MC9S08SV8CLC +MCU_Parallax:P8X32A-D40 +MCU_Parallax:P8X32A-M44 +MCU_Parallax:P8X32A-Q44 +MCU_Puya:PY32F002AF15P +MCU_RaspberryPi:RP2040 +MCU_Renesas_Synergy_S1:R7FS12878xA01CFL +MCU_SiFive:FE310-G000 +MCU_SiFive:FE310-G002 +MCU_SiFive:FU540-C000 +MCU_SiliconLabs:C8051F320-GQ +MCU_SiliconLabs:C8051F321-GM +MCU_SiliconLabs:C8051F380-GQ +MCU_SiliconLabs:C8051F381-GM +MCU_SiliconLabs:C8051F381-GQ +MCU_SiliconLabs:C8051F382-GQ +MCU_SiliconLabs:C8051F383-GM +MCU_SiliconLabs:C8051F383-GQ +MCU_SiliconLabs:C8051F384-GQ +MCU_SiliconLabs:C8051F385-GM +MCU_SiliconLabs:C8051F385-GQ +MCU_SiliconLabs:C8051F386-GQ +MCU_SiliconLabs:C8051F387-GM +MCU_SiliconLabs:C8051F387-GQ +MCU_SiliconLabs:C8051F38C-GM +MCU_SiliconLabs:C8051F38C-GQ +MCU_SiliconLabs:EFM32G230F128G-E-QFN64 +MCU_SiliconLabs:EFM32HG108F32G-C-QFN24 +MCU_SiliconLabs:EFM32HG108F64G-C-QFN24 +MCU_SiliconLabs:EFM32HG308F32G-C-QFN24 +MCU_SiliconLabs:EFM32HG308F64G-C-QFN24 +MCU_SiliconLabs:EFM32ZG108F16-B-QFN24 +MCU_SiliconLabs:EFM32ZG108F32-B-QFN24 +MCU_SiliconLabs:EFM32ZG108F4-B-QFN24 +MCU_SiliconLabs:EFM32ZG108F8-B-QFN24 +MCU_SiliconLabs:EFM32ZG110F16-B-QFN24 +MCU_SiliconLabs:EFM32ZG110F32-B-QFN24 +MCU_SiliconLabs:EFM32ZG110F4-B-QFN24 +MCU_SiliconLabs:EFM32ZG110F8-B-QFN24 +MCU_SiliconLabs:EFM8BB10F2A-A-QFN20 +MCU_SiliconLabs:EFM8BB10F2G-A-QFN20 +MCU_SiliconLabs:EFM8BB10F2I-A-QFN20 +MCU_SiliconLabs:EFM8BB10F4A-A-QFN20 +MCU_SiliconLabs:EFM8BB10F4G-A-QFN20 +MCU_SiliconLabs:EFM8BB10F4I-A-QFN20 +MCU_SiliconLabs:EFM8BB10F8A-A-QFN20 +MCU_SiliconLabs:EFM8BB10F8G-A-QFN20 +MCU_SiliconLabs:EFM8BB10F8G-A-QSOP24 +MCU_SiliconLabs:EFM8BB10F8G-A-SOIC16 +MCU_SiliconLabs:EFM8BB10F8I-A-QFN20 +MCU_SiliconLabs:EFM8BB10F8I-A-QSOP24 +MCU_SiliconLabs:EFM8BB10F8I-A-SOIC16 +MCU_SiliconLabs:EFM8LB12F32E-C-QFP32 +MCU_SiliconLabs:EFM8LB12F64E-C-QFP32 +MCU_SiliconLabs:EFM8UB30F40G-A-QFN20 +MCU_SiliconLabs:EFM8UB31F40G-A-QFN24 +MCU_SiliconLabs:EFM8UB31F40G-A-QSOP24 +MCU_SiliconLabs:EFR32xG23xxxxF512xM48 +MCU_STC:IAP15W205S-35x-SOP16 +MCU_STC:IRC15W207S-35x-SOP16 +MCU_STC:STC15W201S-35x-SOP16 +MCU_STC:STC15W202S-35x-SOP16 +MCU_STC:STC15W203S-35x-SOP16 +MCU_STC:STC15W204S-35x-SOP16 +MCU_STC:STC8G1K04-38I-TSSOP20 +MCU_STC:STC8G1K08-38I-TSSOP20 +MCU_STC:STC8G1K08A-36I-DFN8 +MCU_STC:STC8G1K17-38I-TSSOP20 +MCU_ST_STM32C0:STM32C011D6Yx +MCU_ST_STM32C0:STM32C011F4Px +MCU_ST_STM32C0:STM32C011F4Ux +MCU_ST_STM32C0:STM32C011F6Px +MCU_ST_STM32C0:STM32C011F6Ux +MCU_ST_STM32C0:STM32C011F_4-6_Px +MCU_ST_STM32C0:STM32C011F_4-6_Ux +MCU_ST_STM32C0:STM32C011J4Mx +MCU_ST_STM32C0:STM32C011J6Mx +MCU_ST_STM32C0:STM32C011J_4-6_Mx +MCU_ST_STM32C0:STM32C031C4Tx +MCU_ST_STM32C0:STM32C031C4Ux +MCU_ST_STM32C0:STM32C031C6Tx +MCU_ST_STM32C0:STM32C031C6Ux +MCU_ST_STM32C0:STM32C031C_4-6_Tx +MCU_ST_STM32C0:STM32C031C_4-6_Ux +MCU_ST_STM32C0:STM32C031F4Px +MCU_ST_STM32C0:STM32C031F6Px +MCU_ST_STM32C0:STM32C031F_4-6_Px +MCU_ST_STM32C0:STM32C031G4Ux +MCU_ST_STM32C0:STM32C031G6Ux +MCU_ST_STM32C0:STM32C031G_4-6_Ux +MCU_ST_STM32C0:STM32C031K4Tx +MCU_ST_STM32C0:STM32C031K4Ux +MCU_ST_STM32C0:STM32C031K6Tx +MCU_ST_STM32C0:STM32C031K6Ux +MCU_ST_STM32C0:STM32C031K_4-6_Tx +MCU_ST_STM32C0:STM32C031K_4-6_Ux +MCU_ST_STM32C0:STM32C071C8Tx +MCU_ST_STM32C0:STM32C071C8TxN +MCU_ST_STM32C0:STM32C071C8Ux +MCU_ST_STM32C0:STM32C071C8UxN +MCU_ST_STM32C0:STM32C071CBTx +MCU_ST_STM32C0:STM32C071CBTxN +MCU_ST_STM32C0:STM32C071CBUx +MCU_ST_STM32C0:STM32C071CBUxN +MCU_ST_STM32C0:STM32C071F8Px +MCU_ST_STM32C0:STM32C071F8PxN +MCU_ST_STM32C0:STM32C071FBPx +MCU_ST_STM32C0:STM32C071FBPxN +MCU_ST_STM32C0:STM32C071G8Ux +MCU_ST_STM32C0:STM32C071G8UxN +MCU_ST_STM32C0:STM32C071GBUx +MCU_ST_STM32C0:STM32C071GBUxN +MCU_ST_STM32C0:STM32C071K8Tx +MCU_ST_STM32C0:STM32C071K8TxN +MCU_ST_STM32C0:STM32C071K8Ux +MCU_ST_STM32C0:STM32C071K8UxN +MCU_ST_STM32C0:STM32C071KBTx +MCU_ST_STM32C0:STM32C071KBTxN +MCU_ST_STM32C0:STM32C071KBUx +MCU_ST_STM32C0:STM32C071KBUxN +MCU_ST_STM32C0:STM32C071R8Tx +MCU_ST_STM32C0:STM32C071R8TxN +MCU_ST_STM32C0:STM32C071RBIxN +MCU_ST_STM32C0:STM32C071RBTx +MCU_ST_STM32C0:STM32C071RBTxN +MCU_ST_STM32F0:STM32F030C6Tx +MCU_ST_STM32F0:STM32F030C8Tx +MCU_ST_STM32F0:STM32F030CCTx +MCU_ST_STM32F0:STM32F030F4Px +MCU_ST_STM32F0:STM32F030K6Tx +MCU_ST_STM32F0:STM32F030R8Tx +MCU_ST_STM32F0:STM32F030RCTx +MCU_ST_STM32F0:STM32F031C4Tx +MCU_ST_STM32F0:STM32F031C6Tx +MCU_ST_STM32F0:STM32F031C_4-6_Tx +MCU_ST_STM32F0:STM32F031E6Yx +MCU_ST_STM32F0:STM32F031F4Px +MCU_ST_STM32F0:STM32F031F6Px +MCU_ST_STM32F0:STM32F031F_4-6_Px +MCU_ST_STM32F0:STM32F031G4Ux +MCU_ST_STM32F0:STM32F031G6Ux +MCU_ST_STM32F0:STM32F031G_4-6_Ux +MCU_ST_STM32F0:STM32F031K4Ux +MCU_ST_STM32F0:STM32F031K6Tx +MCU_ST_STM32F0:STM32F031K6Ux +MCU_ST_STM32F0:STM32F031K_4-6_Ux +MCU_ST_STM32F0:STM32F038C6Tx +MCU_ST_STM32F0:STM32F038E6Yx +MCU_ST_STM32F0:STM32F038F6Px +MCU_ST_STM32F0:STM32F038G6Ux +MCU_ST_STM32F0:STM32F038K6Ux +MCU_ST_STM32F0:STM32F042C4Tx +MCU_ST_STM32F0:STM32F042C4Ux +MCU_ST_STM32F0:STM32F042C6Tx +MCU_ST_STM32F0:STM32F042C6Ux +MCU_ST_STM32F0:STM32F042C_4-6_Tx +MCU_ST_STM32F0:STM32F042C_4-6_Ux +MCU_ST_STM32F0:STM32F042F4Px +MCU_ST_STM32F0:STM32F042F6Px +MCU_ST_STM32F0:STM32F042G4Ux +MCU_ST_STM32F0:STM32F042G6Ux +MCU_ST_STM32F0:STM32F042G_4-6_Ux +MCU_ST_STM32F0:STM32F042K4Tx +MCU_ST_STM32F0:STM32F042K4Ux +MCU_ST_STM32F0:STM32F042K6Tx +MCU_ST_STM32F0:STM32F042K6Ux +MCU_ST_STM32F0:STM32F042K_4-6_Tx +MCU_ST_STM32F0:STM32F042K_4-6_Ux +MCU_ST_STM32F0:STM32F042T6Yx +MCU_ST_STM32F0:STM32F048C6Ux +MCU_ST_STM32F0:STM32F048G6Ux +MCU_ST_STM32F0:STM32F048T6Yx +MCU_ST_STM32F0:STM32F051C4Tx +MCU_ST_STM32F0:STM32F051C4Ux +MCU_ST_STM32F0:STM32F051C6Tx +MCU_ST_STM32F0:STM32F051C6Ux +MCU_ST_STM32F0:STM32F051C8Tx +MCU_ST_STM32F0:STM32F051C8Ux +MCU_ST_STM32F0:STM32F051K4Tx +MCU_ST_STM32F0:STM32F051K4Ux +MCU_ST_STM32F0:STM32F051K6Tx +MCU_ST_STM32F0:STM32F051K6Ux +MCU_ST_STM32F0:STM32F051K8Tx +MCU_ST_STM32F0:STM32F051K8Ux +MCU_ST_STM32F0:STM32F051R4Tx +MCU_ST_STM32F0:STM32F051R6Tx +MCU_ST_STM32F0:STM32F051R8Hx +MCU_ST_STM32F0:STM32F051R8Tx +MCU_ST_STM32F0:STM32F051T8Yx +MCU_ST_STM32F0:STM32F058C8Ux +MCU_ST_STM32F0:STM32F058R8Hx +MCU_ST_STM32F0:STM32F058R8Tx +MCU_ST_STM32F0:STM32F058T8Yx +MCU_ST_STM32F0:STM32F070C6Tx +MCU_ST_STM32F0:STM32F070CBTx +MCU_ST_STM32F0:STM32F070F6Px +MCU_ST_STM32F0:STM32F070RBTx +MCU_ST_STM32F0:STM32F071C8Tx +MCU_ST_STM32F0:STM32F071C8Ux +MCU_ST_STM32F0:STM32F071CBTx +MCU_ST_STM32F0:STM32F071CBUx +MCU_ST_STM32F0:STM32F071CBYx +MCU_ST_STM32F0:STM32F071C_8-B_Tx +MCU_ST_STM32F0:STM32F071C_8-B_Ux +MCU_ST_STM32F0:STM32F071RBTx +MCU_ST_STM32F0:STM32F071V8Hx +MCU_ST_STM32F0:STM32F071V8Tx +MCU_ST_STM32F0:STM32F071VBHx +MCU_ST_STM32F0:STM32F071VBTx +MCU_ST_STM32F0:STM32F071V_8-B_Hx +MCU_ST_STM32F0:STM32F071V_8-B_Tx +MCU_ST_STM32F0:STM32F072C8Tx +MCU_ST_STM32F0:STM32F072C8Ux +MCU_ST_STM32F0:STM32F072CBTx +MCU_ST_STM32F0:STM32F072CBUx +MCU_ST_STM32F0:STM32F072CBYx +MCU_ST_STM32F0:STM32F072C_8-B_Tx +MCU_ST_STM32F0:STM32F072C_8-B_Ux +MCU_ST_STM32F0:STM32F072R8Tx +MCU_ST_STM32F0:STM32F072RBHx +MCU_ST_STM32F0:STM32F072RBIx +MCU_ST_STM32F0:STM32F072RBTx +MCU_ST_STM32F0:STM32F072R_8-B_Tx +MCU_ST_STM32F0:STM32F072V8Hx +MCU_ST_STM32F0:STM32F072V8Tx +MCU_ST_STM32F0:STM32F072VBHx +MCU_ST_STM32F0:STM32F072VBTx +MCU_ST_STM32F0:STM32F072V_8-B_Hx +MCU_ST_STM32F0:STM32F072V_8-B_Tx +MCU_ST_STM32F0:STM32F078CBTx +MCU_ST_STM32F0:STM32F078CBUx +MCU_ST_STM32F0:STM32F078CBYx +MCU_ST_STM32F0:STM32F078RBHx +MCU_ST_STM32F0:STM32F078RBTx +MCU_ST_STM32F0:STM32F078VBHx +MCU_ST_STM32F0:STM32F078VBTx +MCU_ST_STM32F0:STM32F091CBTx +MCU_ST_STM32F0:STM32F091CBUx +MCU_ST_STM32F0:STM32F091CCTx +MCU_ST_STM32F0:STM32F091CCUx +MCU_ST_STM32F0:STM32F091C_B-C_Tx +MCU_ST_STM32F0:STM32F091C_B-C_Ux +MCU_ST_STM32F0:STM32F091RBTx +MCU_ST_STM32F0:STM32F091RCHx +MCU_ST_STM32F0:STM32F091RCTx +MCU_ST_STM32F0:STM32F091RCYx +MCU_ST_STM32F0:STM32F091R_B-C_Tx +MCU_ST_STM32F0:STM32F091VBTx +MCU_ST_STM32F0:STM32F091VCHx +MCU_ST_STM32F0:STM32F091VCTx +MCU_ST_STM32F0:STM32F091V_B-C_Tx +MCU_ST_STM32F0:STM32F098CCTx +MCU_ST_STM32F0:STM32F098CCUx +MCU_ST_STM32F0:STM32F098RCHx +MCU_ST_STM32F0:STM32F098RCTx +MCU_ST_STM32F0:STM32F098RCYx +MCU_ST_STM32F0:STM32F098VCHx +MCU_ST_STM32F0:STM32F098VCTx +MCU_ST_STM32F1:STM32F100C4Tx +MCU_ST_STM32F1:STM32F100C6Tx +MCU_ST_STM32F1:STM32F100C8Tx +MCU_ST_STM32F1:STM32F100CBTx +MCU_ST_STM32F1:STM32F100C_4-6_Tx +MCU_ST_STM32F1:STM32F100C_8-B_Tx +MCU_ST_STM32F1:STM32F100R4Hx +MCU_ST_STM32F1:STM32F100R4Tx +MCU_ST_STM32F1:STM32F100R6Hx +MCU_ST_STM32F1:STM32F100R6Tx +MCU_ST_STM32F1:STM32F100R8Hx +MCU_ST_STM32F1:STM32F100R8Tx +MCU_ST_STM32F1:STM32F100RBHx +MCU_ST_STM32F1:STM32F100RBTx +MCU_ST_STM32F1:STM32F100RCTx +MCU_ST_STM32F1:STM32F100RDTx +MCU_ST_STM32F1:STM32F100RETx +MCU_ST_STM32F1:STM32F100R_4-6_Hx +MCU_ST_STM32F1:STM32F100R_4-6_Tx +MCU_ST_STM32F1:STM32F100R_8-B_Hx +MCU_ST_STM32F1:STM32F100R_8-B_Tx +MCU_ST_STM32F1:STM32F100R_C-D-E_Tx +MCU_ST_STM32F1:STM32F100V8Tx +MCU_ST_STM32F1:STM32F100VBTx +MCU_ST_STM32F1:STM32F100VCTx +MCU_ST_STM32F1:STM32F100VDTx +MCU_ST_STM32F1:STM32F100VETx +MCU_ST_STM32F1:STM32F100V_8-B_Tx +MCU_ST_STM32F1:STM32F100V_C-D-E_Tx +MCU_ST_STM32F1:STM32F100ZCTx +MCU_ST_STM32F1:STM32F100ZDTx +MCU_ST_STM32F1:STM32F100ZETx +MCU_ST_STM32F1:STM32F100Z_C-D-E_Tx +MCU_ST_STM32F1:STM32F101C4Tx +MCU_ST_STM32F1:STM32F101C6Tx +MCU_ST_STM32F1:STM32F101C8Tx +MCU_ST_STM32F1:STM32F101C8Ux +MCU_ST_STM32F1:STM32F101CBTx +MCU_ST_STM32F1:STM32F101CBUx +MCU_ST_STM32F1:STM32F101C_4-6_Tx +MCU_ST_STM32F1:STM32F101C_8-B_Tx +MCU_ST_STM32F1:STM32F101C_8-B_Ux +MCU_ST_STM32F1:STM32F101R4Tx +MCU_ST_STM32F1:STM32F101R6Tx +MCU_ST_STM32F1:STM32F101R8Tx +MCU_ST_STM32F1:STM32F101RBHx +MCU_ST_STM32F1:STM32F101RBTx +MCU_ST_STM32F1:STM32F101RCTx +MCU_ST_STM32F1:STM32F101RDTx +MCU_ST_STM32F1:STM32F101RETx +MCU_ST_STM32F1:STM32F101RFTx +MCU_ST_STM32F1:STM32F101RGTx +MCU_ST_STM32F1:STM32F101R_4-6_Tx +MCU_ST_STM32F1:STM32F101R_8-B_Tx +MCU_ST_STM32F1:STM32F101R_C-D-E_Tx +MCU_ST_STM32F1:STM32F101R_F-G_Tx +MCU_ST_STM32F1:STM32F101T4Ux +MCU_ST_STM32F1:STM32F101T6Ux +MCU_ST_STM32F1:STM32F101T8Ux +MCU_ST_STM32F1:STM32F101TBUx +MCU_ST_STM32F1:STM32F101T_4-6_Ux +MCU_ST_STM32F1:STM32F101T_8-B_Ux +MCU_ST_STM32F1:STM32F101V8Tx +MCU_ST_STM32F1:STM32F101VBTx +MCU_ST_STM32F1:STM32F101VCTx +MCU_ST_STM32F1:STM32F101VDTx +MCU_ST_STM32F1:STM32F101VETx +MCU_ST_STM32F1:STM32F101VFTx +MCU_ST_STM32F1:STM32F101VGTx +MCU_ST_STM32F1:STM32F101V_8-B_Tx +MCU_ST_STM32F1:STM32F101V_C-D-E_Tx +MCU_ST_STM32F1:STM32F101V_F-G_Tx +MCU_ST_STM32F1:STM32F101ZCTx +MCU_ST_STM32F1:STM32F101ZDTx +MCU_ST_STM32F1:STM32F101ZETx +MCU_ST_STM32F1:STM32F101ZFTx +MCU_ST_STM32F1:STM32F101ZGTx +MCU_ST_STM32F1:STM32F101Z_C-D-E_Tx +MCU_ST_STM32F1:STM32F101Z_F-G_Tx +MCU_ST_STM32F1:STM32F102C4Tx +MCU_ST_STM32F1:STM32F102C6Tx +MCU_ST_STM32F1:STM32F102C8Tx +MCU_ST_STM32F1:STM32F102CBTx +MCU_ST_STM32F1:STM32F102C_4-6_Tx +MCU_ST_STM32F1:STM32F102C_8-B_Tx +MCU_ST_STM32F1:STM32F102R4Tx +MCU_ST_STM32F1:STM32F102R6Tx +MCU_ST_STM32F1:STM32F102R8Tx +MCU_ST_STM32F1:STM32F102RBTx +MCU_ST_STM32F1:STM32F102R_4-6_Tx +MCU_ST_STM32F1:STM32F102R_8-B_Tx +MCU_ST_STM32F1:STM32F103C4Tx +MCU_ST_STM32F1:STM32F103C6Tx +MCU_ST_STM32F1:STM32F103C6Ux +MCU_ST_STM32F1:STM32F103C8Tx +MCU_ST_STM32F1:STM32F103CBTx +MCU_ST_STM32F1:STM32F103CBUx +MCU_ST_STM32F1:STM32F103C_4-6_Tx +MCU_ST_STM32F1:STM32F103C_8-B_Tx +MCU_ST_STM32F1:STM32F103R4Hx +MCU_ST_STM32F1:STM32F103R4Tx +MCU_ST_STM32F1:STM32F103R6Hx +MCU_ST_STM32F1:STM32F103R6Tx +MCU_ST_STM32F1:STM32F103R8Hx +MCU_ST_STM32F1:STM32F103R8Tx +MCU_ST_STM32F1:STM32F103RBHx +MCU_ST_STM32F1:STM32F103RBTx +MCU_ST_STM32F1:STM32F103RCTx +MCU_ST_STM32F1:STM32F103RCYx +MCU_ST_STM32F1:STM32F103RDTx +MCU_ST_STM32F1:STM32F103RDYx +MCU_ST_STM32F1:STM32F103RETx +MCU_ST_STM32F1:STM32F103REYx +MCU_ST_STM32F1:STM32F103RFTx +MCU_ST_STM32F1:STM32F103RGTx +MCU_ST_STM32F1:STM32F103R_4-6_Hx +MCU_ST_STM32F1:STM32F103R_4-6_Tx +MCU_ST_STM32F1:STM32F103R_8-B_Hx +MCU_ST_STM32F1:STM32F103R_8-B_Tx +MCU_ST_STM32F1:STM32F103R_C-D-E_Tx +MCU_ST_STM32F1:STM32F103R_C-D-E_Yx +MCU_ST_STM32F1:STM32F103R_F-G_Tx +MCU_ST_STM32F1:STM32F103T4Ux +MCU_ST_STM32F1:STM32F103T6Ux +MCU_ST_STM32F1:STM32F103T8Ux +MCU_ST_STM32F1:STM32F103TBUx +MCU_ST_STM32F1:STM32F103T_4-6_Ux +MCU_ST_STM32F1:STM32F103T_8-B_Ux +MCU_ST_STM32F1:STM32F103V8Hx +MCU_ST_STM32F1:STM32F103V8Tx +MCU_ST_STM32F1:STM32F103VBHx +MCU_ST_STM32F1:STM32F103VBIx +MCU_ST_STM32F1:STM32F103VBTx +MCU_ST_STM32F1:STM32F103VCHx +MCU_ST_STM32F1:STM32F103VCTx +MCU_ST_STM32F1:STM32F103VDHx +MCU_ST_STM32F1:STM32F103VDTx +MCU_ST_STM32F1:STM32F103VEHx +MCU_ST_STM32F1:STM32F103VETx +MCU_ST_STM32F1:STM32F103VFTx +MCU_ST_STM32F1:STM32F103VGTx +MCU_ST_STM32F1:STM32F103V_8-B_Hx +MCU_ST_STM32F1:STM32F103V_8-B_Tx +MCU_ST_STM32F1:STM32F103V_C-D-E_Hx +MCU_ST_STM32F1:STM32F103V_C-D-E_Tx +MCU_ST_STM32F1:STM32F103V_F-G_Tx +MCU_ST_STM32F1:STM32F103ZCHx +MCU_ST_STM32F1:STM32F103ZCTx +MCU_ST_STM32F1:STM32F103ZDHx +MCU_ST_STM32F1:STM32F103ZDTx +MCU_ST_STM32F1:STM32F103ZEHx +MCU_ST_STM32F1:STM32F103ZETx +MCU_ST_STM32F1:STM32F103ZFHx +MCU_ST_STM32F1:STM32F103ZFTx +MCU_ST_STM32F1:STM32F103ZGHx +MCU_ST_STM32F1:STM32F103ZGTx +MCU_ST_STM32F1:STM32F103Z_C-D-E_Hx +MCU_ST_STM32F1:STM32F103Z_C-D-E_Tx +MCU_ST_STM32F1:STM32F103Z_F-G_Hx +MCU_ST_STM32F1:STM32F103Z_F-G_Tx +MCU_ST_STM32F1:STM32F105R8Tx +MCU_ST_STM32F1:STM32F105RBTx +MCU_ST_STM32F1:STM32F105RCTx +MCU_ST_STM32F1:STM32F105R_8-B-C_Tx +MCU_ST_STM32F1:STM32F105V8Hx +MCU_ST_STM32F1:STM32F105V8Tx +MCU_ST_STM32F1:STM32F105VBHx +MCU_ST_STM32F1:STM32F105VBTx +MCU_ST_STM32F1:STM32F105VCTx +MCU_ST_STM32F1:STM32F105V_8-B-C_Tx +MCU_ST_STM32F1:STM32F105V_8-B_Hx +MCU_ST_STM32F1:STM32F107RBTx +MCU_ST_STM32F1:STM32F107RCTx +MCU_ST_STM32F1:STM32F107R_B-C_Tx +MCU_ST_STM32F1:STM32F107VBTx +MCU_ST_STM32F1:STM32F107VCHx +MCU_ST_STM32F1:STM32F107VCTx +MCU_ST_STM32F1:STM32F107V_B-C_Tx +MCU_ST_STM32F2:STM32F205RBTx +MCU_ST_STM32F2:STM32F205RCTx +MCU_ST_STM32F2:STM32F205RETx +MCU_ST_STM32F2:STM32F205REYx +MCU_ST_STM32F2:STM32F205RFTx +MCU_ST_STM32F2:STM32F205RGEx +MCU_ST_STM32F2:STM32F205RGTx +MCU_ST_STM32F2:STM32F205RGYx +MCU_ST_STM32F2:STM32F205R_B-C-E-F-G_Tx +MCU_ST_STM32F2:STM32F205R_E-G_Yx +MCU_ST_STM32F2:STM32F205VBTx +MCU_ST_STM32F2:STM32F205VCTx +MCU_ST_STM32F2:STM32F205VETx +MCU_ST_STM32F2:STM32F205VFTx +MCU_ST_STM32F2:STM32F205VGTx +MCU_ST_STM32F2:STM32F205V_B-C-E-F-G_Tx +MCU_ST_STM32F2:STM32F205ZCTx +MCU_ST_STM32F2:STM32F205ZETx +MCU_ST_STM32F2:STM32F205ZFTx +MCU_ST_STM32F2:STM32F205ZGTx +MCU_ST_STM32F2:STM32F205Z_C-E-F-G_Tx +MCU_ST_STM32F2:STM32F207ICHx +MCU_ST_STM32F2:STM32F207ICTx +MCU_ST_STM32F2:STM32F207IEHx +MCU_ST_STM32F2:STM32F207IETx +MCU_ST_STM32F2:STM32F207IFHx +MCU_ST_STM32F2:STM32F207IFTx +MCU_ST_STM32F2:STM32F207IGHx +MCU_ST_STM32F2:STM32F207IGTx +MCU_ST_STM32F2:STM32F207I_C-E-F-G_Hx +MCU_ST_STM32F2:STM32F207I_C-E-F-G_Tx +MCU_ST_STM32F2:STM32F207VCTx +MCU_ST_STM32F2:STM32F207VETx +MCU_ST_STM32F2:STM32F207VFTx +MCU_ST_STM32F2:STM32F207VGTx +MCU_ST_STM32F2:STM32F207V_C-E-F-G_Tx +MCU_ST_STM32F2:STM32F207ZCTx +MCU_ST_STM32F2:STM32F207ZETx +MCU_ST_STM32F2:STM32F207ZFTx +MCU_ST_STM32F2:STM32F207ZGTx +MCU_ST_STM32F2:STM32F207Z_C-E-F-G_Tx +MCU_ST_STM32F2:STM32F215RETx +MCU_ST_STM32F2:STM32F215RGTx +MCU_ST_STM32F2:STM32F215R_E-G_Tx +MCU_ST_STM32F2:STM32F215VETx +MCU_ST_STM32F2:STM32F215VGTx +MCU_ST_STM32F2:STM32F215V_E-G_Tx +MCU_ST_STM32F2:STM32F215ZETx +MCU_ST_STM32F2:STM32F215ZGTx +MCU_ST_STM32F2:STM32F215Z_E-G_Tx +MCU_ST_STM32F2:STM32F217IEHx +MCU_ST_STM32F2:STM32F217IETx +MCU_ST_STM32F2:STM32F217IGHx +MCU_ST_STM32F2:STM32F217IGTx +MCU_ST_STM32F2:STM32F217I_E-G_Hx +MCU_ST_STM32F2:STM32F217I_E-G_Tx +MCU_ST_STM32F2:STM32F217VETx +MCU_ST_STM32F2:STM32F217VGTx +MCU_ST_STM32F2:STM32F217V_E-G_Tx +MCU_ST_STM32F2:STM32F217ZETx +MCU_ST_STM32F2:STM32F217ZGTx +MCU_ST_STM32F2:STM32F217Z_E-G_Tx +MCU_ST_STM32F3:STM32F301C6Tx +MCU_ST_STM32F3:STM32F301C8Tx +MCU_ST_STM32F3:STM32F301C8Yx +MCU_ST_STM32F3:STM32F301C_6-8_Tx +MCU_ST_STM32F3:STM32F301K6Tx +MCU_ST_STM32F3:STM32F301K6Ux +MCU_ST_STM32F3:STM32F301K8Tx +MCU_ST_STM32F3:STM32F301K8Ux +MCU_ST_STM32F3:STM32F301K_6-8_Tx +MCU_ST_STM32F3:STM32F301K_6-8_Ux +MCU_ST_STM32F3:STM32F301R6Tx +MCU_ST_STM32F3:STM32F301R8Tx +MCU_ST_STM32F3:STM32F301R_6-8_Tx +MCU_ST_STM32F3:STM32F302C6Tx +MCU_ST_STM32F3:STM32F302C8Tx +MCU_ST_STM32F3:STM32F302C8Yx +MCU_ST_STM32F3:STM32F302CBTx +MCU_ST_STM32F3:STM32F302CCTx +MCU_ST_STM32F3:STM32F302C_6-8_Tx +MCU_ST_STM32F3:STM32F302C_B-C_Tx +MCU_ST_STM32F3:STM32F302K6Ux +MCU_ST_STM32F3:STM32F302K8Ux +MCU_ST_STM32F3:STM32F302K_6-8_Ux +MCU_ST_STM32F3:STM32F302R6Tx +MCU_ST_STM32F3:STM32F302R8Tx +MCU_ST_STM32F3:STM32F302RBTx +MCU_ST_STM32F3:STM32F302RCTx +MCU_ST_STM32F3:STM32F302RDTx +MCU_ST_STM32F3:STM32F302RETx +MCU_ST_STM32F3:STM32F302R_6-8_Tx +MCU_ST_STM32F3:STM32F302R_B-C_Tx +MCU_ST_STM32F3:STM32F302R_D-E_Tx +MCU_ST_STM32F3:STM32F302VBTx +MCU_ST_STM32F3:STM32F302VCTx +MCU_ST_STM32F3:STM32F302VCYx +MCU_ST_STM32F3:STM32F302VDHx +MCU_ST_STM32F3:STM32F302VDTx +MCU_ST_STM32F3:STM32F302VEHx +MCU_ST_STM32F3:STM32F302VETx +MCU_ST_STM32F3:STM32F302V_B-C_Tx +MCU_ST_STM32F3:STM32F302V_D-E_Hx +MCU_ST_STM32F3:STM32F302V_D-E_Tx +MCU_ST_STM32F3:STM32F302ZDTx +MCU_ST_STM32F3:STM32F302ZETx +MCU_ST_STM32F3:STM32F302Z_D-E_Tx +MCU_ST_STM32F3:STM32F303C6Tx +MCU_ST_STM32F3:STM32F303C8Tx +MCU_ST_STM32F3:STM32F303C8Yx +MCU_ST_STM32F3:STM32F303CBTx +MCU_ST_STM32F3:STM32F303CCTx +MCU_ST_STM32F3:STM32F303C_6-8_Tx +MCU_ST_STM32F3:STM32F303C_B-C_Tx +MCU_ST_STM32F3:STM32F303K6Tx +MCU_ST_STM32F3:STM32F303K6Ux +MCU_ST_STM32F3:STM32F303K8Tx +MCU_ST_STM32F3:STM32F303K8Ux +MCU_ST_STM32F3:STM32F303K_6-8_Tx +MCU_ST_STM32F3:STM32F303K_6-8_Ux +MCU_ST_STM32F3:STM32F303R6Tx +MCU_ST_STM32F3:STM32F303R8Tx +MCU_ST_STM32F3:STM32F303RBTx +MCU_ST_STM32F3:STM32F303RCTx +MCU_ST_STM32F3:STM32F303RDTx +MCU_ST_STM32F3:STM32F303RETx +MCU_ST_STM32F3:STM32F303R_6-8_Tx +MCU_ST_STM32F3:STM32F303R_B-C_Tx +MCU_ST_STM32F3:STM32F303R_D-E_Tx +MCU_ST_STM32F3:STM32F303VBTx +MCU_ST_STM32F3:STM32F303VCTx +MCU_ST_STM32F3:STM32F303VCYx +MCU_ST_STM32F3:STM32F303VDHx +MCU_ST_STM32F3:STM32F303VDTx +MCU_ST_STM32F3:STM32F303VEHx +MCU_ST_STM32F3:STM32F303VETx +MCU_ST_STM32F3:STM32F303VEYx +MCU_ST_STM32F3:STM32F303V_B-C_Tx +MCU_ST_STM32F3:STM32F303V_D-E_Hx +MCU_ST_STM32F3:STM32F303V_D-E_Tx +MCU_ST_STM32F3:STM32F303ZDTx +MCU_ST_STM32F3:STM32F303ZETx +MCU_ST_STM32F3:STM32F303Z_D-E_Tx +MCU_ST_STM32F3:STM32F318C8Tx +MCU_ST_STM32F3:STM32F318C8Yx +MCU_ST_STM32F3:STM32F318K8Ux +MCU_ST_STM32F3:STM32F328C8Tx +MCU_ST_STM32F3:STM32F334C4Tx +MCU_ST_STM32F3:STM32F334C6Tx +MCU_ST_STM32F3:STM32F334C8Tx +MCU_ST_STM32F3:STM32F334C8Yx +MCU_ST_STM32F3:STM32F334C_4-6-8_Tx +MCU_ST_STM32F3:STM32F334K4Tx +MCU_ST_STM32F3:STM32F334K4Ux +MCU_ST_STM32F3:STM32F334K6Tx +MCU_ST_STM32F3:STM32F334K6Ux +MCU_ST_STM32F3:STM32F334K8Tx +MCU_ST_STM32F3:STM32F334K8Ux +MCU_ST_STM32F3:STM32F334K_4-6-8_Tx +MCU_ST_STM32F3:STM32F334K_4-6-8_Ux +MCU_ST_STM32F3:STM32F334R6Tx +MCU_ST_STM32F3:STM32F334R8Tx +MCU_ST_STM32F3:STM32F334R_6-8_Tx +MCU_ST_STM32F3:STM32F358CCTx +MCU_ST_STM32F3:STM32F358RCTx +MCU_ST_STM32F3:STM32F358VCTx +MCU_ST_STM32F3:STM32F373C8Tx +MCU_ST_STM32F3:STM32F373CBTx +MCU_ST_STM32F3:STM32F373CCTx +MCU_ST_STM32F3:STM32F373C_8-B-C_Tx +MCU_ST_STM32F3:STM32F373R8Tx +MCU_ST_STM32F3:STM32F373RBTx +MCU_ST_STM32F3:STM32F373RCTx +MCU_ST_STM32F3:STM32F373R_8-B-C_Tx +MCU_ST_STM32F3:STM32F373V8Hx +MCU_ST_STM32F3:STM32F373V8Tx +MCU_ST_STM32F3:STM32F373VBHx +MCU_ST_STM32F3:STM32F373VBTx +MCU_ST_STM32F3:STM32F373VCHx +MCU_ST_STM32F3:STM32F373VCTx +MCU_ST_STM32F3:STM32F373V_8-B-C_Hx +MCU_ST_STM32F3:STM32F373V_8-B-C_Tx +MCU_ST_STM32F3:STM32F378CCTx +MCU_ST_STM32F3:STM32F378RCTx +MCU_ST_STM32F3:STM32F378RCYx +MCU_ST_STM32F3:STM32F378VCHx +MCU_ST_STM32F3:STM32F378VCTx +MCU_ST_STM32F3:STM32F398VETx +MCU_ST_STM32F4:STM32F401CBUx +MCU_ST_STM32F4:STM32F401CBYx +MCU_ST_STM32F4:STM32F401CCFx +MCU_ST_STM32F4:STM32F401CCUx +MCU_ST_STM32F4:STM32F401CCYx +MCU_ST_STM32F4:STM32F401CDUx +MCU_ST_STM32F4:STM32F401CDYx +MCU_ST_STM32F4:STM32F401CEUx +MCU_ST_STM32F4:STM32F401CEYx +MCU_ST_STM32F4:STM32F401C_B-C_Ux +MCU_ST_STM32F4:STM32F401C_B-C_Yx +MCU_ST_STM32F4:STM32F401C_D-E_Ux +MCU_ST_STM32F4:STM32F401C_D-E_Yx +MCU_ST_STM32F4:STM32F401RBTx +MCU_ST_STM32F4:STM32F401RCTx +MCU_ST_STM32F4:STM32F401RDTx +MCU_ST_STM32F4:STM32F401RETx +MCU_ST_STM32F4:STM32F401R_B-C_Tx +MCU_ST_STM32F4:STM32F401R_D-E_Tx +MCU_ST_STM32F4:STM32F401VBHx +MCU_ST_STM32F4:STM32F401VBTx +MCU_ST_STM32F4:STM32F401VCHx +MCU_ST_STM32F4:STM32F401VCTx +MCU_ST_STM32F4:STM32F401VDHx +MCU_ST_STM32F4:STM32F401VDTx +MCU_ST_STM32F4:STM32F401VEHx +MCU_ST_STM32F4:STM32F401VETx +MCU_ST_STM32F4:STM32F401V_B-C_Hx +MCU_ST_STM32F4:STM32F401V_B-C_Tx +MCU_ST_STM32F4:STM32F401V_D-E_Hx +MCU_ST_STM32F4:STM32F401V_D-E_Tx +MCU_ST_STM32F4:STM32F405OEYx +MCU_ST_STM32F4:STM32F405OGYx +MCU_ST_STM32F4:STM32F405O_E-G_Yx +MCU_ST_STM32F4:STM32F405RGTx +MCU_ST_STM32F4:STM32F405VGTx +MCU_ST_STM32F4:STM32F405ZGTx +MCU_ST_STM32F4:STM32F407IEHx +MCU_ST_STM32F4:STM32F407IETx +MCU_ST_STM32F4:STM32F407IGHx +MCU_ST_STM32F4:STM32F407IGTx +MCU_ST_STM32F4:STM32F407I_E-G_Hx +MCU_ST_STM32F4:STM32F407I_E-G_Tx +MCU_ST_STM32F4:STM32F407VETx +MCU_ST_STM32F4:STM32F407VGTx +MCU_ST_STM32F4:STM32F407V_E-G_Tx +MCU_ST_STM32F4:STM32F407ZETx +MCU_ST_STM32F4:STM32F407ZGTx +MCU_ST_STM32F4:STM32F407Z_E-G_Tx +MCU_ST_STM32F4:STM32F410C8Tx +MCU_ST_STM32F4:STM32F410C8Ux +MCU_ST_STM32F4:STM32F410CBTx +MCU_ST_STM32F4:STM32F410CBUx +MCU_ST_STM32F4:STM32F410C_8-B_Tx +MCU_ST_STM32F4:STM32F410C_8-B_Ux +MCU_ST_STM32F4:STM32F410R8Ix +MCU_ST_STM32F4:STM32F410R8Tx +MCU_ST_STM32F4:STM32F410RBIx +MCU_ST_STM32F4:STM32F410RBTx +MCU_ST_STM32F4:STM32F410R_8-B_Ix +MCU_ST_STM32F4:STM32F410R_8-B_Tx +MCU_ST_STM32F4:STM32F410T8Yx +MCU_ST_STM32F4:STM32F410TBYx +MCU_ST_STM32F4:STM32F410T_8-B_Yx +MCU_ST_STM32F4:STM32F411CCUx +MCU_ST_STM32F4:STM32F411CCYx +MCU_ST_STM32F4:STM32F411CEUx +MCU_ST_STM32F4:STM32F411CEYx +MCU_ST_STM32F4:STM32F411C_C-E_Ux +MCU_ST_STM32F4:STM32F411C_C-E_Yx +MCU_ST_STM32F4:STM32F411RCTx +MCU_ST_STM32F4:STM32F411RETx +MCU_ST_STM32F4:STM32F411R_C-E_Tx +MCU_ST_STM32F4:STM32F411VCHx +MCU_ST_STM32F4:STM32F411VCTx +MCU_ST_STM32F4:STM32F411VEHx +MCU_ST_STM32F4:STM32F411VETx +MCU_ST_STM32F4:STM32F411V_C-E_Hx +MCU_ST_STM32F4:STM32F411V_C-E_Tx +MCU_ST_STM32F4:STM32F412CEUx +MCU_ST_STM32F4:STM32F412CGUx +MCU_ST_STM32F4:STM32F412C_E-G_Ux +MCU_ST_STM32F4:STM32F412RETx +MCU_ST_STM32F4:STM32F412REYx +MCU_ST_STM32F4:STM32F412REYxP +MCU_ST_STM32F4:STM32F412RGTx +MCU_ST_STM32F4:STM32F412RGYx +MCU_ST_STM32F4:STM32F412RGYxP +MCU_ST_STM32F4:STM32F412R_E-G_Tx +MCU_ST_STM32F4:STM32F412R_E-G_Yx +MCU_ST_STM32F4:STM32F412R_E-G_YxP +MCU_ST_STM32F4:STM32F412VEHx +MCU_ST_STM32F4:STM32F412VETx +MCU_ST_STM32F4:STM32F412VGHx +MCU_ST_STM32F4:STM32F412VGTx +MCU_ST_STM32F4:STM32F412V_E-G_Hx +MCU_ST_STM32F4:STM32F412V_E-G_Tx +MCU_ST_STM32F4:STM32F412ZEJx +MCU_ST_STM32F4:STM32F412ZETx +MCU_ST_STM32F4:STM32F412ZGJx +MCU_ST_STM32F4:STM32F412ZGTx +MCU_ST_STM32F4:STM32F412Z_E-G_Jx +MCU_ST_STM32F4:STM32F412Z_E-G_Tx +MCU_ST_STM32F4:STM32F413CGUx +MCU_ST_STM32F4:STM32F413CHUx +MCU_ST_STM32F4:STM32F413C_G-H_Ux +MCU_ST_STM32F4:STM32F413MGYx +MCU_ST_STM32F4:STM32F413MHYx +MCU_ST_STM32F4:STM32F413M_G-H_Yx +MCU_ST_STM32F4:STM32F413RGTx +MCU_ST_STM32F4:STM32F413RHTx +MCU_ST_STM32F4:STM32F413R_G-H_Tx +MCU_ST_STM32F4:STM32F413VGHx +MCU_ST_STM32F4:STM32F413VGTx +MCU_ST_STM32F4:STM32F413VHHx +MCU_ST_STM32F4:STM32F413VHTx +MCU_ST_STM32F4:STM32F413V_G-H_Hx +MCU_ST_STM32F4:STM32F413V_G-H_Tx +MCU_ST_STM32F4:STM32F413ZGJx +MCU_ST_STM32F4:STM32F413ZGTx +MCU_ST_STM32F4:STM32F413ZHJx +MCU_ST_STM32F4:STM32F413ZHTx +MCU_ST_STM32F4:STM32F413Z_G-H_Jx +MCU_ST_STM32F4:STM32F413Z_G-H_Tx +MCU_ST_STM32F4:STM32F415OGYx +MCU_ST_STM32F4:STM32F415RGTx +MCU_ST_STM32F4:STM32F415VGTx +MCU_ST_STM32F4:STM32F415ZGTx +MCU_ST_STM32F4:STM32F417IEHx +MCU_ST_STM32F4:STM32F417IETx +MCU_ST_STM32F4:STM32F417IGHx +MCU_ST_STM32F4:STM32F417IGTx +MCU_ST_STM32F4:STM32F417I_E-G_Hx +MCU_ST_STM32F4:STM32F417I_E-G_Tx +MCU_ST_STM32F4:STM32F417VETx +MCU_ST_STM32F4:STM32F417VGTx +MCU_ST_STM32F4:STM32F417V_E-G_Tx +MCU_ST_STM32F4:STM32F417ZETx +MCU_ST_STM32F4:STM32F417ZGTx +MCU_ST_STM32F4:STM32F417Z_E-G_Tx +MCU_ST_STM32F4:STM32F423CHUx +MCU_ST_STM32F4:STM32F423MHYx +MCU_ST_STM32F4:STM32F423RHTx +MCU_ST_STM32F4:STM32F423VHHx +MCU_ST_STM32F4:STM32F423VHTx +MCU_ST_STM32F4:STM32F423ZHJx +MCU_ST_STM32F4:STM32F423ZHTx +MCU_ST_STM32F4:STM32F427AGHx +MCU_ST_STM32F4:STM32F427AIHx +MCU_ST_STM32F4:STM32F427A_G-I_Hx +MCU_ST_STM32F4:STM32F427IGHx +MCU_ST_STM32F4:STM32F427IGTx +MCU_ST_STM32F4:STM32F427IIHx +MCU_ST_STM32F4:STM32F427IITx +MCU_ST_STM32F4:STM32F427I_G-I_Hx +MCU_ST_STM32F4:STM32F427I_G-I_Tx +MCU_ST_STM32F4:STM32F427VGTx +MCU_ST_STM32F4:STM32F427VITx +MCU_ST_STM32F4:STM32F427V_G-I_Tx +MCU_ST_STM32F4:STM32F427ZGTx +MCU_ST_STM32F4:STM32F427ZITx +MCU_ST_STM32F4:STM32F427Z_G-I_Tx +MCU_ST_STM32F4:STM32F429AGHx +MCU_ST_STM32F4:STM32F429AIHx +MCU_ST_STM32F4:STM32F429A_G-I_Hx +MCU_ST_STM32F4:STM32F429BETx +MCU_ST_STM32F4:STM32F429BGTx +MCU_ST_STM32F4:STM32F429BITx +MCU_ST_STM32F4:STM32F429B_E-G-I_Tx +MCU_ST_STM32F4:STM32F429IEHx +MCU_ST_STM32F4:STM32F429IETx +MCU_ST_STM32F4:STM32F429IGHx +MCU_ST_STM32F4:STM32F429IGTx +MCU_ST_STM32F4:STM32F429IIHx +MCU_ST_STM32F4:STM32F429IITx +MCU_ST_STM32F4:STM32F429I_E-G-I_Hx +MCU_ST_STM32F4:STM32F429I_E-G_Tx +MCU_ST_STM32F4:STM32F429NEHx +MCU_ST_STM32F4:STM32F429NGHx +MCU_ST_STM32F4:STM32F429NIHx +MCU_ST_STM32F4:STM32F429N_E-G_Hx +MCU_ST_STM32F4:STM32F429VETx +MCU_ST_STM32F4:STM32F429VGTx +MCU_ST_STM32F4:STM32F429VITx +MCU_ST_STM32F4:STM32F429V_E-G_Tx +MCU_ST_STM32F4:STM32F429ZETx +MCU_ST_STM32F4:STM32F429ZGTx +MCU_ST_STM32F4:STM32F429ZGYx +MCU_ST_STM32F4:STM32F429ZITx +MCU_ST_STM32F4:STM32F429ZIYx +MCU_ST_STM32F4:STM32F429Z_E-G_Tx +MCU_ST_STM32F4:STM32F437AIHx +MCU_ST_STM32F4:STM32F437IGHx +MCU_ST_STM32F4:STM32F437IGTx +MCU_ST_STM32F4:STM32F437IIHx +MCU_ST_STM32F4:STM32F437IITx +MCU_ST_STM32F4:STM32F437I_G-I_Hx +MCU_ST_STM32F4:STM32F437I_G-I_Tx +MCU_ST_STM32F4:STM32F437VGTx +MCU_ST_STM32F4:STM32F437VITx +MCU_ST_STM32F4:STM32F437V_G-I_Tx +MCU_ST_STM32F4:STM32F437ZGTx +MCU_ST_STM32F4:STM32F437ZITx +MCU_ST_STM32F4:STM32F437Z_G-I_Tx +MCU_ST_STM32F4:STM32F439AIHx +MCU_ST_STM32F4:STM32F439BGTx +MCU_ST_STM32F4:STM32F439BITx +MCU_ST_STM32F4:STM32F439B_G-I_Tx +MCU_ST_STM32F4:STM32F439IGHx +MCU_ST_STM32F4:STM32F439IGTx +MCU_ST_STM32F4:STM32F439IIHx +MCU_ST_STM32F4:STM32F439IITx +MCU_ST_STM32F4:STM32F439I_G-I_Hx +MCU_ST_STM32F4:STM32F439I_G-I_Tx +MCU_ST_STM32F4:STM32F439NGHx +MCU_ST_STM32F4:STM32F439NIHx +MCU_ST_STM32F4:STM32F439N_G-I_Hx +MCU_ST_STM32F4:STM32F439VGTx +MCU_ST_STM32F4:STM32F439VITx +MCU_ST_STM32F4:STM32F439V_G-I_Tx +MCU_ST_STM32F4:STM32F439ZGTx +MCU_ST_STM32F4:STM32F439ZGYx +MCU_ST_STM32F4:STM32F439ZITx +MCU_ST_STM32F4:STM32F439ZIYx +MCU_ST_STM32F4:STM32F439Z_G-I_Tx +MCU_ST_STM32F4:STM32F439Z_G-I_Yx +MCU_ST_STM32F4:STM32F446MCYx +MCU_ST_STM32F4:STM32F446MEYx +MCU_ST_STM32F4:STM32F446M_C-E_Yx +MCU_ST_STM32F4:STM32F446RCTx +MCU_ST_STM32F4:STM32F446RETx +MCU_ST_STM32F4:STM32F446R_C-E_Tx +MCU_ST_STM32F4:STM32F446VCTx +MCU_ST_STM32F4:STM32F446VETx +MCU_ST_STM32F4:STM32F446V_C-E_Tx +MCU_ST_STM32F4:STM32F446ZCHx +MCU_ST_STM32F4:STM32F446ZCJx +MCU_ST_STM32F4:STM32F446ZCTx +MCU_ST_STM32F4:STM32F446ZEHx +MCU_ST_STM32F4:STM32F446ZEJx +MCU_ST_STM32F4:STM32F446ZETx +MCU_ST_STM32F4:STM32F446Z_C-E_Hx +MCU_ST_STM32F4:STM32F446Z_C-E_Jx +MCU_ST_STM32F4:STM32F446Z_C-E_Tx +MCU_ST_STM32F4:STM32F469AEHx +MCU_ST_STM32F4:STM32F469AEYx +MCU_ST_STM32F4:STM32F469AGHx +MCU_ST_STM32F4:STM32F469AGYx +MCU_ST_STM32F4:STM32F469AIHx +MCU_ST_STM32F4:STM32F469AIYx +MCU_ST_STM32F4:STM32F469A_E-G-I_Hx +MCU_ST_STM32F4:STM32F469A_E-G-I_Yx +MCU_ST_STM32F4:STM32F469BETx +MCU_ST_STM32F4:STM32F469BGTx +MCU_ST_STM32F4:STM32F469BITx +MCU_ST_STM32F4:STM32F469B_E-G-I_Tx +MCU_ST_STM32F4:STM32F469IEHx +MCU_ST_STM32F4:STM32F469IETx +MCU_ST_STM32F4:STM32F469IGHx +MCU_ST_STM32F4:STM32F469IGTx +MCU_ST_STM32F4:STM32F469IIHx +MCU_ST_STM32F4:STM32F469IITx +MCU_ST_STM32F4:STM32F469I_E-G-I_Hx +MCU_ST_STM32F4:STM32F469I_E-G_Tx +MCU_ST_STM32F4:STM32F469NEHx +MCU_ST_STM32F4:STM32F469NGHx +MCU_ST_STM32F4:STM32F469NIHx +MCU_ST_STM32F4:STM32F469N_E-G_Hx +MCU_ST_STM32F4:STM32F469VETx +MCU_ST_STM32F4:STM32F469VGTx +MCU_ST_STM32F4:STM32F469VITx +MCU_ST_STM32F4:STM32F469V_E-G_Tx +MCU_ST_STM32F4:STM32F469ZETx +MCU_ST_STM32F4:STM32F469ZGTx +MCU_ST_STM32F4:STM32F469ZITx +MCU_ST_STM32F4:STM32F469Z_E-G_Tx +MCU_ST_STM32F4:STM32F479AGHx +MCU_ST_STM32F4:STM32F479AGYx +MCU_ST_STM32F4:STM32F479AIHx +MCU_ST_STM32F4:STM32F479AIYx +MCU_ST_STM32F4:STM32F479A_G-I_Hx +MCU_ST_STM32F4:STM32F479A_G-I_Yx +MCU_ST_STM32F4:STM32F479BGTx +MCU_ST_STM32F4:STM32F479BITx +MCU_ST_STM32F4:STM32F479B_G-I_Tx +MCU_ST_STM32F4:STM32F479IGHx +MCU_ST_STM32F4:STM32F479IGTx +MCU_ST_STM32F4:STM32F479IIHx +MCU_ST_STM32F4:STM32F479IITx +MCU_ST_STM32F4:STM32F479I_G-I_Hx +MCU_ST_STM32F4:STM32F479I_G-I_Tx +MCU_ST_STM32F4:STM32F479NGHx +MCU_ST_STM32F4:STM32F479NIHx +MCU_ST_STM32F4:STM32F479N_G-I_Hx +MCU_ST_STM32F4:STM32F479VGTx +MCU_ST_STM32F4:STM32F479VITx +MCU_ST_STM32F4:STM32F479V_G-I_Tx +MCU_ST_STM32F4:STM32F479ZGTx +MCU_ST_STM32F4:STM32F479ZITx +MCU_ST_STM32F4:STM32F479Z_G-I_Tx +MCU_ST_STM32F7:STM32F722ICKx +MCU_ST_STM32F7:STM32F722ICTx +MCU_ST_STM32F7:STM32F722IEKx +MCU_ST_STM32F7:STM32F722IETx +MCU_ST_STM32F7:STM32F722I_C-E_Kx +MCU_ST_STM32F7:STM32F722I_C-E_Tx +MCU_ST_STM32F7:STM32F722RCTx +MCU_ST_STM32F7:STM32F722RETx +MCU_ST_STM32F7:STM32F722R_C-E_Tx +MCU_ST_STM32F7:STM32F722VCTx +MCU_ST_STM32F7:STM32F722VETx +MCU_ST_STM32F7:STM32F722V_C-E_Tx +MCU_ST_STM32F7:STM32F722ZCTx +MCU_ST_STM32F7:STM32F722ZETx +MCU_ST_STM32F7:STM32F722Z_C-E_Tx +MCU_ST_STM32F7:STM32F723ICKx +MCU_ST_STM32F7:STM32F723ICTx +MCU_ST_STM32F7:STM32F723IEKx +MCU_ST_STM32F7:STM32F723IETx +MCU_ST_STM32F7:STM32F723I_C-E_Kx +MCU_ST_STM32F7:STM32F723I_C-E_Tx +MCU_ST_STM32F7:STM32F723VCTx +MCU_ST_STM32F7:STM32F723VCYx +MCU_ST_STM32F7:STM32F723VETx +MCU_ST_STM32F7:STM32F723VEYx +MCU_ST_STM32F7:STM32F723V_C-E_Tx +MCU_ST_STM32F7:STM32F723V_C-E_Yx +MCU_ST_STM32F7:STM32F723ZCIx +MCU_ST_STM32F7:STM32F723ZCTx +MCU_ST_STM32F7:STM32F723ZEIx +MCU_ST_STM32F7:STM32F723ZETx +MCU_ST_STM32F7:STM32F723Z_C-E_Ix +MCU_ST_STM32F7:STM32F723Z_C-E_Tx +MCU_ST_STM32F7:STM32F730I8Kx +MCU_ST_STM32F7:STM32F730R8Tx +MCU_ST_STM32F7:STM32F730V8Tx +MCU_ST_STM32F7:STM32F730Z8Tx +MCU_ST_STM32F7:STM32F732IEKx +MCU_ST_STM32F7:STM32F732IETx +MCU_ST_STM32F7:STM32F732RETx +MCU_ST_STM32F7:STM32F732VETx +MCU_ST_STM32F7:STM32F732ZETx +MCU_ST_STM32F7:STM32F733IEKx +MCU_ST_STM32F7:STM32F733IETx +MCU_ST_STM32F7:STM32F733VETx +MCU_ST_STM32F7:STM32F733VEYx +MCU_ST_STM32F7:STM32F733ZEIx +MCU_ST_STM32F7:STM32F733ZETx +MCU_ST_STM32F7:STM32F745IEKx +MCU_ST_STM32F7:STM32F745IETx +MCU_ST_STM32F7:STM32F745IGKx +MCU_ST_STM32F7:STM32F745IGTx +MCU_ST_STM32F7:STM32F745I_E-G_Kx +MCU_ST_STM32F7:STM32F745I_E-G_Tx +MCU_ST_STM32F7:STM32F745VEHx +MCU_ST_STM32F7:STM32F745VETx +MCU_ST_STM32F7:STM32F745VGHx +MCU_ST_STM32F7:STM32F745VGTx +MCU_ST_STM32F7:STM32F745V_E-G_Hx +MCU_ST_STM32F7:STM32F745V_E-G_Tx +MCU_ST_STM32F7:STM32F745ZETx +MCU_ST_STM32F7:STM32F745ZGTx +MCU_ST_STM32F7:STM32F745Z_E-G_Tx +MCU_ST_STM32F7:STM32F746BETx +MCU_ST_STM32F7:STM32F746BGTx +MCU_ST_STM32F7:STM32F746B_E-G_Tx +MCU_ST_STM32F7:STM32F746IEKx +MCU_ST_STM32F7:STM32F746IETx +MCU_ST_STM32F7:STM32F746IGKx +MCU_ST_STM32F7:STM32F746IGTx +MCU_ST_STM32F7:STM32F746I_E-G_Kx +MCU_ST_STM32F7:STM32F746NEHx +MCU_ST_STM32F7:STM32F746NGHx +MCU_ST_STM32F7:STM32F746VEHx +MCU_ST_STM32F7:STM32F746VETx +MCU_ST_STM32F7:STM32F746VGHx +MCU_ST_STM32F7:STM32F746VGTx +MCU_ST_STM32F7:STM32F746V_E-G_Hx +MCU_ST_STM32F7:STM32F746ZETx +MCU_ST_STM32F7:STM32F746ZEYx +MCU_ST_STM32F7:STM32F746ZGTx +MCU_ST_STM32F7:STM32F746ZGYx +MCU_ST_STM32F7:STM32F746Z_E-G_Yx +MCU_ST_STM32F7:STM32F750N8Hx +MCU_ST_STM32F7:STM32F750V8Tx +MCU_ST_STM32F7:STM32F750Z8Tx +MCU_ST_STM32F7:STM32F756BGTx +MCU_ST_STM32F7:STM32F756IGKx +MCU_ST_STM32F7:STM32F756IGTx +MCU_ST_STM32F7:STM32F756NGHx +MCU_ST_STM32F7:STM32F756VGHx +MCU_ST_STM32F7:STM32F756VGTx +MCU_ST_STM32F7:STM32F756ZGTx +MCU_ST_STM32F7:STM32F756ZGYx +MCU_ST_STM32F7:STM32F765BGTx +MCU_ST_STM32F7:STM32F765BITx +MCU_ST_STM32F7:STM32F765B_G-I_Tx +MCU_ST_STM32F7:STM32F765IGKx +MCU_ST_STM32F7:STM32F765IGTx +MCU_ST_STM32F7:STM32F765IIKx +MCU_ST_STM32F7:STM32F765IITx +MCU_ST_STM32F7:STM32F765I_G-I_Kx +MCU_ST_STM32F7:STM32F765I_G-I_Tx +MCU_ST_STM32F7:STM32F765NGHx +MCU_ST_STM32F7:STM32F765NIHx +MCU_ST_STM32F7:STM32F765N_G-I_Hx +MCU_ST_STM32F7:STM32F765VGHx +MCU_ST_STM32F7:STM32F765VGTx +MCU_ST_STM32F7:STM32F765VIHx +MCU_ST_STM32F7:STM32F765VITx +MCU_ST_STM32F7:STM32F765V_G-I_Hx +MCU_ST_STM32F7:STM32F765V_G-I_Tx +MCU_ST_STM32F7:STM32F765ZGTx +MCU_ST_STM32F7:STM32F765ZITx +MCU_ST_STM32F7:STM32F765Z_G-I_Tx +MCU_ST_STM32F7:STM32F767BGTx +MCU_ST_STM32F7:STM32F767BITx +MCU_ST_STM32F7:STM32F767B_G-I_Tx +MCU_ST_STM32F7:STM32F767IGKx +MCU_ST_STM32F7:STM32F767IGTx +MCU_ST_STM32F7:STM32F767IIKx +MCU_ST_STM32F7:STM32F767IITx +MCU_ST_STM32F7:STM32F767I_G-I_Kx +MCU_ST_STM32F7:STM32F767I_G-I_Tx +MCU_ST_STM32F7:STM32F767NGHx +MCU_ST_STM32F7:STM32F767NIHx +MCU_ST_STM32F7:STM32F767N_G-I_Hx +MCU_ST_STM32F7:STM32F767VGHx +MCU_ST_STM32F7:STM32F767VGTx +MCU_ST_STM32F7:STM32F767VIHx +MCU_ST_STM32F7:STM32F767VITx +MCU_ST_STM32F7:STM32F767ZGTx +MCU_ST_STM32F7:STM32F767ZITx +MCU_ST_STM32F7:STM32F768AIYx +MCU_ST_STM32F7:STM32F769AGYx +MCU_ST_STM32F7:STM32F769AIYx +MCU_ST_STM32F7:STM32F769A_G-I_Yx +MCU_ST_STM32F7:STM32F769BGTx +MCU_ST_STM32F7:STM32F769BITx +MCU_ST_STM32F7:STM32F769B_G-I_Tx +MCU_ST_STM32F7:STM32F769IGTx +MCU_ST_STM32F7:STM32F769IITx +MCU_ST_STM32F7:STM32F769NGHx +MCU_ST_STM32F7:STM32F769NIHx +MCU_ST_STM32F7:STM32F777BITx +MCU_ST_STM32F7:STM32F777IIKx +MCU_ST_STM32F7:STM32F777IITx +MCU_ST_STM32F7:STM32F777NIHx +MCU_ST_STM32F7:STM32F777VIHx +MCU_ST_STM32F7:STM32F777VITx +MCU_ST_STM32F7:STM32F777ZITx +MCU_ST_STM32F7:STM32F778AIYx +MCU_ST_STM32F7:STM32F779AIYx +MCU_ST_STM32F7:STM32F779BITx +MCU_ST_STM32F7:STM32F779IITx +MCU_ST_STM32F7:STM32F779NIHx +MCU_ST_STM32G0:STM32G030C6Tx +MCU_ST_STM32G0:STM32G030C8Tx +MCU_ST_STM32G0:STM32G030C_6-8_Tx +MCU_ST_STM32G0:STM32G030F6Px +MCU_ST_STM32G0:STM32G030J6Mx +MCU_ST_STM32G0:STM32G030K6Tx +MCU_ST_STM32G0:STM32G030K8Tx +MCU_ST_STM32G0:STM32G030K_6-8_Tx +MCU_ST_STM32G0:STM32G031C4Tx +MCU_ST_STM32G0:STM32G031C4Ux +MCU_ST_STM32G0:STM32G031C6Tx +MCU_ST_STM32G0:STM32G031C6Ux +MCU_ST_STM32G0:STM32G031C8Tx +MCU_ST_STM32G0:STM32G031C8Ux +MCU_ST_STM32G0:STM32G031C_4-6-8_Tx +MCU_ST_STM32G0:STM32G031C_4-6-8_Ux +MCU_ST_STM32G0:STM32G031F4Px +MCU_ST_STM32G0:STM32G031F6Px +MCU_ST_STM32G0:STM32G031F8Px +MCU_ST_STM32G0:STM32G031F_4-6-8_Px +MCU_ST_STM32G0:STM32G031G4Ux +MCU_ST_STM32G0:STM32G031G6Ux +MCU_ST_STM32G0:STM32G031G8Ux +MCU_ST_STM32G0:STM32G031G_4-6-8_Ux +MCU_ST_STM32G0:STM32G031J4Mx +MCU_ST_STM32G0:STM32G031J6Mx +MCU_ST_STM32G0:STM32G031J_4-6_Mx +MCU_ST_STM32G0:STM32G031K4Tx +MCU_ST_STM32G0:STM32G031K4Ux +MCU_ST_STM32G0:STM32G031K6Tx +MCU_ST_STM32G0:STM32G031K6Ux +MCU_ST_STM32G0:STM32G031K8Tx +MCU_ST_STM32G0:STM32G031K8Ux +MCU_ST_STM32G0:STM32G031K_4-6-8_Tx +MCU_ST_STM32G0:STM32G031K_4-6-8_Ux +MCU_ST_STM32G0:STM32G031Y8Yx +MCU_ST_STM32G0:STM32G041C6Tx +MCU_ST_STM32G0:STM32G041C6Ux +MCU_ST_STM32G0:STM32G041C8Tx +MCU_ST_STM32G0:STM32G041C8Ux +MCU_ST_STM32G0:STM32G041C_6-8_Tx +MCU_ST_STM32G0:STM32G041C_6-8_Ux +MCU_ST_STM32G0:STM32G041F6Px +MCU_ST_STM32G0:STM32G041F8Px +MCU_ST_STM32G0:STM32G041F_6-8_Px +MCU_ST_STM32G0:STM32G041G6Ux +MCU_ST_STM32G0:STM32G041G8Ux +MCU_ST_STM32G0:STM32G041G_6-8_Ux +MCU_ST_STM32G0:STM32G041J6Mx +MCU_ST_STM32G0:STM32G041K6Tx +MCU_ST_STM32G0:STM32G041K6Ux +MCU_ST_STM32G0:STM32G041K8Tx +MCU_ST_STM32G0:STM32G041K8Ux +MCU_ST_STM32G0:STM32G041K_6-8_Tx +MCU_ST_STM32G0:STM32G041K_6-8_Ux +MCU_ST_STM32G0:STM32G041Y8Yx +MCU_ST_STM32G0:STM32G050C6Tx +MCU_ST_STM32G0:STM32G050C8Tx +MCU_ST_STM32G0:STM32G050F6Px +MCU_ST_STM32G0:STM32G050K6Tx +MCU_ST_STM32G0:STM32G050K8Tx +MCU_ST_STM32G0:STM32G051C6Tx +MCU_ST_STM32G0:STM32G051C6Ux +MCU_ST_STM32G0:STM32G051C8Tx +MCU_ST_STM32G0:STM32G051C8Ux +MCU_ST_STM32G0:STM32G051C_6-8_Tx +MCU_ST_STM32G0:STM32G051C_6-8_Ux +MCU_ST_STM32G0:STM32G051F6Px +MCU_ST_STM32G0:STM32G051F8Px +MCU_ST_STM32G0:STM32G051F8Yx +MCU_ST_STM32G0:STM32G051F_6-8_Px +MCU_ST_STM32G0:STM32G051G6Ux +MCU_ST_STM32G0:STM32G051G8Ux +MCU_ST_STM32G0:STM32G051G_6-8_Ux +MCU_ST_STM32G0:STM32G051K6Tx +MCU_ST_STM32G0:STM32G051K6Ux +MCU_ST_STM32G0:STM32G051K8Tx +MCU_ST_STM32G0:STM32G051K8Ux +MCU_ST_STM32G0:STM32G051K_6-8_Tx +MCU_ST_STM32G0:STM32G051K_6-8_Ux +MCU_ST_STM32G0:STM32G061C6Tx +MCU_ST_STM32G0:STM32G061C6Ux +MCU_ST_STM32G0:STM32G061C8Tx +MCU_ST_STM32G0:STM32G061C8Ux +MCU_ST_STM32G0:STM32G061C_6-8_Tx +MCU_ST_STM32G0:STM32G061C_6-8_Ux +MCU_ST_STM32G0:STM32G061F6Px +MCU_ST_STM32G0:STM32G061F8Px +MCU_ST_STM32G0:STM32G061F8Yx +MCU_ST_STM32G0:STM32G061F_6-8_Px +MCU_ST_STM32G0:STM32G061G6Ux +MCU_ST_STM32G0:STM32G061G8Ux +MCU_ST_STM32G0:STM32G061G_6-8_Ux +MCU_ST_STM32G0:STM32G061K6Tx +MCU_ST_STM32G0:STM32G061K6Ux +MCU_ST_STM32G0:STM32G061K8Tx +MCU_ST_STM32G0:STM32G061K8Ux +MCU_ST_STM32G0:STM32G061K_6-8_Tx +MCU_ST_STM32G0:STM32G061K_6-8_Ux +MCU_ST_STM32G0:STM32G070CBTx +MCU_ST_STM32G0:STM32G070KBTx +MCU_ST_STM32G0:STM32G070RBTx +MCU_ST_STM32G0:STM32G071EBYx +MCU_ST_STM32G0:STM32G071G8UxN +MCU_ST_STM32G0:STM32G071GBUxN +MCU_ST_STM32G0:STM32G071G_8-B_UxN +MCU_ST_STM32G0:STM32G071K8TxN +MCU_ST_STM32G0:STM32G071K8UxN +MCU_ST_STM32G0:STM32G071KBTxN +MCU_ST_STM32G0:STM32G071KBUxN +MCU_ST_STM32G0:STM32G071K_8-B_TxN +MCU_ST_STM32G0:STM32G071K_8-B_UxN +MCU_ST_STM32G0:STM32G071RBIx +MCU_ST_STM32G0:STM32G081CBTx +MCU_ST_STM32G0:STM32G081CBUx +MCU_ST_STM32G0:STM32G081EBYx +MCU_ST_STM32G0:STM32G081GBUx +MCU_ST_STM32G0:STM32G081GBUxN +MCU_ST_STM32G0:STM32G081KBTx +MCU_ST_STM32G0:STM32G081KBTxN +MCU_ST_STM32G0:STM32G081KBUx +MCU_ST_STM32G0:STM32G081KBUxN +MCU_ST_STM32G0:STM32G081RBIx +MCU_ST_STM32G0:STM32G081RBTx +MCU_ST_STM32G0:STM32G0B0CETx +MCU_ST_STM32G0:STM32G0B0KETx +MCU_ST_STM32G0:STM32G0B0RETx +MCU_ST_STM32G0:STM32G0B0VETx +MCU_ST_STM32G0:STM32G0B1CBTx +MCU_ST_STM32G0:STM32G0B1CBTxN +MCU_ST_STM32G0:STM32G0B1CBUx +MCU_ST_STM32G0:STM32G0B1CBUxN +MCU_ST_STM32G0:STM32G0B1CCTx +MCU_ST_STM32G0:STM32G0B1CCTxN +MCU_ST_STM32G0:STM32G0B1CCUx +MCU_ST_STM32G0:STM32G0B1CCUxN +MCU_ST_STM32G0:STM32G0B1CETx +MCU_ST_STM32G0:STM32G0B1CETxN +MCU_ST_STM32G0:STM32G0B1CEUx +MCU_ST_STM32G0:STM32G0B1CEUxN +MCU_ST_STM32G0:STM32G0B1C_B-C-E_Tx +MCU_ST_STM32G0:STM32G0B1C_B-C-E_TxN +MCU_ST_STM32G0:STM32G0B1C_B-C-E_Ux +MCU_ST_STM32G0:STM32G0B1C_B-C-E_UxN +MCU_ST_STM32G0:STM32G0B1KBTx +MCU_ST_STM32G0:STM32G0B1KBTxN +MCU_ST_STM32G0:STM32G0B1KBUx +MCU_ST_STM32G0:STM32G0B1KBUxN +MCU_ST_STM32G0:STM32G0B1KCTx +MCU_ST_STM32G0:STM32G0B1KCTxN +MCU_ST_STM32G0:STM32G0B1KCUx +MCU_ST_STM32G0:STM32G0B1KCUxN +MCU_ST_STM32G0:STM32G0B1KETx +MCU_ST_STM32G0:STM32G0B1KETxN +MCU_ST_STM32G0:STM32G0B1KEUx +MCU_ST_STM32G0:STM32G0B1KEUxN +MCU_ST_STM32G0:STM32G0B1K_B-C-E_Tx +MCU_ST_STM32G0:STM32G0B1K_B-C-E_TxN +MCU_ST_STM32G0:STM32G0B1K_B-C-E_Ux +MCU_ST_STM32G0:STM32G0B1K_B-C-E_UxN +MCU_ST_STM32G0:STM32G0B1MBTx +MCU_ST_STM32G0:STM32G0B1MCTx +MCU_ST_STM32G0:STM32G0B1METx +MCU_ST_STM32G0:STM32G0B1M_B-C-E_Tx +MCU_ST_STM32G0:STM32G0B1NEYx +MCU_ST_STM32G0:STM32G0B1RBIxN +MCU_ST_STM32G0:STM32G0B1RBTx +MCU_ST_STM32G0:STM32G0B1RBTxN +MCU_ST_STM32G0:STM32G0B1RCIxN +MCU_ST_STM32G0:STM32G0B1RCTx +MCU_ST_STM32G0:STM32G0B1RCTxN +MCU_ST_STM32G0:STM32G0B1REIxN +MCU_ST_STM32G0:STM32G0B1RETx +MCU_ST_STM32G0:STM32G0B1RETxN +MCU_ST_STM32G0:STM32G0B1R_B-C-E_IxN +MCU_ST_STM32G0:STM32G0B1R_B-C-E_Tx +MCU_ST_STM32G0:STM32G0B1R_B-C-E_TxN +MCU_ST_STM32G0:STM32G0B1VBIx +MCU_ST_STM32G0:STM32G0B1VBTx +MCU_ST_STM32G0:STM32G0B1VCIx +MCU_ST_STM32G0:STM32G0B1VCTx +MCU_ST_STM32G0:STM32G0B1VEIx +MCU_ST_STM32G0:STM32G0B1VETx +MCU_ST_STM32G0:STM32G0B1V_B-C-E_Ix +MCU_ST_STM32G0:STM32G0B1V_B-C-E_Tx +MCU_ST_STM32G0:STM32G0C1CCTx +MCU_ST_STM32G0:STM32G0C1CCTxN +MCU_ST_STM32G0:STM32G0C1CCUx +MCU_ST_STM32G0:STM32G0C1CCUxN +MCU_ST_STM32G0:STM32G0C1CETx +MCU_ST_STM32G0:STM32G0C1CETxN +MCU_ST_STM32G0:STM32G0C1CEUx +MCU_ST_STM32G0:STM32G0C1CEUxN +MCU_ST_STM32G0:STM32G0C1C_C-E_Tx +MCU_ST_STM32G0:STM32G0C1C_C-E_TxN +MCU_ST_STM32G0:STM32G0C1C_C-E_Ux +MCU_ST_STM32G0:STM32G0C1C_C-E_UxN +MCU_ST_STM32G0:STM32G0C1KCTx +MCU_ST_STM32G0:STM32G0C1KCTxN +MCU_ST_STM32G0:STM32G0C1KCUx +MCU_ST_STM32G0:STM32G0C1KCUxN +MCU_ST_STM32G0:STM32G0C1KETx +MCU_ST_STM32G0:STM32G0C1KETxN +MCU_ST_STM32G0:STM32G0C1KEUx +MCU_ST_STM32G0:STM32G0C1KEUxN +MCU_ST_STM32G0:STM32G0C1K_C-E_Tx +MCU_ST_STM32G0:STM32G0C1K_C-E_TxN +MCU_ST_STM32G0:STM32G0C1K_C-E_Ux +MCU_ST_STM32G0:STM32G0C1K_C-E_UxN +MCU_ST_STM32G0:STM32G0C1MCTx +MCU_ST_STM32G0:STM32G0C1METx +MCU_ST_STM32G0:STM32G0C1M_C-E_Tx +MCU_ST_STM32G0:STM32G0C1NEYx +MCU_ST_STM32G0:STM32G0C1RCIxN +MCU_ST_STM32G0:STM32G0C1RCTx +MCU_ST_STM32G0:STM32G0C1RCTxN +MCU_ST_STM32G0:STM32G0C1REIxN +MCU_ST_STM32G0:STM32G0C1RETx +MCU_ST_STM32G0:STM32G0C1RETxN +MCU_ST_STM32G0:STM32G0C1R_C-E_IxN +MCU_ST_STM32G0:STM32G0C1R_C-E_Tx +MCU_ST_STM32G0:STM32G0C1R_C-E_TxN +MCU_ST_STM32G0:STM32G0C1VCIx +MCU_ST_STM32G0:STM32G0C1VCTx +MCU_ST_STM32G0:STM32G0C1VEIx +MCU_ST_STM32G0:STM32G0C1VETx +MCU_ST_STM32G0:STM32G0C1V_C-E_Ix +MCU_ST_STM32G0:STM32G0C1V_C-E_Tx +MCU_ST_STM32G4:STM32G431C6Tx +MCU_ST_STM32G4:STM32G431C6Ux +MCU_ST_STM32G4:STM32G431C8Tx +MCU_ST_STM32G4:STM32G431C8Ux +MCU_ST_STM32G4:STM32G431CBTx +MCU_ST_STM32G4:STM32G431CBTxZ +MCU_ST_STM32G4:STM32G431CBUx +MCU_ST_STM32G4:STM32G431CBYx +MCU_ST_STM32G4:STM32G431C_6-8-B_Tx +MCU_ST_STM32G4:STM32G431C_6-8-B_Ux +MCU_ST_STM32G4:STM32G431K6Tx +MCU_ST_STM32G4:STM32G431K6Ux +MCU_ST_STM32G4:STM32G431K8Tx +MCU_ST_STM32G4:STM32G431K8Ux +MCU_ST_STM32G4:STM32G431KBTx +MCU_ST_STM32G4:STM32G431KBUx +MCU_ST_STM32G4:STM32G431K_6-8-B_Tx +MCU_ST_STM32G4:STM32G431K_6-8-B_Ux +MCU_ST_STM32G4:STM32G431M6Tx +MCU_ST_STM32G4:STM32G431M8Tx +MCU_ST_STM32G4:STM32G431MBTx +MCU_ST_STM32G4:STM32G431M_6-8-B_Tx +MCU_ST_STM32G4:STM32G431R6Ix +MCU_ST_STM32G4:STM32G431R6Tx +MCU_ST_STM32G4:STM32G431R8Ix +MCU_ST_STM32G4:STM32G431R8Tx +MCU_ST_STM32G4:STM32G431RBIx +MCU_ST_STM32G4:STM32G431RBTx +MCU_ST_STM32G4:STM32G431RBTxZ +MCU_ST_STM32G4:STM32G431R_6-8-B_Ix +MCU_ST_STM32G4:STM32G431R_6-8-B_Tx +MCU_ST_STM32G4:STM32G431V6Tx +MCU_ST_STM32G4:STM32G431V8Tx +MCU_ST_STM32G4:STM32G431VBTx +MCU_ST_STM32G4:STM32G431V_6-8-B_Tx +MCU_ST_STM32G4:STM32G441CBTx +MCU_ST_STM32G4:STM32G441CBUx +MCU_ST_STM32G4:STM32G441CBYx +MCU_ST_STM32G4:STM32G441KBTx +MCU_ST_STM32G4:STM32G441KBUx +MCU_ST_STM32G4:STM32G441MBTx +MCU_ST_STM32G4:STM32G441RBIx +MCU_ST_STM32G4:STM32G441RBTx +MCU_ST_STM32G4:STM32G441VBTx +MCU_ST_STM32G4:STM32G473CBTx +MCU_ST_STM32G4:STM32G473CBUx +MCU_ST_STM32G4:STM32G473CCTx +MCU_ST_STM32G4:STM32G473CCUx +MCU_ST_STM32G4:STM32G473CETx +MCU_ST_STM32G4:STM32G473CEUx +MCU_ST_STM32G4:STM32G473C_B-C-E_Tx +MCU_ST_STM32G4:STM32G473C_B-C-E_Ux +MCU_ST_STM32G4:STM32G473MBTx +MCU_ST_STM32G4:STM32G473MCTx +MCU_ST_STM32G4:STM32G473METx +MCU_ST_STM32G4:STM32G473MEYx +MCU_ST_STM32G4:STM32G473M_B-C-E_Tx +MCU_ST_STM32G4:STM32G473PBIx +MCU_ST_STM32G4:STM32G473PCIx +MCU_ST_STM32G4:STM32G473PEIx +MCU_ST_STM32G4:STM32G473P_B-C-E_Ix +MCU_ST_STM32G4:STM32G473QBTx +MCU_ST_STM32G4:STM32G473QCTx +MCU_ST_STM32G4:STM32G473QETx +MCU_ST_STM32G4:STM32G473QETxZ +MCU_ST_STM32G4:STM32G473Q_B-C-E_Tx +MCU_ST_STM32G4:STM32G473RBTx +MCU_ST_STM32G4:STM32G473RCTx +MCU_ST_STM32G4:STM32G473RETx +MCU_ST_STM32G4:STM32G473RETxZ +MCU_ST_STM32G4:STM32G473R_B-C-E_Tx +MCU_ST_STM32G4:STM32G473VBHx +MCU_ST_STM32G4:STM32G473VBTx +MCU_ST_STM32G4:STM32G473VCHx +MCU_ST_STM32G4:STM32G473VCTx +MCU_ST_STM32G4:STM32G473VEHx +MCU_ST_STM32G4:STM32G473VETx +MCU_ST_STM32G4:STM32G473V_B-C-E_Hx +MCU_ST_STM32G4:STM32G473V_B-C-E_Tx +MCU_ST_STM32G4:STM32G474CBTx +MCU_ST_STM32G4:STM32G474CBUx +MCU_ST_STM32G4:STM32G474CCTx +MCU_ST_STM32G4:STM32G474CCUx +MCU_ST_STM32G4:STM32G474CETx +MCU_ST_STM32G4:STM32G474CEUx +MCU_ST_STM32G4:STM32G474C_B-C-E_Tx +MCU_ST_STM32G4:STM32G474C_B-C-E_Ux +MCU_ST_STM32G4:STM32G474MBTx +MCU_ST_STM32G4:STM32G474MCTx +MCU_ST_STM32G4:STM32G474METx +MCU_ST_STM32G4:STM32G474MEYx +MCU_ST_STM32G4:STM32G474M_B-C-E_Tx +MCU_ST_STM32G4:STM32G474PBIx +MCU_ST_STM32G4:STM32G474PCIx +MCU_ST_STM32G4:STM32G474PEIx +MCU_ST_STM32G4:STM32G474P_B-C-E_Ix +MCU_ST_STM32G4:STM32G474QBTx +MCU_ST_STM32G4:STM32G474QCTx +MCU_ST_STM32G4:STM32G474QETx +MCU_ST_STM32G4:STM32G474Q_B-C-E_Tx +MCU_ST_STM32G4:STM32G474RBTx +MCU_ST_STM32G4:STM32G474RCTx +MCU_ST_STM32G4:STM32G474RETx +MCU_ST_STM32G4:STM32G474R_B-C-E_Tx +MCU_ST_STM32G4:STM32G474VBHx +MCU_ST_STM32G4:STM32G474VBTx +MCU_ST_STM32G4:STM32G474VCHx +MCU_ST_STM32G4:STM32G474VCTx +MCU_ST_STM32G4:STM32G474VEHx +MCU_ST_STM32G4:STM32G474VETx +MCU_ST_STM32G4:STM32G474V_B-C-E_Hx +MCU_ST_STM32G4:STM32G474V_B-C-E_Tx +MCU_ST_STM32G4:STM32G483CETx +MCU_ST_STM32G4:STM32G483CEUx +MCU_ST_STM32G4:STM32G483METx +MCU_ST_STM32G4:STM32G483MEYx +MCU_ST_STM32G4:STM32G483PEIx +MCU_ST_STM32G4:STM32G483QETx +MCU_ST_STM32G4:STM32G483RETx +MCU_ST_STM32G4:STM32G483VEHx +MCU_ST_STM32G4:STM32G483VETx +MCU_ST_STM32G4:STM32G484CETx +MCU_ST_STM32G4:STM32G484CEUx +MCU_ST_STM32G4:STM32G484METx +MCU_ST_STM32G4:STM32G484MEYx +MCU_ST_STM32G4:STM32G484PEIx +MCU_ST_STM32G4:STM32G484QETx +MCU_ST_STM32G4:STM32G484RETx +MCU_ST_STM32G4:STM32G484VEHx +MCU_ST_STM32G4:STM32G484VETx +MCU_ST_STM32G4:STM32G491CCTx +MCU_ST_STM32G4:STM32G491CCUx +MCU_ST_STM32G4:STM32G491CETx +MCU_ST_STM32G4:STM32G491CEUx +MCU_ST_STM32G4:STM32G491C_C-E_Tx +MCU_ST_STM32G4:STM32G491C_C-E_Ux +MCU_ST_STM32G4:STM32G491KCUx +MCU_ST_STM32G4:STM32G491KEUx +MCU_ST_STM32G4:STM32G491K_C-E_Ux +MCU_ST_STM32G4:STM32G491MCSx +MCU_ST_STM32G4:STM32G491MCTx +MCU_ST_STM32G4:STM32G491MESx +MCU_ST_STM32G4:STM32G491METx +MCU_ST_STM32G4:STM32G491M_C-E_Sx +MCU_ST_STM32G4:STM32G491M_C-E_Tx +MCU_ST_STM32G4:STM32G491RCIx +MCU_ST_STM32G4:STM32G491RCTx +MCU_ST_STM32G4:STM32G491REIx +MCU_ST_STM32G4:STM32G491RETx +MCU_ST_STM32G4:STM32G491RETxZ +MCU_ST_STM32G4:STM32G491REYx +MCU_ST_STM32G4:STM32G491R_C-E_Ix +MCU_ST_STM32G4:STM32G491R_C-E_Tx +MCU_ST_STM32G4:STM32G491VCTx +MCU_ST_STM32G4:STM32G491VETx +MCU_ST_STM32G4:STM32G491V_C-E_Tx +MCU_ST_STM32G4:STM32G4A1CETx +MCU_ST_STM32G4:STM32G4A1CEUx +MCU_ST_STM32G4:STM32G4A1KEUx +MCU_ST_STM32G4:STM32G4A1MESx +MCU_ST_STM32G4:STM32G4A1METx +MCU_ST_STM32G4:STM32G4A1REIx +MCU_ST_STM32G4:STM32G4A1RETx +MCU_ST_STM32G4:STM32G4A1REYx +MCU_ST_STM32G4:STM32G4A1VETx +MCU_ST_STM32H5:STM32H503CBTx +MCU_ST_STM32H5:STM32H503CBUx +MCU_ST_STM32H5:STM32H503EBYx +MCU_ST_STM32H5:STM32H503KBUx +MCU_ST_STM32H5:STM32H503RBTx +MCU_ST_STM32H5:STM32H523CCTx +MCU_ST_STM32H5:STM32H523CCUx +MCU_ST_STM32H5:STM32H523CETx +MCU_ST_STM32H5:STM32H523CEUx +MCU_ST_STM32H5:STM32H523RCTx +MCU_ST_STM32H5:STM32H523RETx +MCU_ST_STM32H5:STM32H523VCIx +MCU_ST_STM32H5:STM32H523VCTx +MCU_ST_STM32H5:STM32H523VEIx +MCU_ST_STM32H5:STM32H523VETx +MCU_ST_STM32H5:STM32H523ZCJx +MCU_ST_STM32H5:STM32H523ZCTx +MCU_ST_STM32H5:STM32H523ZEJx +MCU_ST_STM32H5:STM32H523ZETx +MCU_ST_STM32H5:STM32H533CETx +MCU_ST_STM32H5:STM32H533CEUx +MCU_ST_STM32H5:STM32H533RETx +MCU_ST_STM32H5:STM32H533VEIx +MCU_ST_STM32H5:STM32H533VETx +MCU_ST_STM32H5:STM32H533ZEJx +MCU_ST_STM32H5:STM32H533ZETx +MCU_ST_STM32H5:STM32H562AGIx +MCU_ST_STM32H5:STM32H562AIIx +MCU_ST_STM32H5:STM32H562IGKx +MCU_ST_STM32H5:STM32H562IGTx +MCU_ST_STM32H5:STM32H562IIKx +MCU_ST_STM32H5:STM32H562IITx +MCU_ST_STM32H5:STM32H562RGTx +MCU_ST_STM32H5:STM32H562RGVx +MCU_ST_STM32H5:STM32H562RITx +MCU_ST_STM32H5:STM32H562RIVx +MCU_ST_STM32H5:STM32H562VGTx +MCU_ST_STM32H5:STM32H562VITx +MCU_ST_STM32H5:STM32H562ZGTx +MCU_ST_STM32H5:STM32H562ZITx +MCU_ST_STM32H5:STM32H563AGIx +MCU_ST_STM32H5:STM32H563AIIx +MCU_ST_STM32H5:STM32H563AIIxQ +MCU_ST_STM32H5:STM32H563IGKx +MCU_ST_STM32H5:STM32H563IGTx +MCU_ST_STM32H5:STM32H563IIKx +MCU_ST_STM32H5:STM32H563IIKxQ +MCU_ST_STM32H5:STM32H563IITx +MCU_ST_STM32H5:STM32H563IITxQ +MCU_ST_STM32H5:STM32H563MIYxQ +MCU_ST_STM32H5:STM32H563RGTx +MCU_ST_STM32H5:STM32H563RGVx +MCU_ST_STM32H5:STM32H563RITx +MCU_ST_STM32H5:STM32H563RIVx +MCU_ST_STM32H5:STM32H563VGTx +MCU_ST_STM32H5:STM32H563VITx +MCU_ST_STM32H5:STM32H563VITxQ +MCU_ST_STM32H5:STM32H563ZGTx +MCU_ST_STM32H5:STM32H563ZITx +MCU_ST_STM32H5:STM32H563ZITxQ +MCU_ST_STM32H5:STM32H573AIIx +MCU_ST_STM32H5:STM32H573AIIxQ +MCU_ST_STM32H5:STM32H573IIKx +MCU_ST_STM32H5:STM32H573IIKxQ +MCU_ST_STM32H5:STM32H573IITx +MCU_ST_STM32H5:STM32H573IITxQ +MCU_ST_STM32H5:STM32H573MIYxQ +MCU_ST_STM32H5:STM32H573RITx +MCU_ST_STM32H5:STM32H573RIVx +MCU_ST_STM32H5:STM32H573VITx +MCU_ST_STM32H5:STM32H573VITxQ +MCU_ST_STM32H5:STM32H573ZITx +MCU_ST_STM32H5:STM32H573ZITxQ +MCU_ST_STM32H7:STM32H723VEHx +MCU_ST_STM32H7:STM32H723VETx +MCU_ST_STM32H7:STM32H723VGHx +MCU_ST_STM32H7:STM32H723VGTx +MCU_ST_STM32H7:STM32H723ZEIx +MCU_ST_STM32H7:STM32H723ZETx +MCU_ST_STM32H7:STM32H723ZGIx +MCU_ST_STM32H7:STM32H723ZGTx +MCU_ST_STM32H7:STM32H725AEIx +MCU_ST_STM32H7:STM32H725AGIx +MCU_ST_STM32H7:STM32H725IEKx +MCU_ST_STM32H7:STM32H725IETx +MCU_ST_STM32H7:STM32H725IGKx +MCU_ST_STM32H7:STM32H725IGTx +MCU_ST_STM32H7:STM32H725REVx +MCU_ST_STM32H7:STM32H725RGVx +MCU_ST_STM32H7:STM32H725VEHx +MCU_ST_STM32H7:STM32H725VETx +MCU_ST_STM32H7:STM32H725VGHx +MCU_ST_STM32H7:STM32H725VGTx +MCU_ST_STM32H7:STM32H725VGYx +MCU_ST_STM32H7:STM32H725ZETx +MCU_ST_STM32H7:STM32H725ZGTx +MCU_ST_STM32H7:STM32H730ABIxQ +MCU_ST_STM32H7:STM32H730IBKxQ +MCU_ST_STM32H7:STM32H730IBTxQ +MCU_ST_STM32H7:STM32H730VBHx +MCU_ST_STM32H7:STM32H730VBTx +MCU_ST_STM32H7:STM32H730ZBIx +MCU_ST_STM32H7:STM32H730ZBTx +MCU_ST_STM32H7:STM32H733VGHx +MCU_ST_STM32H7:STM32H733VGTx +MCU_ST_STM32H7:STM32H733ZGIx +MCU_ST_STM32H7:STM32H733ZGTx +MCU_ST_STM32H7:STM32H735AGIx +MCU_ST_STM32H7:STM32H735IGKx +MCU_ST_STM32H7:STM32H735IGTx +MCU_ST_STM32H7:STM32H735RGVx +MCU_ST_STM32H7:STM32H735VGHx +MCU_ST_STM32H7:STM32H735VGTx +MCU_ST_STM32H7:STM32H735VGYx +MCU_ST_STM32H7:STM32H735ZGTx +MCU_ST_STM32H7:STM32H742AGIx +MCU_ST_STM32H7:STM32H742AIIx +MCU_ST_STM32H7:STM32H742A_G-I_Ix +MCU_ST_STM32H7:STM32H742BGTx +MCU_ST_STM32H7:STM32H742BITx +MCU_ST_STM32H7:STM32H742B_G-I_Tx +MCU_ST_STM32H7:STM32H742IGKx +MCU_ST_STM32H7:STM32H742IGTx +MCU_ST_STM32H7:STM32H742IIKx +MCU_ST_STM32H7:STM32H742IITx +MCU_ST_STM32H7:STM32H742I_G-I_Kx +MCU_ST_STM32H7:STM32H742I_G-I_Tx +MCU_ST_STM32H7:STM32H742VGHx +MCU_ST_STM32H7:STM32H742VGTx +MCU_ST_STM32H7:STM32H742VIHx +MCU_ST_STM32H7:STM32H742VITx +MCU_ST_STM32H7:STM32H742V_G-I_Hx +MCU_ST_STM32H7:STM32H742V_G-I_Tx +MCU_ST_STM32H7:STM32H742XGHx +MCU_ST_STM32H7:STM32H742XIHx +MCU_ST_STM32H7:STM32H742X_G-I_Hx +MCU_ST_STM32H7:STM32H742ZGTx +MCU_ST_STM32H7:STM32H742ZITx +MCU_ST_STM32H7:STM32H742Z_G-I_Tx +MCU_ST_STM32H7:STM32H743AGIx +MCU_ST_STM32H7:STM32H743AIIx +MCU_ST_STM32H7:STM32H743A_G-I_Ix +MCU_ST_STM32H7:STM32H743BGTx +MCU_ST_STM32H7:STM32H743BITx +MCU_ST_STM32H7:STM32H743IGKx +MCU_ST_STM32H7:STM32H743IGTx +MCU_ST_STM32H7:STM32H743IIKx +MCU_ST_STM32H7:STM32H743IITx +MCU_ST_STM32H7:STM32H743VGHx +MCU_ST_STM32H7:STM32H743VGTx +MCU_ST_STM32H7:STM32H743VIHx +MCU_ST_STM32H7:STM32H743VITx +MCU_ST_STM32H7:STM32H743V_G-I_Hx +MCU_ST_STM32H7:STM32H743XGHx +MCU_ST_STM32H7:STM32H743XIHx +MCU_ST_STM32H7:STM32H743ZGTx +MCU_ST_STM32H7:STM32H743ZITx +MCU_ST_STM32H7:STM32H745BGTx +MCU_ST_STM32H7:STM32H745BITx +MCU_ST_STM32H7:STM32H745IGKx +MCU_ST_STM32H7:STM32H745IGTx +MCU_ST_STM32H7:STM32H745IIKx +MCU_ST_STM32H7:STM32H745IITx +MCU_ST_STM32H7:STM32H745XGHx +MCU_ST_STM32H7:STM32H745XIHx +MCU_ST_STM32H7:STM32H745ZGTx +MCU_ST_STM32H7:STM32H745ZITx +MCU_ST_STM32H7:STM32H747AGIx +MCU_ST_STM32H7:STM32H747AIIx +MCU_ST_STM32H7:STM32H747A_G-I_Ix +MCU_ST_STM32H7:STM32H747BGTx +MCU_ST_STM32H7:STM32H747BITx +MCU_ST_STM32H7:STM32H747IGTx +MCU_ST_STM32H7:STM32H747IITx +MCU_ST_STM32H7:STM32H747XGHx +MCU_ST_STM32H7:STM32H747XIHx +MCU_ST_STM32H7:STM32H747ZIYx +MCU_ST_STM32H7:STM32H750IBKx +MCU_ST_STM32H7:STM32H750IBTx +MCU_ST_STM32H7:STM32H750VBTx +MCU_ST_STM32H7:STM32H750XBHx +MCU_ST_STM32H7:STM32H750ZBTx +MCU_ST_STM32H7:STM32H753AIIx +MCU_ST_STM32H7:STM32H753BITx +MCU_ST_STM32H7:STM32H753IIKx +MCU_ST_STM32H7:STM32H753IITx +MCU_ST_STM32H7:STM32H753VIHx +MCU_ST_STM32H7:STM32H753VITx +MCU_ST_STM32H7:STM32H753XIHx +MCU_ST_STM32H7:STM32H753ZITx +MCU_ST_STM32H7:STM32H755BITx +MCU_ST_STM32H7:STM32H755IIKx +MCU_ST_STM32H7:STM32H755IITx +MCU_ST_STM32H7:STM32H755XIHx +MCU_ST_STM32H7:STM32H755ZITx +MCU_ST_STM32H7:STM32H757AIIx +MCU_ST_STM32H7:STM32H757BITx +MCU_ST_STM32H7:STM32H757IITx +MCU_ST_STM32H7:STM32H757XIHx +MCU_ST_STM32H7:STM32H757ZIYx +MCU_ST_STM32H7:STM32H7A3AGIxQ +MCU_ST_STM32H7:STM32H7A3AIIxQ +MCU_ST_STM32H7:STM32H7A3A_G-I_IxQ +MCU_ST_STM32H7:STM32H7A3IGKx +MCU_ST_STM32H7:STM32H7A3IGKxQ +MCU_ST_STM32H7:STM32H7A3IGTx +MCU_ST_STM32H7:STM32H7A3IGTxQ +MCU_ST_STM32H7:STM32H7A3IIKx +MCU_ST_STM32H7:STM32H7A3IIKxQ +MCU_ST_STM32H7:STM32H7A3IITx +MCU_ST_STM32H7:STM32H7A3IITxQ +MCU_ST_STM32H7:STM32H7A3I_G-I_Kx +MCU_ST_STM32H7:STM32H7A3I_G-I_KxQ +MCU_ST_STM32H7:STM32H7A3I_G-I_Tx +MCU_ST_STM32H7:STM32H7A3I_G-I_TxQ +MCU_ST_STM32H7:STM32H7A3LGHxQ +MCU_ST_STM32H7:STM32H7A3LIHxQ +MCU_ST_STM32H7:STM32H7A3L_G-I_HxQ +MCU_ST_STM32H7:STM32H7A3NGHx +MCU_ST_STM32H7:STM32H7A3NIHx +MCU_ST_STM32H7:STM32H7A3N_G-I_Hx +MCU_ST_STM32H7:STM32H7A3QIYxQ +MCU_ST_STM32H7:STM32H7A3RGTx +MCU_ST_STM32H7:STM32H7A3RITx +MCU_ST_STM32H7:STM32H7A3R_G-I_Tx +MCU_ST_STM32H7:STM32H7A3VGHx +MCU_ST_STM32H7:STM32H7A3VGHxQ +MCU_ST_STM32H7:STM32H7A3VGTx +MCU_ST_STM32H7:STM32H7A3VGTxQ +MCU_ST_STM32H7:STM32H7A3VIHx +MCU_ST_STM32H7:STM32H7A3VIHxQ +MCU_ST_STM32H7:STM32H7A3VITx +MCU_ST_STM32H7:STM32H7A3VITxQ +MCU_ST_STM32H7:STM32H7A3V_G-I_Hx +MCU_ST_STM32H7:STM32H7A3V_G-I_HxQ +MCU_ST_STM32H7:STM32H7A3V_G-I_Tx +MCU_ST_STM32H7:STM32H7A3V_G-I_TxQ +MCU_ST_STM32H7:STM32H7A3ZGTx +MCU_ST_STM32H7:STM32H7A3ZGTxQ +MCU_ST_STM32H7:STM32H7A3ZITx +MCU_ST_STM32H7:STM32H7A3ZITxQ +MCU_ST_STM32H7:STM32H7A3Z_G-I_Tx +MCU_ST_STM32H7:STM32H7A3Z_G-I_TxQ +MCU_ST_STM32H7:STM32H7B0ABIxQ +MCU_ST_STM32H7:STM32H7B0IBKxQ +MCU_ST_STM32H7:STM32H7B0IBTx +MCU_ST_STM32H7:STM32H7B0RBTx +MCU_ST_STM32H7:STM32H7B0VBTx +MCU_ST_STM32H7:STM32H7B0ZBTx +MCU_ST_STM32H7:STM32H7B3AIIxQ +MCU_ST_STM32H7:STM32H7B3IIKx +MCU_ST_STM32H7:STM32H7B3IIKxQ +MCU_ST_STM32H7:STM32H7B3IITx +MCU_ST_STM32H7:STM32H7B3IITxQ +MCU_ST_STM32H7:STM32H7B3LIHxQ +MCU_ST_STM32H7:STM32H7B3NIHx +MCU_ST_STM32H7:STM32H7B3QIYxQ +MCU_ST_STM32H7:STM32H7B3RITx +MCU_ST_STM32H7:STM32H7B3VIHx +MCU_ST_STM32H7:STM32H7B3VIHxQ +MCU_ST_STM32H7:STM32H7B3VITx +MCU_ST_STM32H7:STM32H7B3VITxQ +MCU_ST_STM32H7:STM32H7B3ZITx +MCU_ST_STM32H7:STM32H7B3ZITxQ +MCU_ST_STM32H7:STM32H7R3A8Ix +MCU_ST_STM32H7:STM32H7R3I8Kx +MCU_ST_STM32H7:STM32H7R3I8Tx +MCU_ST_STM32H7:STM32H7R3L8Hx +MCU_ST_STM32H7:STM32H7R3L8HxH +MCU_ST_STM32H7:STM32H7R3R8Vx +MCU_ST_STM32H7:STM32H7R3V8Hx +MCU_ST_STM32H7:STM32H7R3V8Tx +MCU_ST_STM32H7:STM32H7R3V8Yx +MCU_ST_STM32H7:STM32H7R3Z8Jx +MCU_ST_STM32H7:STM32H7R3Z8Tx +MCU_ST_STM32H7:STM32H7R7A8Ix +MCU_ST_STM32H7:STM32H7R7I8Kx +MCU_ST_STM32H7:STM32H7R7I8Tx +MCU_ST_STM32H7:STM32H7R7L8Hx +MCU_ST_STM32H7:STM32H7R7L8HxH +MCU_ST_STM32H7:STM32H7R7Z8Jx +MCU_ST_STM32H7:STM32H7S3A8Ix +MCU_ST_STM32H7:STM32H7S3I8Kx +MCU_ST_STM32H7:STM32H7S3I8Tx +MCU_ST_STM32H7:STM32H7S3L8Hx +MCU_ST_STM32H7:STM32H7S3L8HxH +MCU_ST_STM32H7:STM32H7S3R8Vx +MCU_ST_STM32H7:STM32H7S3V8Hx +MCU_ST_STM32H7:STM32H7S3V8Tx +MCU_ST_STM32H7:STM32H7S3V8Yx +MCU_ST_STM32H7:STM32H7S3Z8Jx +MCU_ST_STM32H7:STM32H7S3Z8Tx +MCU_ST_STM32H7:STM32H7S7A8Ix +MCU_ST_STM32H7:STM32H7S7I8Kx +MCU_ST_STM32H7:STM32H7S7I8Tx +MCU_ST_STM32H7:STM32H7S7L8Hx +MCU_ST_STM32H7:STM32H7S7L8HxH +MCU_ST_STM32H7:STM32H7S7Z8Jx +MCU_ST_STM32L0:STM32L010C6Tx +MCU_ST_STM32L0:STM32L010F4Px +MCU_ST_STM32L0:STM32L010K4Tx +MCU_ST_STM32L0:STM32L010K8Tx +MCU_ST_STM32L0:STM32L010R8Tx +MCU_ST_STM32L0:STM32L010RBTx +MCU_ST_STM32L0:STM32L011D3Px +MCU_ST_STM32L0:STM32L011D4Px +MCU_ST_STM32L0:STM32L011D_3-4_Px +MCU_ST_STM32L0:STM32L011E3Yx +MCU_ST_STM32L0:STM32L011E4Yx +MCU_ST_STM32L0:STM32L011E_3-4_Yx +MCU_ST_STM32L0:STM32L011F3Px +MCU_ST_STM32L0:STM32L011F3Ux +MCU_ST_STM32L0:STM32L011F4Px +MCU_ST_STM32L0:STM32L011F4Ux +MCU_ST_STM32L0:STM32L011F_3-4_Px +MCU_ST_STM32L0:STM32L011F_3-4_Ux +MCU_ST_STM32L0:STM32L011G3Ux +MCU_ST_STM32L0:STM32L011G4Ux +MCU_ST_STM32L0:STM32L011G_3-4_Ux +MCU_ST_STM32L0:STM32L011K3Tx +MCU_ST_STM32L0:STM32L011K3Ux +MCU_ST_STM32L0:STM32L011K4Tx +MCU_ST_STM32L0:STM32L011K4Ux +MCU_ST_STM32L0:STM32L011K_3-4_Tx +MCU_ST_STM32L0:STM32L011K_3-4_Ux +MCU_ST_STM32L0:STM32L021D4Px +MCU_ST_STM32L0:STM32L021F4Px +MCU_ST_STM32L0:STM32L021F4Ux +MCU_ST_STM32L0:STM32L021G4Ux +MCU_ST_STM32L0:STM32L021K4Tx +MCU_ST_STM32L0:STM32L021K4Ux +MCU_ST_STM32L0:STM32L031C4Tx +MCU_ST_STM32L0:STM32L031C4Ux +MCU_ST_STM32L0:STM32L031C6Tx +MCU_ST_STM32L0:STM32L031C6Ux +MCU_ST_STM32L0:STM32L031C_4-6_Tx +MCU_ST_STM32L0:STM32L031C_4-6_Ux +MCU_ST_STM32L0:STM32L031E4Yx +MCU_ST_STM32L0:STM32L031E6Yx +MCU_ST_STM32L0:STM32L031E_4-6_Yx +MCU_ST_STM32L0:STM32L031F4Px +MCU_ST_STM32L0:STM32L031F6Px +MCU_ST_STM32L0:STM32L031F_4-6_Px +MCU_ST_STM32L0:STM32L031G4Ux +MCU_ST_STM32L0:STM32L031G6Ux +MCU_ST_STM32L0:STM32L031G6UxS +MCU_ST_STM32L0:STM32L031G_4-6_Ux +MCU_ST_STM32L0:STM32L031K4Tx +MCU_ST_STM32L0:STM32L031K4Ux +MCU_ST_STM32L0:STM32L031K6Tx +MCU_ST_STM32L0:STM32L031K6Ux +MCU_ST_STM32L0:STM32L031K_4-6_Tx +MCU_ST_STM32L0:STM32L031K_4-6_Ux +MCU_ST_STM32L0:STM32L041C4Tx +MCU_ST_STM32L0:STM32L041C6Tx +MCU_ST_STM32L0:STM32L041C6Ux +MCU_ST_STM32L0:STM32L041C_4-6_Tx +MCU_ST_STM32L0:STM32L041E6Yx +MCU_ST_STM32L0:STM32L041F6Px +MCU_ST_STM32L0:STM32L041G6Ux +MCU_ST_STM32L0:STM32L041G6UxS +MCU_ST_STM32L0:STM32L041K6Tx +MCU_ST_STM32L0:STM32L041K6Ux +MCU_ST_STM32L0:STM32L051C6Tx +MCU_ST_STM32L0:STM32L051C6Ux +MCU_ST_STM32L0:STM32L051C8Tx +MCU_ST_STM32L0:STM32L051C8Ux +MCU_ST_STM32L0:STM32L051C_6-8_Tx +MCU_ST_STM32L0:STM32L051C_6-8_Ux +MCU_ST_STM32L0:STM32L051K6Tx +MCU_ST_STM32L0:STM32L051K6Ux +MCU_ST_STM32L0:STM32L051K8Tx +MCU_ST_STM32L0:STM32L051K8Ux +MCU_ST_STM32L0:STM32L051K_6-8_Tx +MCU_ST_STM32L0:STM32L051K_6-8_Ux +MCU_ST_STM32L0:STM32L051R6Hx +MCU_ST_STM32L0:STM32L051R6Tx +MCU_ST_STM32L0:STM32L051R8Hx +MCU_ST_STM32L0:STM32L051R8Tx +MCU_ST_STM32L0:STM32L051R_6-8_Hx +MCU_ST_STM32L0:STM32L051R_6-8_Tx +MCU_ST_STM32L0:STM32L051T6Yx +MCU_ST_STM32L0:STM32L051T8Yx +MCU_ST_STM32L0:STM32L051T_6-8_Yx +MCU_ST_STM32L0:STM32L052C6Tx +MCU_ST_STM32L0:STM32L052C6Ux +MCU_ST_STM32L0:STM32L052C8Tx +MCU_ST_STM32L0:STM32L052C8Ux +MCU_ST_STM32L0:STM32L052C_6-8_Tx +MCU_ST_STM32L0:STM32L052C_6-8_Ux +MCU_ST_STM32L0:STM32L052K6Tx +MCU_ST_STM32L0:STM32L052K6Ux +MCU_ST_STM32L0:STM32L052K8Tx +MCU_ST_STM32L0:STM32L052K8Ux +MCU_ST_STM32L0:STM32L052K_6-8_Tx +MCU_ST_STM32L0:STM32L052K_6-8_Ux +MCU_ST_STM32L0:STM32L052R6Hx +MCU_ST_STM32L0:STM32L052R6Tx +MCU_ST_STM32L0:STM32L052R8Hx +MCU_ST_STM32L0:STM32L052R8Tx +MCU_ST_STM32L0:STM32L052R_6-8_Hx +MCU_ST_STM32L0:STM32L052R_6-8_Tx +MCU_ST_STM32L0:STM32L052T6Yx +MCU_ST_STM32L0:STM32L052T8Fx +MCU_ST_STM32L0:STM32L052T8Yx +MCU_ST_STM32L0:STM32L052T_6-8_Yx +MCU_ST_STM32L0:STM32L053C6Tx +MCU_ST_STM32L0:STM32L053C6Ux +MCU_ST_STM32L0:STM32L053C8Tx +MCU_ST_STM32L0:STM32L053C8Ux +MCU_ST_STM32L0:STM32L053C_6-8_Tx +MCU_ST_STM32L0:STM32L053C_6-8_Ux +MCU_ST_STM32L0:STM32L053R6Hx +MCU_ST_STM32L0:STM32L053R6Tx +MCU_ST_STM32L0:STM32L053R8Hx +MCU_ST_STM32L0:STM32L053R8Tx +MCU_ST_STM32L0:STM32L053R_6-8_Hx +MCU_ST_STM32L0:STM32L053R_6-8_Tx +MCU_ST_STM32L0:STM32L062C8Ux +MCU_ST_STM32L0:STM32L062K8Tx +MCU_ST_STM32L0:STM32L062K8Ux +MCU_ST_STM32L0:STM32L063C8Tx +MCU_ST_STM32L0:STM32L063C8Ux +MCU_ST_STM32L0:STM32L063R8Tx +MCU_ST_STM32L0:STM32L071C8Tx +MCU_ST_STM32L0:STM32L071C8Ux +MCU_ST_STM32L0:STM32L071CBTx +MCU_ST_STM32L0:STM32L071CBUx +MCU_ST_STM32L0:STM32L071CBYx +MCU_ST_STM32L0:STM32L071CZTx +MCU_ST_STM32L0:STM32L071CZUx +MCU_ST_STM32L0:STM32L071CZYx +MCU_ST_STM32L0:STM32L071C_B-Z_Tx +MCU_ST_STM32L0:STM32L071C_B-Z_Ux +MCU_ST_STM32L0:STM32L071C_B-Z_Yx +MCU_ST_STM32L0:STM32L071K8Ux +MCU_ST_STM32L0:STM32L071KBTx +MCU_ST_STM32L0:STM32L071KBUx +MCU_ST_STM32L0:STM32L071KZTx +MCU_ST_STM32L0:STM32L071KZUx +MCU_ST_STM32L0:STM32L071K_B-Z_Tx +MCU_ST_STM32L0:STM32L071K_B-Z_Ux +MCU_ST_STM32L0:STM32L071RBHx +MCU_ST_STM32L0:STM32L071RBTx +MCU_ST_STM32L0:STM32L071RZHx +MCU_ST_STM32L0:STM32L071RZTx +MCU_ST_STM32L0:STM32L071R_B-Z_Hx +MCU_ST_STM32L0:STM32L071R_B-Z_Tx +MCU_ST_STM32L0:STM32L071V8Ix +MCU_ST_STM32L0:STM32L071V8Tx +MCU_ST_STM32L0:STM32L071VBIx +MCU_ST_STM32L0:STM32L071VBTx +MCU_ST_STM32L0:STM32L071VZIx +MCU_ST_STM32L0:STM32L071VZTx +MCU_ST_STM32L0:STM32L071V_B-Z_Ix +MCU_ST_STM32L0:STM32L071V_B-Z_Tx +MCU_ST_STM32L0:STM32L072CBTx +MCU_ST_STM32L0:STM32L072CBUx +MCU_ST_STM32L0:STM32L072CBYx +MCU_ST_STM32L0:STM32L072CZEx +MCU_ST_STM32L0:STM32L072CZTx +MCU_ST_STM32L0:STM32L072CZUx +MCU_ST_STM32L0:STM32L072CZYx +MCU_ST_STM32L0:STM32L072C_B-Z_Tx +MCU_ST_STM32L0:STM32L072C_B-Z_Ux +MCU_ST_STM32L0:STM32L072C_B-Z_Yx +MCU_ST_STM32L0:STM32L072KBTx +MCU_ST_STM32L0:STM32L072KBUx +MCU_ST_STM32L0:STM32L072KZTx +MCU_ST_STM32L0:STM32L072KZUx +MCU_ST_STM32L0:STM32L072K_B-Z_Tx +MCU_ST_STM32L0:STM32L072K_B-Z_Ux +MCU_ST_STM32L0:STM32L072RBHx +MCU_ST_STM32L0:STM32L072RBIx +MCU_ST_STM32L0:STM32L072RBTx +MCU_ST_STM32L0:STM32L072RZHx +MCU_ST_STM32L0:STM32L072RZIx +MCU_ST_STM32L0:STM32L072RZTx +MCU_ST_STM32L0:STM32L072R_B-Z_Hx +MCU_ST_STM32L0:STM32L072R_B-Z_Ix +MCU_ST_STM32L0:STM32L072R_B-Z_Tx +MCU_ST_STM32L0:STM32L072V8Ix +MCU_ST_STM32L0:STM32L072V8Tx +MCU_ST_STM32L0:STM32L072VBIx +MCU_ST_STM32L0:STM32L072VBTx +MCU_ST_STM32L0:STM32L072VZIx +MCU_ST_STM32L0:STM32L072VZTx +MCU_ST_STM32L0:STM32L072V_B-Z_Ix +MCU_ST_STM32L0:STM32L072V_B-Z_Tx +MCU_ST_STM32L0:STM32L073CBTx +MCU_ST_STM32L0:STM32L073CBUx +MCU_ST_STM32L0:STM32L073CZTx +MCU_ST_STM32L0:STM32L073CZUx +MCU_ST_STM32L0:STM32L073CZYx +MCU_ST_STM32L0:STM32L073C_B-Z_Tx +MCU_ST_STM32L0:STM32L073C_B-Z_Ux +MCU_ST_STM32L0:STM32L073RBHx +MCU_ST_STM32L0:STM32L073RBTx +MCU_ST_STM32L0:STM32L073RZHx +MCU_ST_STM32L0:STM32L073RZIx +MCU_ST_STM32L0:STM32L073RZTx +MCU_ST_STM32L0:STM32L073R_B-Z_Hx +MCU_ST_STM32L0:STM32L073R_B-Z_Tx +MCU_ST_STM32L0:STM32L073V8Ix +MCU_ST_STM32L0:STM32L073V8Tx +MCU_ST_STM32L0:STM32L073VBIx +MCU_ST_STM32L0:STM32L073VBTx +MCU_ST_STM32L0:STM32L073VZIx +MCU_ST_STM32L0:STM32L073VZTx +MCU_ST_STM32L0:STM32L073V_B-Z_Ix +MCU_ST_STM32L0:STM32L073V_B-Z_Tx +MCU_ST_STM32L0:STM32L081CBTx +MCU_ST_STM32L0:STM32L081CZTx +MCU_ST_STM32L0:STM32L081CZUx +MCU_ST_STM32L0:STM32L081C_B-Z_Tx +MCU_ST_STM32L0:STM32L081KZTx +MCU_ST_STM32L0:STM32L081KZUx +MCU_ST_STM32L0:STM32L082CZUx +MCU_ST_STM32L0:STM32L082CZYx +MCU_ST_STM32L0:STM32L082KBTx +MCU_ST_STM32L0:STM32L082KBUx +MCU_ST_STM32L0:STM32L082KZTx +MCU_ST_STM32L0:STM32L082KZUx +MCU_ST_STM32L0:STM32L082K_B-Z_Tx +MCU_ST_STM32L0:STM32L082K_B-Z_Ux +MCU_ST_STM32L0:STM32L083CBTx +MCU_ST_STM32L0:STM32L083CZTx +MCU_ST_STM32L0:STM32L083CZUx +MCU_ST_STM32L0:STM32L083C_B-Z_Tx +MCU_ST_STM32L0:STM32L083RBHx +MCU_ST_STM32L0:STM32L083RBTx +MCU_ST_STM32L0:STM32L083RZHx +MCU_ST_STM32L0:STM32L083RZTx +MCU_ST_STM32L0:STM32L083R_B-Z_Hx +MCU_ST_STM32L0:STM32L083R_B-Z_Tx +MCU_ST_STM32L0:STM32L083V8Ix +MCU_ST_STM32L0:STM32L083V8Tx +MCU_ST_STM32L0:STM32L083VBIx +MCU_ST_STM32L0:STM32L083VBTx +MCU_ST_STM32L0:STM32L083VZIx +MCU_ST_STM32L0:STM32L083VZTx +MCU_ST_STM32L0:STM32L083V_B-Z_Ix +MCU_ST_STM32L0:STM32L083V_B-Z_Tx +MCU_ST_STM32L1:STM32L100C6Ux +MCU_ST_STM32L1:STM32L100C6UxA +MCU_ST_STM32L1:STM32L100R8Tx +MCU_ST_STM32L1:STM32L100R8TxA +MCU_ST_STM32L1:STM32L100RBTx +MCU_ST_STM32L1:STM32L100RBTxA +MCU_ST_STM32L1:STM32L100RCTx +MCU_ST_STM32L1:STM32L100R_8-B_Tx +MCU_ST_STM32L1:STM32L100R_8-B_TxA +MCU_ST_STM32L1:STM32L151C6Tx +MCU_ST_STM32L1:STM32L151C6TxA +MCU_ST_STM32L1:STM32L151C6Ux +MCU_ST_STM32L1:STM32L151C6UxA +MCU_ST_STM32L1:STM32L151C8Tx +MCU_ST_STM32L1:STM32L151C8TxA +MCU_ST_STM32L1:STM32L151C8Ux +MCU_ST_STM32L1:STM32L151C8UxA +MCU_ST_STM32L1:STM32L151CBTx +MCU_ST_STM32L1:STM32L151CBTxA +MCU_ST_STM32L1:STM32L151CBUx +MCU_ST_STM32L1:STM32L151CBUxA +MCU_ST_STM32L1:STM32L151CCTx +MCU_ST_STM32L1:STM32L151CCUx +MCU_ST_STM32L1:STM32L151C_6-8-B_Tx +MCU_ST_STM32L1:STM32L151C_6-8-B_TxA +MCU_ST_STM32L1:STM32L151C_6-8-B_Ux +MCU_ST_STM32L1:STM32L151C_6-8-B_UxA +MCU_ST_STM32L1:STM32L151QCHx +MCU_ST_STM32L1:STM32L151QDHx +MCU_ST_STM32L1:STM32L151QEHx +MCU_ST_STM32L1:STM32L151R6Hx +MCU_ST_STM32L1:STM32L151R6HxA +MCU_ST_STM32L1:STM32L151R6Tx +MCU_ST_STM32L1:STM32L151R6TxA +MCU_ST_STM32L1:STM32L151R8Hx +MCU_ST_STM32L1:STM32L151R8HxA +MCU_ST_STM32L1:STM32L151R8Tx +MCU_ST_STM32L1:STM32L151R8TxA +MCU_ST_STM32L1:STM32L151RBHx +MCU_ST_STM32L1:STM32L151RBHxA +MCU_ST_STM32L1:STM32L151RBTx +MCU_ST_STM32L1:STM32L151RBTxA +MCU_ST_STM32L1:STM32L151RCTx +MCU_ST_STM32L1:STM32L151RCTxA +MCU_ST_STM32L1:STM32L151RCYx +MCU_ST_STM32L1:STM32L151RDTx +MCU_ST_STM32L1:STM32L151RDYx +MCU_ST_STM32L1:STM32L151RETx +MCU_ST_STM32L1:STM32L151R_6-8-B_Hx +MCU_ST_STM32L1:STM32L151R_6-8-B_HxA +MCU_ST_STM32L1:STM32L151R_6-8-B_Tx +MCU_ST_STM32L1:STM32L151R_6-8-B_TxA +MCU_ST_STM32L1:STM32L151UCYx +MCU_ST_STM32L1:STM32L151V8Hx +MCU_ST_STM32L1:STM32L151V8HxA +MCU_ST_STM32L1:STM32L151V8Tx +MCU_ST_STM32L1:STM32L151V8TxA +MCU_ST_STM32L1:STM32L151VBHx +MCU_ST_STM32L1:STM32L151VBHxA +MCU_ST_STM32L1:STM32L151VBTx +MCU_ST_STM32L1:STM32L151VBTxA +MCU_ST_STM32L1:STM32L151VCHx +MCU_ST_STM32L1:STM32L151VCTx +MCU_ST_STM32L1:STM32L151VCTxA +MCU_ST_STM32L1:STM32L151VDTx +MCU_ST_STM32L1:STM32L151VDTxX +MCU_ST_STM32L1:STM32L151VDYxX +MCU_ST_STM32L1:STM32L151VETx +MCU_ST_STM32L1:STM32L151VEYx +MCU_ST_STM32L1:STM32L151V_8-B_Hx +MCU_ST_STM32L1:STM32L151V_8-B_HxA +MCU_ST_STM32L1:STM32L151V_8-B_Tx +MCU_ST_STM32L1:STM32L151V_8-B_TxA +MCU_ST_STM32L1:STM32L151ZCTx +MCU_ST_STM32L1:STM32L151ZDTx +MCU_ST_STM32L1:STM32L151ZETx +MCU_ST_STM32L1:STM32L152C6Tx +MCU_ST_STM32L1:STM32L152C6TxA +MCU_ST_STM32L1:STM32L152C6Ux +MCU_ST_STM32L1:STM32L152C6UxA +MCU_ST_STM32L1:STM32L152C8Tx +MCU_ST_STM32L1:STM32L152C8TxA +MCU_ST_STM32L1:STM32L152C8Ux +MCU_ST_STM32L1:STM32L152C8UxA +MCU_ST_STM32L1:STM32L152CBTx +MCU_ST_STM32L1:STM32L152CBTxA +MCU_ST_STM32L1:STM32L152CBUx +MCU_ST_STM32L1:STM32L152CBUxA +MCU_ST_STM32L1:STM32L152CCTx +MCU_ST_STM32L1:STM32L152CCUx +MCU_ST_STM32L1:STM32L152C_6-8-B_Tx +MCU_ST_STM32L1:STM32L152C_6-8-B_TxA +MCU_ST_STM32L1:STM32L152C_6-8-B_Ux +MCU_ST_STM32L1:STM32L152C_6-8-B_UxA +MCU_ST_STM32L1:STM32L152QCHx +MCU_ST_STM32L1:STM32L152QDHx +MCU_ST_STM32L1:STM32L152QEHx +MCU_ST_STM32L1:STM32L152R6Hx +MCU_ST_STM32L1:STM32L152R6HxA +MCU_ST_STM32L1:STM32L152R6Tx +MCU_ST_STM32L1:STM32L152R6TxA +MCU_ST_STM32L1:STM32L152R8Hx +MCU_ST_STM32L1:STM32L152R8HxA +MCU_ST_STM32L1:STM32L152R8Tx +MCU_ST_STM32L1:STM32L152R8TxA +MCU_ST_STM32L1:STM32L152RBHx +MCU_ST_STM32L1:STM32L152RBHxA +MCU_ST_STM32L1:STM32L152RBTx +MCU_ST_STM32L1:STM32L152RBTxA +MCU_ST_STM32L1:STM32L152RCTx +MCU_ST_STM32L1:STM32L152RCTxA +MCU_ST_STM32L1:STM32L152RDTx +MCU_ST_STM32L1:STM32L152RDYx +MCU_ST_STM32L1:STM32L152RETx +MCU_ST_STM32L1:STM32L152R_6-8-B_Hx +MCU_ST_STM32L1:STM32L152R_6-8-B_HxA +MCU_ST_STM32L1:STM32L152R_6-8-B_Tx +MCU_ST_STM32L1:STM32L152R_6-8-B_TxA +MCU_ST_STM32L1:STM32L152UCYx +MCU_ST_STM32L1:STM32L152V8Hx +MCU_ST_STM32L1:STM32L152V8HxA +MCU_ST_STM32L1:STM32L152V8Tx +MCU_ST_STM32L1:STM32L152V8TxA +MCU_ST_STM32L1:STM32L152VBHx +MCU_ST_STM32L1:STM32L152VBHxA +MCU_ST_STM32L1:STM32L152VBTx +MCU_ST_STM32L1:STM32L152VBTxA +MCU_ST_STM32L1:STM32L152VCHx +MCU_ST_STM32L1:STM32L152VCTx +MCU_ST_STM32L1:STM32L152VCTxA +MCU_ST_STM32L1:STM32L152VDTx +MCU_ST_STM32L1:STM32L152VDTxX +MCU_ST_STM32L1:STM32L152VETx +MCU_ST_STM32L1:STM32L152VEYx +MCU_ST_STM32L1:STM32L152V_8-B_Hx +MCU_ST_STM32L1:STM32L152V_8-B_HxA +MCU_ST_STM32L1:STM32L152V_8-B_Tx +MCU_ST_STM32L1:STM32L152V_8-B_TxA +MCU_ST_STM32L1:STM32L152ZCTx +MCU_ST_STM32L1:STM32L152ZDTx +MCU_ST_STM32L1:STM32L152ZETx +MCU_ST_STM32L1:STM32L162QCHx +MCU_ST_STM32L1:STM32L162QDHx +MCU_ST_STM32L1:STM32L162RCTx +MCU_ST_STM32L1:STM32L162RCTxA +MCU_ST_STM32L1:STM32L162RDTx +MCU_ST_STM32L1:STM32L162RDYx +MCU_ST_STM32L1:STM32L162RETx +MCU_ST_STM32L1:STM32L162VCHx +MCU_ST_STM32L1:STM32L162VCTx +MCU_ST_STM32L1:STM32L162VCTxA +MCU_ST_STM32L1:STM32L162VDTx +MCU_ST_STM32L1:STM32L162VDYxX +MCU_ST_STM32L1:STM32L162VETx +MCU_ST_STM32L1:STM32L162VEYx +MCU_ST_STM32L1:STM32L162ZCTx +MCU_ST_STM32L1:STM32L162ZDTx +MCU_ST_STM32L1:STM32L162ZETx +MCU_ST_STM32L4:STM32L412C8Tx +MCU_ST_STM32L4:STM32L412C8Ux +MCU_ST_STM32L4:STM32L412CBTx +MCU_ST_STM32L4:STM32L412CBTxP +MCU_ST_STM32L4:STM32L412CBUx +MCU_ST_STM32L4:STM32L412CBUxP +MCU_ST_STM32L4:STM32L412K8Tx +MCU_ST_STM32L4:STM32L412K8Ux +MCU_ST_STM32L4:STM32L412KBTx +MCU_ST_STM32L4:STM32L412KBUx +MCU_ST_STM32L4:STM32L412R8Ix +MCU_ST_STM32L4:STM32L412R8Tx +MCU_ST_STM32L4:STM32L412RBIx +MCU_ST_STM32L4:STM32L412RBIxP +MCU_ST_STM32L4:STM32L412RBTx +MCU_ST_STM32L4:STM32L412RBTxP +MCU_ST_STM32L4:STM32L412T8Yx +MCU_ST_STM32L4:STM32L412TBYx +MCU_ST_STM32L4:STM32L412TBYxP +MCU_ST_STM32L4:STM32L422CBTx +MCU_ST_STM32L4:STM32L422CBUx +MCU_ST_STM32L4:STM32L422KBTx +MCU_ST_STM32L4:STM32L422KBUx +MCU_ST_STM32L4:STM32L422RBIx +MCU_ST_STM32L4:STM32L422RBTx +MCU_ST_STM32L4:STM32L422TBYx +MCU_ST_STM32L4:STM32L431CBTx +MCU_ST_STM32L4:STM32L431CBUx +MCU_ST_STM32L4:STM32L431CBYx +MCU_ST_STM32L4:STM32L431CCTx +MCU_ST_STM32L4:STM32L431CCUx +MCU_ST_STM32L4:STM32L431CCYx +MCU_ST_STM32L4:STM32L431C_B-C_Tx +MCU_ST_STM32L4:STM32L431C_B-C_Ux +MCU_ST_STM32L4:STM32L431C_B-C_Yx +MCU_ST_STM32L4:STM32L431KBUx +MCU_ST_STM32L4:STM32L431KCUx +MCU_ST_STM32L4:STM32L431K_B-C_Ux +MCU_ST_STM32L4:STM32L431RBIx +MCU_ST_STM32L4:STM32L431RBTx +MCU_ST_STM32L4:STM32L431RBYx +MCU_ST_STM32L4:STM32L431RCIx +MCU_ST_STM32L4:STM32L431RCTx +MCU_ST_STM32L4:STM32L431RCYx +MCU_ST_STM32L4:STM32L431R_B-C_Ix +MCU_ST_STM32L4:STM32L431R_B-C_Tx +MCU_ST_STM32L4:STM32L431R_B-C_Yx +MCU_ST_STM32L4:STM32L431VCIx +MCU_ST_STM32L4:STM32L431VCTx +MCU_ST_STM32L4:STM32L432KBUx +MCU_ST_STM32L4:STM32L432KCUx +MCU_ST_STM32L4:STM32L432K_B-C_Ux +MCU_ST_STM32L4:STM32L433CBTx +MCU_ST_STM32L4:STM32L433CBUx +MCU_ST_STM32L4:STM32L433CBYx +MCU_ST_STM32L4:STM32L433CCTx +MCU_ST_STM32L4:STM32L433CCUx +MCU_ST_STM32L4:STM32L433CCYx +MCU_ST_STM32L4:STM32L433C_B-C_Tx +MCU_ST_STM32L4:STM32L433C_B-C_Ux +MCU_ST_STM32L4:STM32L433C_B-C_Yx +MCU_ST_STM32L4:STM32L433RBIx +MCU_ST_STM32L4:STM32L433RBTx +MCU_ST_STM32L4:STM32L433RBYx +MCU_ST_STM32L4:STM32L433RCIx +MCU_ST_STM32L4:STM32L433RCTx +MCU_ST_STM32L4:STM32L433RCTxP +MCU_ST_STM32L4:STM32L433RCYx +MCU_ST_STM32L4:STM32L433R_B-C_Ix +MCU_ST_STM32L4:STM32L433R_B-C_Tx +MCU_ST_STM32L4:STM32L433R_B-C_Yx +MCU_ST_STM32L4:STM32L433VCIx +MCU_ST_STM32L4:STM32L433VCTx +MCU_ST_STM32L4:STM32L442KCUx +MCU_ST_STM32L4:STM32L443CCFx +MCU_ST_STM32L4:STM32L443CCTx +MCU_ST_STM32L4:STM32L443CCUx +MCU_ST_STM32L4:STM32L443CCYx +MCU_ST_STM32L4:STM32L443RCIx +MCU_ST_STM32L4:STM32L443RCTx +MCU_ST_STM32L4:STM32L443RCYx +MCU_ST_STM32L4:STM32L443VCIx +MCU_ST_STM32L4:STM32L443VCTx +MCU_ST_STM32L4:STM32L451CCUx +MCU_ST_STM32L4:STM32L451CETx +MCU_ST_STM32L4:STM32L451CEUx +MCU_ST_STM32L4:STM32L451C_C-E_Ux +MCU_ST_STM32L4:STM32L451RCIx +MCU_ST_STM32L4:STM32L451RCTx +MCU_ST_STM32L4:STM32L451RCYx +MCU_ST_STM32L4:STM32L451REIx +MCU_ST_STM32L4:STM32L451RETx +MCU_ST_STM32L4:STM32L451REYx +MCU_ST_STM32L4:STM32L451R_C-E_Ix +MCU_ST_STM32L4:STM32L451R_C-E_Tx +MCU_ST_STM32L4:STM32L451R_C-E_Yx +MCU_ST_STM32L4:STM32L451VCIx +MCU_ST_STM32L4:STM32L451VCTx +MCU_ST_STM32L4:STM32L451VEIx +MCU_ST_STM32L4:STM32L451VETx +MCU_ST_STM32L4:STM32L451V_C-E_Ix +MCU_ST_STM32L4:STM32L451V_C-E_Tx +MCU_ST_STM32L4:STM32L452CCUx +MCU_ST_STM32L4:STM32L452CETx +MCU_ST_STM32L4:STM32L452CETxP +MCU_ST_STM32L4:STM32L452CEUx +MCU_ST_STM32L4:STM32L452C_C-E_Ux +MCU_ST_STM32L4:STM32L452RCIx +MCU_ST_STM32L4:STM32L452RCTx +MCU_ST_STM32L4:STM32L452RCYx +MCU_ST_STM32L4:STM32L452REIx +MCU_ST_STM32L4:STM32L452RETx +MCU_ST_STM32L4:STM32L452RETxP +MCU_ST_STM32L4:STM32L452REYx +MCU_ST_STM32L4:STM32L452REYxP +MCU_ST_STM32L4:STM32L452R_C-E_Ix +MCU_ST_STM32L4:STM32L452R_C-E_Tx +MCU_ST_STM32L4:STM32L452R_C-E_Yx +MCU_ST_STM32L4:STM32L452VCIx +MCU_ST_STM32L4:STM32L452VCTx +MCU_ST_STM32L4:STM32L452VEIx +MCU_ST_STM32L4:STM32L452VETx +MCU_ST_STM32L4:STM32L452V_C-E_Ix +MCU_ST_STM32L4:STM32L452V_C-E_Tx +MCU_ST_STM32L4:STM32L462CETx +MCU_ST_STM32L4:STM32L462CEUx +MCU_ST_STM32L4:STM32L462REIx +MCU_ST_STM32L4:STM32L462RETx +MCU_ST_STM32L4:STM32L462REYx +MCU_ST_STM32L4:STM32L462VEIx +MCU_ST_STM32L4:STM32L462VETx +MCU_ST_STM32L4:STM32L471QEIx +MCU_ST_STM32L4:STM32L471QGIx +MCU_ST_STM32L4:STM32L471Q_E-G_Ix +MCU_ST_STM32L4:STM32L471RETx +MCU_ST_STM32L4:STM32L471RGTx +MCU_ST_STM32L4:STM32L471R_E-G_Tx +MCU_ST_STM32L4:STM32L471VETx +MCU_ST_STM32L4:STM32L471VGTx +MCU_ST_STM32L4:STM32L471V_E-G_Tx +MCU_ST_STM32L4:STM32L471ZEJx +MCU_ST_STM32L4:STM32L471ZETx +MCU_ST_STM32L4:STM32L471ZGJx +MCU_ST_STM32L4:STM32L471ZGTx +MCU_ST_STM32L4:STM32L471Z_E-G_Jx +MCU_ST_STM32L4:STM32L471Z_E-G_Tx +MCU_ST_STM32L4:STM32L475RCTx +MCU_ST_STM32L4:STM32L475RETx +MCU_ST_STM32L4:STM32L475RGTx +MCU_ST_STM32L4:STM32L475R_C-E-G_Tx +MCU_ST_STM32L4:STM32L475VCTx +MCU_ST_STM32L4:STM32L475VETx +MCU_ST_STM32L4:STM32L475VGTx +MCU_ST_STM32L4:STM32L475V_C-E-G_Tx +MCU_ST_STM32L4:STM32L476JEYx +MCU_ST_STM32L4:STM32L476JGYx +MCU_ST_STM32L4:STM32L476JGYxP +MCU_ST_STM32L4:STM32L476J_E-G_Yx +MCU_ST_STM32L4:STM32L476MEYx +MCU_ST_STM32L4:STM32L476MGYx +MCU_ST_STM32L4:STM32L476M_E-G_Yx +MCU_ST_STM32L4:STM32L476QEIx +MCU_ST_STM32L4:STM32L476QGIx +MCU_ST_STM32L4:STM32L476QGIxP +MCU_ST_STM32L4:STM32L476Q_E-G_Ix +MCU_ST_STM32L4:STM32L476RCTx +MCU_ST_STM32L4:STM32L476RETx +MCU_ST_STM32L4:STM32L476RGTx +MCU_ST_STM32L4:STM32L476R_C-E-G_Tx +MCU_ST_STM32L4:STM32L476VCTx +MCU_ST_STM32L4:STM32L476VETx +MCU_ST_STM32L4:STM32L476VGTx +MCU_ST_STM32L4:STM32L476VGYxP +MCU_ST_STM32L4:STM32L476V_C-E-G_Tx +MCU_ST_STM32L4:STM32L476ZETx +MCU_ST_STM32L4:STM32L476ZGJx +MCU_ST_STM32L4:STM32L476ZGTx +MCU_ST_STM32L4:STM32L476ZGTxP +MCU_ST_STM32L4:STM32L476Z_E-G_Tx +MCU_ST_STM32L4:STM32L486JGYx +MCU_ST_STM32L4:STM32L486QGIx +MCU_ST_STM32L4:STM32L486RGTx +MCU_ST_STM32L4:STM32L486VGTx +MCU_ST_STM32L4:STM32L486ZGTx +MCU_ST_STM32L4:STM32L496AEIx +MCU_ST_STM32L4:STM32L496AGIx +MCU_ST_STM32L4:STM32L496AGIxP +MCU_ST_STM32L4:STM32L496A_E-G_Ix +MCU_ST_STM32L4:STM32L496QEIx +MCU_ST_STM32L4:STM32L496QGIx +MCU_ST_STM32L4:STM32L496QGIxP +MCU_ST_STM32L4:STM32L496QGIxS +MCU_ST_STM32L4:STM32L496Q_E-G_Ix +MCU_ST_STM32L4:STM32L496RETx +MCU_ST_STM32L4:STM32L496RGTx +MCU_ST_STM32L4:STM32L496RGTxP +MCU_ST_STM32L4:STM32L496R_E-G_Tx +MCU_ST_STM32L4:STM32L496VETx +MCU_ST_STM32L4:STM32L496VGTx +MCU_ST_STM32L4:STM32L496VGTxP +MCU_ST_STM32L4:STM32L496VGYx +MCU_ST_STM32L4:STM32L496VGYxP +MCU_ST_STM32L4:STM32L496V_E-G_Tx +MCU_ST_STM32L4:STM32L496WGYxP +MCU_ST_STM32L4:STM32L496ZETx +MCU_ST_STM32L4:STM32L496ZGTx +MCU_ST_STM32L4:STM32L496ZGTxP +MCU_ST_STM32L4:STM32L496Z_E-G_Tx +MCU_ST_STM32L4:STM32L4A6AGIx +MCU_ST_STM32L4:STM32L4A6AGIxP +MCU_ST_STM32L4:STM32L4A6QGIx +MCU_ST_STM32L4:STM32L4A6QGIxP +MCU_ST_STM32L4:STM32L4A6RGTx +MCU_ST_STM32L4:STM32L4A6RGTxP +MCU_ST_STM32L4:STM32L4A6VGTx +MCU_ST_STM32L4:STM32L4A6VGTxP +MCU_ST_STM32L4:STM32L4A6VGYx +MCU_ST_STM32L4:STM32L4A6VGYxP +MCU_ST_STM32L4:STM32L4A6ZGTx +MCU_ST_STM32L4:STM32L4A6ZGTxP +MCU_ST_STM32L4:STM32L4P5AEIx +MCU_ST_STM32L4:STM32L4P5AGIx +MCU_ST_STM32L4:STM32L4P5AGIxP +MCU_ST_STM32L4:STM32L4P5A_G-E_Ix +MCU_ST_STM32L4:STM32L4P5CETx +MCU_ST_STM32L4:STM32L4P5CEUx +MCU_ST_STM32L4:STM32L4P5CGTx +MCU_ST_STM32L4:STM32L4P5CGTxP +MCU_ST_STM32L4:STM32L4P5CGUx +MCU_ST_STM32L4:STM32L4P5CGUxP +MCU_ST_STM32L4:STM32L4P5C_G-E_Tx +MCU_ST_STM32L4:STM32L4P5C_G-E_Ux +MCU_ST_STM32L4:STM32L4P5QEIx +MCU_ST_STM32L4:STM32L4P5QGIx +MCU_ST_STM32L4:STM32L4P5QGIxP +MCU_ST_STM32L4:STM32L4P5QGIxS +MCU_ST_STM32L4:STM32L4P5Q_G-E_Ix +MCU_ST_STM32L4:STM32L4P5RETx +MCU_ST_STM32L4:STM32L4P5RGTx +MCU_ST_STM32L4:STM32L4P5RGTxP +MCU_ST_STM32L4:STM32L4P5R_G-E_Tx +MCU_ST_STM32L4:STM32L4P5VETx +MCU_ST_STM32L4:STM32L4P5VEYx +MCU_ST_STM32L4:STM32L4P5VGTx +MCU_ST_STM32L4:STM32L4P5VGTxP +MCU_ST_STM32L4:STM32L4P5VGYx +MCU_ST_STM32L4:STM32L4P5VGYxP +MCU_ST_STM32L4:STM32L4P5V_G-E_Tx +MCU_ST_STM32L4:STM32L4P5V_G-E_Yx +MCU_ST_STM32L4:STM32L4P5ZETx +MCU_ST_STM32L4:STM32L4P5ZGTx +MCU_ST_STM32L4:STM32L4P5ZGTxP +MCU_ST_STM32L4:STM32L4P5Z_G-E_Tx +MCU_ST_STM32L4:STM32L4Q5AGIx +MCU_ST_STM32L4:STM32L4Q5AGIxP +MCU_ST_STM32L4:STM32L4Q5CGTx +MCU_ST_STM32L4:STM32L4Q5CGTxP +MCU_ST_STM32L4:STM32L4Q5CGUx +MCU_ST_STM32L4:STM32L4Q5CGUxP +MCU_ST_STM32L4:STM32L4Q5QGIx +MCU_ST_STM32L4:STM32L4Q5QGIxP +MCU_ST_STM32L4:STM32L4Q5RGTx +MCU_ST_STM32L4:STM32L4Q5RGTxP +MCU_ST_STM32L4:STM32L4Q5VGTx +MCU_ST_STM32L4:STM32L4Q5VGTxP +MCU_ST_STM32L4:STM32L4Q5VGYx +MCU_ST_STM32L4:STM32L4Q5VGYxP +MCU_ST_STM32L4:STM32L4Q5ZGTx +MCU_ST_STM32L4:STM32L4Q5ZGTxP +MCU_ST_STM32L4:STM32L4R5AGIx +MCU_ST_STM32L4:STM32L4R5AIIx +MCU_ST_STM32L4:STM32L4R5AIIxP +MCU_ST_STM32L4:STM32L4R5A_G-I_Ix +MCU_ST_STM32L4:STM32L4R5QGIx +MCU_ST_STM32L4:STM32L4R5QGIxS +MCU_ST_STM32L4:STM32L4R5QIIx +MCU_ST_STM32L4:STM32L4R5QIIxP +MCU_ST_STM32L4:STM32L4R5Q_G-I_Ix +MCU_ST_STM32L4:STM32L4R5VGTx +MCU_ST_STM32L4:STM32L4R5VITx +MCU_ST_STM32L4:STM32L4R5V_G-I_Tx +MCU_ST_STM32L4:STM32L4R5ZGTx +MCU_ST_STM32L4:STM32L4R5ZGYx +MCU_ST_STM32L4:STM32L4R5ZITx +MCU_ST_STM32L4:STM32L4R5ZITxP +MCU_ST_STM32L4:STM32L4R5ZIYx +MCU_ST_STM32L4:STM32L4R5Z_G-I_Tx +MCU_ST_STM32L4:STM32L4R5Z_G-I_Yx +MCU_ST_STM32L4:STM32L4R7AIIx +MCU_ST_STM32L4:STM32L4R7VITx +MCU_ST_STM32L4:STM32L4R7ZITx +MCU_ST_STM32L4:STM32L4R9AGIx +MCU_ST_STM32L4:STM32L4R9AIIx +MCU_ST_STM32L4:STM32L4R9A_G-I_Ix +MCU_ST_STM32L4:STM32L4R9VGTx +MCU_ST_STM32L4:STM32L4R9VITx +MCU_ST_STM32L4:STM32L4R9V_G-I_Tx +MCU_ST_STM32L4:STM32L4R9ZGJx +MCU_ST_STM32L4:STM32L4R9ZGTx +MCU_ST_STM32L4:STM32L4R9ZGYx +MCU_ST_STM32L4:STM32L4R9ZIJx +MCU_ST_STM32L4:STM32L4R9ZITx +MCU_ST_STM32L4:STM32L4R9ZIYx +MCU_ST_STM32L4:STM32L4R9ZIYxP +MCU_ST_STM32L4:STM32L4R9Z_G-I_Jx +MCU_ST_STM32L4:STM32L4R9Z_G-I_Tx +MCU_ST_STM32L4:STM32L4R9Z_G-I_Yx +MCU_ST_STM32L4:STM32L4S5AIIx +MCU_ST_STM32L4:STM32L4S5QIIx +MCU_ST_STM32L4:STM32L4S5VITx +MCU_ST_STM32L4:STM32L4S5ZITx +MCU_ST_STM32L4:STM32L4S5ZIYx +MCU_ST_STM32L4:STM32L4S7AIIx +MCU_ST_STM32L4:STM32L4S7VITx +MCU_ST_STM32L4:STM32L4S7ZITx +MCU_ST_STM32L4:STM32L4S9AIIx +MCU_ST_STM32L4:STM32L4S9VITx +MCU_ST_STM32L4:STM32L4S9ZIJx +MCU_ST_STM32L4:STM32L4S9ZITx +MCU_ST_STM32L4:STM32L4S9ZIYx +MCU_ST_STM32L5:STM32L552CCTx +MCU_ST_STM32L5:STM32L552CCUx +MCU_ST_STM32L5:STM32L552CETx +MCU_ST_STM32L5:STM32L552CETxP +MCU_ST_STM32L5:STM32L552CEUx +MCU_ST_STM32L5:STM32L552CEUxP +MCU_ST_STM32L5:STM32L552C_C-E_Tx +MCU_ST_STM32L5:STM32L552C_C-E_Ux +MCU_ST_STM32L5:STM32L552MEYxP +MCU_ST_STM32L5:STM32L552MEYxQ +MCU_ST_STM32L5:STM32L552QCIxQ +MCU_ST_STM32L5:STM32L552QEIx +MCU_ST_STM32L5:STM32L552QEIxP +MCU_ST_STM32L5:STM32L552QEIxQ +MCU_ST_STM32L5:STM32L552Q_C-E_IxQ +MCU_ST_STM32L5:STM32L552RCTx +MCU_ST_STM32L5:STM32L552RETx +MCU_ST_STM32L5:STM32L552RETxP +MCU_ST_STM32L5:STM32L552RETxQ +MCU_ST_STM32L5:STM32L552R_C-E_Tx +MCU_ST_STM32L5:STM32L552VCTxQ +MCU_ST_STM32L5:STM32L552VETx +MCU_ST_STM32L5:STM32L552VETxQ +MCU_ST_STM32L5:STM32L552V_C-E_TxQ +MCU_ST_STM32L5:STM32L552ZCTxQ +MCU_ST_STM32L5:STM32L552ZETx +MCU_ST_STM32L5:STM32L552ZETxQ +MCU_ST_STM32L5:STM32L552Z_C-E_TxQ +MCU_ST_STM32L5:STM32L562CETx +MCU_ST_STM32L5:STM32L562CETxP +MCU_ST_STM32L5:STM32L562CEUx +MCU_ST_STM32L5:STM32L562CEUxP +MCU_ST_STM32L5:STM32L562MEYxP +MCU_ST_STM32L5:STM32L562MEYxQ +MCU_ST_STM32L5:STM32L562QEIx +MCU_ST_STM32L5:STM32L562QEIxP +MCU_ST_STM32L5:STM32L562QEIxQ +MCU_ST_STM32L5:STM32L562RETx +MCU_ST_STM32L5:STM32L562RETxP +MCU_ST_STM32L5:STM32L562RETxQ +MCU_ST_STM32L5:STM32L562VETx +MCU_ST_STM32L5:STM32L562VETxQ +MCU_ST_STM32L5:STM32L562ZETx +MCU_ST_STM32L5:STM32L562ZETxQ +MCU_ST_STM32MP1:STM32MP131AAEx +MCU_ST_STM32MP1:STM32MP131AAFx +MCU_ST_STM32MP1:STM32MP131AAGx +MCU_ST_STM32MP1:STM32MP131CAEx +MCU_ST_STM32MP1:STM32MP131CAFx +MCU_ST_STM32MP1:STM32MP131CAGx +MCU_ST_STM32MP1:STM32MP131DAEx +MCU_ST_STM32MP1:STM32MP131DAFx +MCU_ST_STM32MP1:STM32MP131DAGx +MCU_ST_STM32MP1:STM32MP131FAEx +MCU_ST_STM32MP1:STM32MP131FAFx +MCU_ST_STM32MP1:STM32MP131FAGx +MCU_ST_STM32MP1:STM32MP133AAEx +MCU_ST_STM32MP1:STM32MP133AAFx +MCU_ST_STM32MP1:STM32MP133AAGx +MCU_ST_STM32MP1:STM32MP133CAEx +MCU_ST_STM32MP1:STM32MP133CAFx +MCU_ST_STM32MP1:STM32MP133CAGx +MCU_ST_STM32MP1:STM32MP133DAEx +MCU_ST_STM32MP1:STM32MP133DAFx +MCU_ST_STM32MP1:STM32MP133DAGx +MCU_ST_STM32MP1:STM32MP133FAEx +MCU_ST_STM32MP1:STM32MP133FAFx +MCU_ST_STM32MP1:STM32MP133FAGx +MCU_ST_STM32MP1:STM32MP135AAEx +MCU_ST_STM32MP1:STM32MP135AAFx +MCU_ST_STM32MP1:STM32MP135AAGx +MCU_ST_STM32MP1:STM32MP135CAEx +MCU_ST_STM32MP1:STM32MP135CAFx +MCU_ST_STM32MP1:STM32MP135CAGx +MCU_ST_STM32MP1:STM32MP135DAEx +MCU_ST_STM32MP1:STM32MP135DAFx +MCU_ST_STM32MP1:STM32MP135DAGx +MCU_ST_STM32MP1:STM32MP135FAEx +MCU_ST_STM32MP1:STM32MP135FAFx +MCU_ST_STM32MP1:STM32MP135FAGx +MCU_ST_STM32MP1:STM32MP151AAAx +MCU_ST_STM32MP1:STM32MP151AABx +MCU_ST_STM32MP1:STM32MP151AACx +MCU_ST_STM32MP1:STM32MP151AADx +MCU_ST_STM32MP1:STM32MP151CAAx +MCU_ST_STM32MP1:STM32MP151CABx +MCU_ST_STM32MP1:STM32MP151CACx +MCU_ST_STM32MP1:STM32MP151CADx +MCU_ST_STM32MP1:STM32MP151DAAx +MCU_ST_STM32MP1:STM32MP151DABx +MCU_ST_STM32MP1:STM32MP151DACx +MCU_ST_STM32MP1:STM32MP151DADx +MCU_ST_STM32MP1:STM32MP151FAAx +MCU_ST_STM32MP1:STM32MP151FABx +MCU_ST_STM32MP1:STM32MP151FACx +MCU_ST_STM32MP1:STM32MP151FADx +MCU_ST_STM32MP1:STM32MP153AAAx +MCU_ST_STM32MP1:STM32MP153AABx +MCU_ST_STM32MP1:STM32MP153AACx +MCU_ST_STM32MP1:STM32MP153AADx +MCU_ST_STM32MP1:STM32MP153CAAx +MCU_ST_STM32MP1:STM32MP153CABx +MCU_ST_STM32MP1:STM32MP153CACx +MCU_ST_STM32MP1:STM32MP153CADx +MCU_ST_STM32MP1:STM32MP153DAAx +MCU_ST_STM32MP1:STM32MP153DABx +MCU_ST_STM32MP1:STM32MP153DACx +MCU_ST_STM32MP1:STM32MP153DADx +MCU_ST_STM32MP1:STM32MP153FAAx +MCU_ST_STM32MP1:STM32MP153FABx +MCU_ST_STM32MP1:STM32MP153FACx +MCU_ST_STM32MP1:STM32MP153FADx +MCU_ST_STM32MP1:STM32MP157AAAx +MCU_ST_STM32MP1:STM32MP157AABx +MCU_ST_STM32MP1:STM32MP157AACx +MCU_ST_STM32MP1:STM32MP157AADx +MCU_ST_STM32MP1:STM32MP157CAAx +MCU_ST_STM32MP1:STM32MP157CABx +MCU_ST_STM32MP1:STM32MP157CACx +MCU_ST_STM32MP1:STM32MP157CADx +MCU_ST_STM32MP1:STM32MP157DAAx +MCU_ST_STM32MP1:STM32MP157DABx +MCU_ST_STM32MP1:STM32MP157DACx +MCU_ST_STM32MP1:STM32MP157DADx +MCU_ST_STM32MP1:STM32MP157FAAx +MCU_ST_STM32MP1:STM32MP157FABx +MCU_ST_STM32MP1:STM32MP157FACx +MCU_ST_STM32MP1:STM32MP157FADx +MCU_ST_STM32U0:STM32U031C6Tx +MCU_ST_STM32U0:STM32U031C6Ux +MCU_ST_STM32U0:STM32U031C8Tx +MCU_ST_STM32U0:STM32U031C8Ux +MCU_ST_STM32U0:STM32U031F4Px +MCU_ST_STM32U0:STM32U031F6Px +MCU_ST_STM32U0:STM32U031F8Px +MCU_ST_STM32U0:STM32U031G6Yx +MCU_ST_STM32U0:STM32U031G8Yx +MCU_ST_STM32U0:STM32U031K4Ux +MCU_ST_STM32U0:STM32U031K6Ux +MCU_ST_STM32U0:STM32U031K8Ux +MCU_ST_STM32U0:STM32U031R6Ix +MCU_ST_STM32U0:STM32U031R6Tx +MCU_ST_STM32U0:STM32U031R8Ix +MCU_ST_STM32U0:STM32U031R8Tx +MCU_ST_STM32U0:STM32U073C8Tx +MCU_ST_STM32U0:STM32U073C8Ux +MCU_ST_STM32U0:STM32U073CBTx +MCU_ST_STM32U0:STM32U073CBUx +MCU_ST_STM32U0:STM32U073CCTx +MCU_ST_STM32U0:STM32U073CCUx +MCU_ST_STM32U0:STM32U073H8Yx +MCU_ST_STM32U0:STM32U073HBYx +MCU_ST_STM32U0:STM32U073HCYx +MCU_ST_STM32U0:STM32U073K8Ux +MCU_ST_STM32U0:STM32U073KBUx +MCU_ST_STM32U0:STM32U073KCUx +MCU_ST_STM32U0:STM32U073M8Ix +MCU_ST_STM32U0:STM32U073M8Tx +MCU_ST_STM32U0:STM32U073MBIx +MCU_ST_STM32U0:STM32U073MBTx +MCU_ST_STM32U0:STM32U073MCIx +MCU_ST_STM32U0:STM32U073MCTx +MCU_ST_STM32U0:STM32U073R8Ix +MCU_ST_STM32U0:STM32U073R8Tx +MCU_ST_STM32U0:STM32U073RBIx +MCU_ST_STM32U0:STM32U073RBTx +MCU_ST_STM32U0:STM32U073RCIx +MCU_ST_STM32U0:STM32U073RCTx +MCU_ST_STM32U0:STM32U083CCTx +MCU_ST_STM32U0:STM32U083CCUx +MCU_ST_STM32U0:STM32U083HCYx +MCU_ST_STM32U0:STM32U083KCUx +MCU_ST_STM32U0:STM32U083MCIx +MCU_ST_STM32U0:STM32U083MCTx +MCU_ST_STM32U0:STM32U083RCIx +MCU_ST_STM32U0:STM32U083RCTx +MCU_ST_STM32U5:STM32U535CBTx +MCU_ST_STM32U5:STM32U535CBTxQ +MCU_ST_STM32U5:STM32U535CBUx +MCU_ST_STM32U5:STM32U535CBUxQ +MCU_ST_STM32U5:STM32U535CCTx +MCU_ST_STM32U5:STM32U535CCTxQ +MCU_ST_STM32U5:STM32U535CCUx +MCU_ST_STM32U5:STM32U535CCUxQ +MCU_ST_STM32U5:STM32U535CETx +MCU_ST_STM32U5:STM32U535CETxQ +MCU_ST_STM32U5:STM32U535CEUx +MCU_ST_STM32U5:STM32U535CEUxQ +MCU_ST_STM32U5:STM32U535JEYxQ +MCU_ST_STM32U5:STM32U535NCYxQ +MCU_ST_STM32U5:STM32U535NEYxQ +MCU_ST_STM32U5:STM32U535RBIx +MCU_ST_STM32U5:STM32U535RBIxQ +MCU_ST_STM32U5:STM32U535RBTx +MCU_ST_STM32U5:STM32U535RBTxQ +MCU_ST_STM32U5:STM32U535RCIx +MCU_ST_STM32U5:STM32U535RCIxQ +MCU_ST_STM32U5:STM32U535RCTx +MCU_ST_STM32U5:STM32U535RCTxQ +MCU_ST_STM32U5:STM32U535REIx +MCU_ST_STM32U5:STM32U535REIxQ +MCU_ST_STM32U5:STM32U535RETx +MCU_ST_STM32U5:STM32U535RETxQ +MCU_ST_STM32U5:STM32U535VCIx +MCU_ST_STM32U5:STM32U535VCIxQ +MCU_ST_STM32U5:STM32U535VCTx +MCU_ST_STM32U5:STM32U535VCTxQ +MCU_ST_STM32U5:STM32U535VEIx +MCU_ST_STM32U5:STM32U535VEIxQ +MCU_ST_STM32U5:STM32U535VETx +MCU_ST_STM32U5:STM32U535VETxQ +MCU_ST_STM32U5:STM32U545CETx +MCU_ST_STM32U5:STM32U545CETxQ +MCU_ST_STM32U5:STM32U545CEUx +MCU_ST_STM32U5:STM32U545CEUxQ +MCU_ST_STM32U5:STM32U545JEYxQ +MCU_ST_STM32U5:STM32U545NEYxQ +MCU_ST_STM32U5:STM32U545REIx +MCU_ST_STM32U5:STM32U545REIxQ +MCU_ST_STM32U5:STM32U545RETx +MCU_ST_STM32U5:STM32U545RETxQ +MCU_ST_STM32U5:STM32U545VEIx +MCU_ST_STM32U5:STM32U545VEIxQ +MCU_ST_STM32U5:STM32U545VETx +MCU_ST_STM32U5:STM32U545VETxQ +MCU_ST_STM32U5:STM32U575AGIx +MCU_ST_STM32U5:STM32U575AGIxQ +MCU_ST_STM32U5:STM32U575AIIx +MCU_ST_STM32U5:STM32U575AIIxQ +MCU_ST_STM32U5:STM32U575CGTx +MCU_ST_STM32U5:STM32U575CGTxQ +MCU_ST_STM32U5:STM32U575CGUx +MCU_ST_STM32U5:STM32U575CGUxQ +MCU_ST_STM32U5:STM32U575CITx +MCU_ST_STM32U5:STM32U575CITxQ +MCU_ST_STM32U5:STM32U575CIUx +MCU_ST_STM32U5:STM32U575CIUxQ +MCU_ST_STM32U5:STM32U575OGYxQ +MCU_ST_STM32U5:STM32U575OIYxQ +MCU_ST_STM32U5:STM32U575QGIx +MCU_ST_STM32U5:STM32U575QGIxQ +MCU_ST_STM32U5:STM32U575QIIx +MCU_ST_STM32U5:STM32U575QIIxQ +MCU_ST_STM32U5:STM32U575RGTx +MCU_ST_STM32U5:STM32U575RGTxQ +MCU_ST_STM32U5:STM32U575RITx +MCU_ST_STM32U5:STM32U575RITxQ +MCU_ST_STM32U5:STM32U575VGTx +MCU_ST_STM32U5:STM32U575VGTxQ +MCU_ST_STM32U5:STM32U575VITx +MCU_ST_STM32U5:STM32U575VITxQ +MCU_ST_STM32U5:STM32U575ZGTx +MCU_ST_STM32U5:STM32U575ZGTxQ +MCU_ST_STM32U5:STM32U575ZITx +MCU_ST_STM32U5:STM32U575ZITxQ +MCU_ST_STM32U5:STM32U585AIIx +MCU_ST_STM32U5:STM32U585AIIxQ +MCU_ST_STM32U5:STM32U585CITx +MCU_ST_STM32U5:STM32U585CITxQ +MCU_ST_STM32U5:STM32U585CIUx +MCU_ST_STM32U5:STM32U585CIUxQ +MCU_ST_STM32U5:STM32U585OIYxQ +MCU_ST_STM32U5:STM32U585QIIx +MCU_ST_STM32U5:STM32U585QIIxQ +MCU_ST_STM32U5:STM32U585RITx +MCU_ST_STM32U5:STM32U585RITxQ +MCU_ST_STM32U5:STM32U585VITx +MCU_ST_STM32U5:STM32U585VITxQ +MCU_ST_STM32U5:STM32U585ZITx +MCU_ST_STM32U5:STM32U585ZITxQ +MCU_ST_STM32U5:STM32U595AIHx +MCU_ST_STM32U5:STM32U595AIHxQ +MCU_ST_STM32U5:STM32U595AJHx +MCU_ST_STM32U5:STM32U595AJHxQ +MCU_ST_STM32U5:STM32U595QIIx +MCU_ST_STM32U5:STM32U595QIIxQ +MCU_ST_STM32U5:STM32U595QJIx +MCU_ST_STM32U5:STM32U595QJIxQ +MCU_ST_STM32U5:STM32U595RITx +MCU_ST_STM32U5:STM32U595RITxQ +MCU_ST_STM32U5:STM32U595RJTx +MCU_ST_STM32U5:STM32U595RJTxQ +MCU_ST_STM32U5:STM32U595VITx +MCU_ST_STM32U5:STM32U595VITxQ +MCU_ST_STM32U5:STM32U595VJTx +MCU_ST_STM32U5:STM32U595VJTxQ +MCU_ST_STM32U5:STM32U595ZITx +MCU_ST_STM32U5:STM32U595ZITxQ +MCU_ST_STM32U5:STM32U595ZIYxQ +MCU_ST_STM32U5:STM32U595ZJTx +MCU_ST_STM32U5:STM32U595ZJTxQ +MCU_ST_STM32U5:STM32U595ZJYxQ +MCU_ST_STM32U5:STM32U599BJYxQ +MCU_ST_STM32U5:STM32U599NIHxQ +MCU_ST_STM32U5:STM32U599NJHxQ +MCU_ST_STM32U5:STM32U599VITxQ +MCU_ST_STM32U5:STM32U599VJTx +MCU_ST_STM32U5:STM32U599VJTxQ +MCU_ST_STM32U5:STM32U599ZITxQ +MCU_ST_STM32U5:STM32U599ZIYxQ +MCU_ST_STM32U5:STM32U599ZJTxQ +MCU_ST_STM32U5:STM32U599ZJYxQ +MCU_ST_STM32U5:STM32U5A5AJHx +MCU_ST_STM32U5:STM32U5A5AJHxQ +MCU_ST_STM32U5:STM32U5A5QIIxQ +MCU_ST_STM32U5:STM32U5A5QJIx +MCU_ST_STM32U5:STM32U5A5QJIxQ +MCU_ST_STM32U5:STM32U5A5RJTx +MCU_ST_STM32U5:STM32U5A5RJTxQ +MCU_ST_STM32U5:STM32U5A5VJTx +MCU_ST_STM32U5:STM32U5A5VJTxQ +MCU_ST_STM32U5:STM32U5A5ZJTx +MCU_ST_STM32U5:STM32U5A5ZJTxQ +MCU_ST_STM32U5:STM32U5A5ZJYxQ +MCU_ST_STM32U5:STM32U5A9BJYxQ +MCU_ST_STM32U5:STM32U5A9NJHxQ +MCU_ST_STM32U5:STM32U5A9VJTxQ +MCU_ST_STM32U5:STM32U5A9ZJTxQ +MCU_ST_STM32U5:STM32U5A9ZJYxQ +MCU_ST_STM32U5:STM32U5F7VITx +MCU_ST_STM32U5:STM32U5F7VITxQ +MCU_ST_STM32U5:STM32U5F7VJTx +MCU_ST_STM32U5:STM32U5F7VJTxQ +MCU_ST_STM32U5:STM32U5F9BJYxQ +MCU_ST_STM32U5:STM32U5F9NJHxQ +MCU_ST_STM32U5:STM32U5F9VITxQ +MCU_ST_STM32U5:STM32U5F9VJTxQ +MCU_ST_STM32U5:STM32U5F9ZIJxQ +MCU_ST_STM32U5:STM32U5F9ZITxQ +MCU_ST_STM32U5:STM32U5F9ZJJxQ +MCU_ST_STM32U5:STM32U5F9ZJTxQ +MCU_ST_STM32U5:STM32U5G7VJTx +MCU_ST_STM32U5:STM32U5G7VJTxQ +MCU_ST_STM32U5:STM32U5G9BJYxQ +MCU_ST_STM32U5:STM32U5G9NJHxQ +MCU_ST_STM32U5:STM32U5G9VJTxQ +MCU_ST_STM32U5:STM32U5G9ZJJxQ +MCU_ST_STM32U5:STM32U5G9ZJTxQ +MCU_ST_STM32WB:STM32WB05KZVx +MCU_ST_STM32WB:STM32WB06KCVx +MCU_ST_STM32WB:STM32WB07KCVx +MCU_ST_STM32WB:STM32WB09KEVx +MCU_ST_STM32WB:STM32WB10CCUx +MCU_ST_STM32WB:STM32WB15CCUx +MCU_ST_STM32WB:STM32WB15CCUxE +MCU_ST_STM32WB:STM32WB15CCYx +MCU_ST_STM32WB:STM32WB30CEUxA +MCU_ST_STM32WB:STM32WB35CCUxA +MCU_ST_STM32WB:STM32WB35CEUxA +MCU_ST_STM32WB:STM32WB35C_C-E_UxA +MCU_ST_STM32WB:STM32WB50CGUx +MCU_ST_STM32WB:STM32WB55CCUx +MCU_ST_STM32WB:STM32WB55CEUx +MCU_ST_STM32WB:STM32WB55CGUx +MCU_ST_STM32WB:STM32WB55RCVx +MCU_ST_STM32WB:STM32WB55REVx +MCU_ST_STM32WB:STM32WB55RGVx +MCU_ST_STM32WB:STM32WB55VCQx +MCU_ST_STM32WB:STM32WB55VCYx +MCU_ST_STM32WB:STM32WB55VEQx +MCU_ST_STM32WB:STM32WB55VEYx +MCU_ST_STM32WB:STM32WB55VGQx +MCU_ST_STM32WB:STM32WB55VGYx +MCU_ST_STM32WB:STM32WB55VYYx +MCU_ST_STM32WB:STM32WBA52CEUx +MCU_ST_STM32WB:STM32WBA52CGUx +MCU_ST_STM32WB:STM32WBA52KEUx +MCU_ST_STM32WB:STM32WBA52KGUx +MCU_ST_STM32WB:STM32WBA54CEUx +MCU_ST_STM32WB:STM32WBA54CGUx +MCU_ST_STM32WB:STM32WBA54KEUx +MCU_ST_STM32WB:STM32WBA54KGUx +MCU_ST_STM32WB:STM32WBA55CEUx +MCU_ST_STM32WB:STM32WBA55CGUx +MCU_ST_STM32WB:STM32WBA55HEFx +MCU_ST_STM32WB:STM32WBA55HGFx +MCU_ST_STM32WB:STM32WBA55UEIx +MCU_ST_STM32WB:STM32WBA55UGIx +MCU_ST_STM32WL:STM32WL54CCUx +MCU_ST_STM32WL:STM32WL54JCIx +MCU_ST_STM32WL:STM32WL55CCUx +MCU_ST_STM32WL:STM32WL55JCIx +MCU_ST_STM32WL:STM32WLE4C8Ux +MCU_ST_STM32WL:STM32WLE4CBUx +MCU_ST_STM32WL:STM32WLE4CCUx +MCU_ST_STM32WL:STM32WLE4J8Ix +MCU_ST_STM32WL:STM32WLE4JBIx +MCU_ST_STM32WL:STM32WLE4JCIx +MCU_ST_STM32WL:STM32WLE5C8Ux +MCU_ST_STM32WL:STM32WLE5CBUx +MCU_ST_STM32WL:STM32WLE5CCUx +MCU_ST_STM32WL:STM32WLE5J8Ix +MCU_ST_STM32WL:STM32WLE5JBIx +MCU_ST_STM32WL:STM32WLE5JCIx +MCU_ST_STM8:STM8AF6223 +MCU_ST_STM8:STM8AF6223A +MCU_ST_STM8:STM8AL3188T +MCU_ST_STM8:STM8AL3189T +MCU_ST_STM8:STM8AL318AT +MCU_ST_STM8:STM8AL3L88T +MCU_ST_STM8:STM8AL3L89T +MCU_ST_STM8:STM8AL3L8AT +MCU_ST_STM8:STM8L051F3P +MCU_ST_STM8:STM8L101F1U +MCU_ST_STM8:STM8L101F2P +MCU_ST_STM8:STM8L101F2U +MCU_ST_STM8:STM8L101F3P +MCU_ST_STM8:STM8L101F3U +MCU_ST_STM8:STM8L151C2T +MCU_ST_STM8:STM8L151C3T +MCU_ST_STM8:STM8L152R6T +MCU_ST_STM8:STM8L152R8T +MCU_ST_STM8:STM8S001J3M +MCU_ST_STM8:STM8S003F3P +MCU_ST_STM8:STM8S003F3U +MCU_ST_STM8:STM8S003K3T +MCU_ST_STM8:STM8S207C6 +MCU_ST_STM8:STM8S207C8 +MCU_ST_STM8:STM8S207CB +MCU_ST_STM8:STM8S207MB +MCU_ST_STM8:STM8S207R6 +MCU_ST_STM8:STM8S207R8 +MCU_ST_STM8:STM8S207RB +MCU_ST_STM8:STM8S208C6 +MCU_ST_STM8:STM8S208C8 +MCU_ST_STM8:STM8S208CB +MCU_ST_STM8:STM8S208MB +MCU_ST_STM8:STM8S208R6 +MCU_ST_STM8:STM8S208R8 +MCU_ST_STM8:STM8S208RB +MCU_Texas:LM3S6911-EQC50 +MCU_Texas:LM3S6911-IQC50 +MCU_Texas:LM4F110B2QR +MCU_Texas:LM4F110C4QR +MCU_Texas:LM4F110E5QR +MCU_Texas:LM4F110H5QR +MCU_Texas:LM4F111B2QR +MCU_Texas:LM4F111C4QR +MCU_Texas:LM4F111E5QR +MCU_Texas:LM4F111H5QR +MCU_Texas:MSP432E401Y +MCU_Texas:TM4C1230C3PM +MCU_Texas:TM4C1230D5PM +MCU_Texas:TM4C1230E6PM +MCU_Texas:TM4C1230H6PM +MCU_Texas:TM4C1231C3PM +MCU_Texas:TM4C1231D5PM +MCU_Texas:TM4C1231E6PM +MCU_Texas:TM4C1231H6PM +MCU_Texas:TMS320LF2406 +MCU_Texas:TMS470R1B768 +MCU_Texas_MSP430:CC430F5133xRGZ +MCU_Texas_MSP430:CC430F5135xRGZ +MCU_Texas_MSP430:CC430F5137xRGZ +MCU_Texas_MSP430:MSP430AFE221IPW +MCU_Texas_MSP430:MSP430AFE222IPW +MCU_Texas_MSP430:MSP430AFE223IPW +MCU_Texas_MSP430:MSP430AFE231IPW +MCU_Texas_MSP430:MSP430AFE232IPW +MCU_Texas_MSP430:MSP430AFE233IPW +MCU_Texas_MSP430:MSP430AFE251IPW +MCU_Texas_MSP430:MSP430AFE252IPW +MCU_Texas_MSP430:MSP430AFE253IPW +MCU_Texas_MSP430:MSP430F1101AIDGV +MCU_Texas_MSP430:MSP430F1101AIDW +MCU_Texas_MSP430:MSP430F1101AIPW +MCU_Texas_MSP430:MSP430F1101AIRGE +MCU_Texas_MSP430:MSP430F1111AIDGV +MCU_Texas_MSP430:MSP430F1111AIDW +MCU_Texas_MSP430:MSP430F1111AIPW +MCU_Texas_MSP430:MSP430F1111AIRGE +MCU_Texas_MSP430:MSP430F1121AIDGV +MCU_Texas_MSP430:MSP430F1121AIDW +MCU_Texas_MSP430:MSP430F1121AIPW +MCU_Texas_MSP430:MSP430F1121AIRGE +MCU_Texas_MSP430:MSP430F1122IDW +MCU_Texas_MSP430:MSP430F1122IPW +MCU_Texas_MSP430:MSP430F1122IRHB +MCU_Texas_MSP430:MSP430F1132IDW +MCU_Texas_MSP430:MSP430F1132IPW +MCU_Texas_MSP430:MSP430F1132IRHB +MCU_Texas_MSP430:MSP430F1222IDW +MCU_Texas_MSP430:MSP430F1222IPW +MCU_Texas_MSP430:MSP430F1222IRHB +MCU_Texas_MSP430:MSP430F122IDW +MCU_Texas_MSP430:MSP430F122IPW +MCU_Texas_MSP430:MSP430F122IRHB +MCU_Texas_MSP430:MSP430F1232IDW +MCU_Texas_MSP430:MSP430F1232IPW +MCU_Texas_MSP430:MSP430F1232IRHB +MCU_Texas_MSP430:MSP430F123IDW +MCU_Texas_MSP430:MSP430F123IPW +MCU_Texas_MSP430:MSP430F123IRHB +MCU_Texas_MSP430:MSP430F2001IN +MCU_Texas_MSP430:MSP430F2001IPW +MCU_Texas_MSP430:MSP430F2001IRSA +MCU_Texas_MSP430:MSP430F2002IN +MCU_Texas_MSP430:MSP430F2002IPW +MCU_Texas_MSP430:MSP430F2002IRSA +MCU_Texas_MSP430:MSP430F2003IN +MCU_Texas_MSP430:MSP430F2003IPW +MCU_Texas_MSP430:MSP430F2003IRSA +MCU_Texas_MSP430:MSP430F2011IN +MCU_Texas_MSP430:MSP430F2011IPW +MCU_Texas_MSP430:MSP430F2011IRSA +MCU_Texas_MSP430:MSP430F2012IN +MCU_Texas_MSP430:MSP430F2012IPW +MCU_Texas_MSP430:MSP430F2012IRSA +MCU_Texas_MSP430:MSP430F2013IN +MCU_Texas_MSP430:MSP430F2013IPW +MCU_Texas_MSP430:MSP430F2013IRSA +MCU_Texas_MSP430:MSP430F2101IDGV +MCU_Texas_MSP430:MSP430F2101IDW +MCU_Texas_MSP430:MSP430F2101IPW +MCU_Texas_MSP430:MSP430F2101IRGE +MCU_Texas_MSP430:MSP430F2111IDGV +MCU_Texas_MSP430:MSP430F2111IDW +MCU_Texas_MSP430:MSP430F2111IPW +MCU_Texas_MSP430:MSP430F2111IRGE +MCU_Texas_MSP430:MSP430F2112IPW +MCU_Texas_MSP430:MSP430F2112IRHB +MCU_Texas_MSP430:MSP430F2112IRTV +MCU_Texas_MSP430:MSP430F2121IDGV +MCU_Texas_MSP430:MSP430F2121IDW +MCU_Texas_MSP430:MSP430F2121IPW +MCU_Texas_MSP430:MSP430F2121IRGE +MCU_Texas_MSP430:MSP430F2122IPW +MCU_Texas_MSP430:MSP430F2122IRHB +MCU_Texas_MSP430:MSP430F2122IRTV +MCU_Texas_MSP430:MSP430F2131IDGV +MCU_Texas_MSP430:MSP430F2131IDW +MCU_Texas_MSP430:MSP430F2131IPW +MCU_Texas_MSP430:MSP430F2131IRGE +MCU_Texas_MSP430:MSP430F2132IPW +MCU_Texas_MSP430:MSP430F2132IRHB +MCU_Texas_MSP430:MSP430F2132IRTV +MCU_Texas_MSP430:MSP430F2232IDA +MCU_Texas_MSP430:MSP430F2232IRHA +MCU_Texas_MSP430:MSP430F2232IYFF +MCU_Texas_MSP430:MSP430F2234IDA +MCU_Texas_MSP430:MSP430F2234IRHA +MCU_Texas_MSP430:MSP430F2234IYFF +MCU_Texas_MSP430:MSP430F2252IDA +MCU_Texas_MSP430:MSP430F2252IRHA +MCU_Texas_MSP430:MSP430F2252IYFF +MCU_Texas_MSP430:MSP430F2254IDA +MCU_Texas_MSP430:MSP430F2254IRHA +MCU_Texas_MSP430:MSP430F2254IYFF +MCU_Texas_MSP430:MSP430F2272IDA +MCU_Texas_MSP430:MSP430F2272IRHA +MCU_Texas_MSP430:MSP430F2272IYFF +MCU_Texas_MSP430:MSP430F2274IDA +MCU_Texas_MSP430:MSP430F2274IRHA +MCU_Texas_MSP430:MSP430F2274IYFF +MCU_Texas_MSP430:MSP430F2330IRHA +MCU_Texas_MSP430:MSP430F2330IYFF +MCU_Texas_MSP430:MSP430F2350IRHA +MCU_Texas_MSP430:MSP430F2350IYFF +MCU_Texas_MSP430:MSP430F2370IRHA +MCU_Texas_MSP430:MSP430F2370IYFF +MCU_Texas_MSP430:MSP430F2618-EP +MCU_Texas_MSP430:MSP430F5217IRGC +MCU_Texas_MSP430:MSP430F5217IYFF +MCU_Texas_MSP430:MSP430F5219IRGC +MCU_Texas_MSP430:MSP430F5219IYFF +MCU_Texas_MSP430:MSP430F5227IRGC +MCU_Texas_MSP430:MSP430F5227IYFF +MCU_Texas_MSP430:MSP430F5229IRGC +MCU_Texas_MSP430:MSP430F5229IYFF +MCU_Texas_MSP430:MSP430F5232IRGZ +MCU_Texas_MSP430:MSP430F5234IRGZ +MCU_Texas_MSP430:MSP430F5237IRGC +MCU_Texas_MSP430:MSP430F5239IRGC +MCU_Texas_MSP430:MSP430F5242IRGZ +MCU_Texas_MSP430:MSP430F5244IRGZ +MCU_Texas_MSP430:MSP430F5247IRGC +MCU_Texas_MSP430:MSP430F5249IRGC +MCU_Texas_MSP430:MSP430F5304IPT +MCU_Texas_MSP430:MSP430F5304IRGZ +MCU_Texas_MSP430:MSP430F5308IPT +MCU_Texas_MSP430:MSP430F5308IRGC +MCU_Texas_MSP430:MSP430F5308IRGZ +MCU_Texas_MSP430:MSP430F5308IZQE +MCU_Texas_MSP430:MSP430F5309IPT +MCU_Texas_MSP430:MSP430F5309IRGC +MCU_Texas_MSP430:MSP430F5309IRGZ +MCU_Texas_MSP430:MSP430F5309IZQE +MCU_Texas_MSP430:MSP430F5310IPT +MCU_Texas_MSP430:MSP430F5310IRGC +MCU_Texas_MSP430:MSP430F5310IRGZ +MCU_Texas_MSP430:MSP430F5310IZQE +MCU_Texas_MSP430:MSP430F5333IPZ +MCU_Texas_MSP430:MSP430F5333IZQW +MCU_Texas_MSP430:MSP430F5335IPZ +MCU_Texas_MSP430:MSP430F5335IZQW +MCU_Texas_MSP430:MSP430F5336IPZ +MCU_Texas_MSP430:MSP430F5336IZQW +MCU_Texas_MSP430:MSP430F5338IPZ +MCU_Texas_MSP430:MSP430F5338IZQW +MCU_Texas_MSP430:MSP430F5340IRGZ +MCU_Texas_MSP430:MSP430F5341IRGZ +MCU_Texas_MSP430:MSP430F5342IRGZ +MCU_Texas_MSP430:MSP430F5358IZQW +MCU_Texas_MSP430:MSP430F5359IZQW +MCU_Texas_MSP430:MSP430F5500IRGZ +MCU_Texas_MSP430:MSP430F5501IRGZ +MCU_Texas_MSP430:MSP430F5502IRGZ +MCU_Texas_MSP430:MSP430F5503IRGZ +MCU_Texas_MSP430:MSP430F5504IRGZ +MCU_Texas_MSP430:MSP430F5505IRGZ +MCU_Texas_MSP430:MSP430F5506IRGZ +MCU_Texas_MSP430:MSP430F5507IRGZ +MCU_Texas_MSP430:MSP430F5508IRGZ +MCU_Texas_MSP430:MSP430F5509IRGZ +MCU_Texas_MSP430:MSP430F5510IRGZ +MCU_Texas_MSP430:MSP430F5524IYFF +MCU_Texas_MSP430:MSP430F5526IYFF +MCU_Texas_MSP430:MSP430F5528IYFF +MCU_Texas_MSP430:MSP430F5630IZQW +MCU_Texas_MSP430:MSP430F5631IZQW +MCU_Texas_MSP430:MSP430F5632IZQW +MCU_Texas_MSP430:MSP430F5633IZQW +MCU_Texas_MSP430:MSP430F5634IZQW +MCU_Texas_MSP430:MSP430F5635IZQW +MCU_Texas_MSP430:MSP430F5636IZQW +MCU_Texas_MSP430:MSP430F5637IZQW +MCU_Texas_MSP430:MSP430F5638IZQW +MCU_Texas_MSP430:MSP430F5658IZQW +MCU_Texas_MSP430:MSP430F5659IZQW +MCU_Texas_MSP430:MSP430FR5720IRGE +MCU_Texas_MSP430:MSP430FR5722IRGE +MCU_Texas_MSP430:MSP430FR5724IRGE +MCU_Texas_MSP430:MSP430FR5726IRGE +MCU_Texas_MSP430:MSP430FR5728IRGE +MCU_Texas_MSP430:MSP430FR5730IRGE +MCU_Texas_MSP430:MSP430FR5732IRGE +MCU_Texas_MSP430:MSP430FR5734IRGE +MCU_Texas_MSP430:MSP430FR5736IRGE +MCU_Texas_MSP430:MSP430FR5738IRGE +MCU_Texas_MSP430:MSP430G2001IN14 +MCU_Texas_MSP430:MSP430G2001IPW14 +MCU_Texas_MSP430:MSP430G2001IRSA16 +MCU_Texas_MSP430:MSP430G2101IN14 +MCU_Texas_MSP430:MSP430G2101IPW14 +MCU_Texas_MSP430:MSP430G2101IRSA16 +MCU_Texas_MSP430:MSP430G2102IN20 +MCU_Texas_MSP430:MSP430G2102IPW14 +MCU_Texas_MSP430:MSP430G2102IPW20 +MCU_Texas_MSP430:MSP430G2102IRSA16 +MCU_Texas_MSP430:MSP430G2111IN14 +MCU_Texas_MSP430:MSP430G2111IPW14 +MCU_Texas_MSP430:MSP430G2111IRSA16 +MCU_Texas_MSP430:MSP430G2112IN20 +MCU_Texas_MSP430:MSP430G2112IPW14 +MCU_Texas_MSP430:MSP430G2112IPW20 +MCU_Texas_MSP430:MSP430G2112IRSA16 +MCU_Texas_MSP430:MSP430G2113IPW20 +MCU_Texas_MSP430:MSP430G2121IN14 +MCU_Texas_MSP430:MSP430G2121IPW14 +MCU_Texas_MSP430:MSP430G2121IRSA16 +MCU_Texas_MSP430:MSP430G2131IN14 +MCU_Texas_MSP430:MSP430G2131IPW14 +MCU_Texas_MSP430:MSP430G2131IRSA16 +MCU_Texas_MSP430:MSP430G2132IN20 +MCU_Texas_MSP430:MSP430G2132IPW14 +MCU_Texas_MSP430:MSP430G2132IPW20 +MCU_Texas_MSP430:MSP430G2132IRSA16 +MCU_Texas_MSP430:MSP430G2152IN20 +MCU_Texas_MSP430:MSP430G2152IPW14 +MCU_Texas_MSP430:MSP430G2152IPW20 +MCU_Texas_MSP430:MSP430G2152IRSA16 +MCU_Texas_MSP430:MSP430G2153IN20 +MCU_Texas_MSP430:MSP430G2153IPW20 +MCU_Texas_MSP430:MSP430G2153IPW28 +MCU_Texas_MSP430:MSP430G2153IRHB32 +MCU_Texas_MSP430:MSP430G2201IN14 +MCU_Texas_MSP430:MSP430G2201IPW14 +MCU_Texas_MSP430:MSP430G2201IRSA16 +MCU_Texas_MSP430:MSP430G2202IN20 +MCU_Texas_MSP430:MSP430G2202IPW14 +MCU_Texas_MSP430:MSP430G2202IPW20 +MCU_Texas_MSP430:MSP430G2202IRSA16 +MCU_Texas_MSP430:MSP430G2203IN20 +MCU_Texas_MSP430:MSP430G2203IPW20 +MCU_Texas_MSP430:MSP430G2203IPW28 +MCU_Texas_MSP430:MSP430G2203IRHB32 +MCU_Texas_MSP430:MSP430G2210ID +MCU_Texas_MSP430:MSP430G2211IN14 +MCU_Texas_MSP430:MSP430G2211IPW14 +MCU_Texas_MSP430:MSP430G2211IRSA16 +MCU_Texas_MSP430:MSP430G2212IN20 +MCU_Texas_MSP430:MSP430G2212IPW14 +MCU_Texas_MSP430:MSP430G2212IPW20 +MCU_Texas_MSP430:MSP430G2212IRSA16 +MCU_Texas_MSP430:MSP430G2213IN20 +MCU_Texas_MSP430:MSP430G2213IPW20 +MCU_Texas_MSP430:MSP430G2213IPW28 +MCU_Texas_MSP430:MSP430G2213IRHB32 +MCU_Texas_MSP430:MSP430G2221IN14 +MCU_Texas_MSP430:MSP430G2221IPW14 +MCU_Texas_MSP430:MSP430G2221IRSA16 +MCU_Texas_MSP430:MSP430G2230ID +MCU_Texas_MSP430:MSP430G2231IN14 +MCU_Texas_MSP430:MSP430G2231IPW14 +MCU_Texas_MSP430:MSP430G2231IRSA16 +MCU_Texas_MSP430:MSP430G2232IN20 +MCU_Texas_MSP430:MSP430G2232IPW14 +MCU_Texas_MSP430:MSP430G2232IPW20 +MCU_Texas_MSP430:MSP430G2232IRSA16 +MCU_Texas_MSP430:MSP430G2233IN20 +MCU_Texas_MSP430:MSP430G2233IPW20 +MCU_Texas_MSP430:MSP430G2233IPW28 +MCU_Texas_MSP430:MSP430G2233IRHB32 +MCU_Texas_MSP430:MSP430G2252IN20 +MCU_Texas_MSP430:MSP430G2252IPW14 +MCU_Texas_MSP430:MSP430G2252IPW20 +MCU_Texas_MSP430:MSP430G2252IRSA16 +MCU_Texas_MSP430:MSP430G2253IN20 +MCU_Texas_MSP430:MSP430G2253IPW20 +MCU_Texas_MSP430:MSP430G2253IPW28 +MCU_Texas_MSP430:MSP430G2253IRHB32 +MCU_Texas_MSP430:MSP430G2302IN20 +MCU_Texas_MSP430:MSP430G2302IPW14 +MCU_Texas_MSP430:MSP430G2302IPW20 +MCU_Texas_MSP430:MSP430G2302IRSA16 +MCU_Texas_MSP430:MSP430G2303IN20 +MCU_Texas_MSP430:MSP430G2303IPW20 +MCU_Texas_MSP430:MSP430G2303IPW28 +MCU_Texas_MSP430:MSP430G2303IRHB32 +MCU_Texas_MSP430:MSP430G2312IN20 +MCU_Texas_MSP430:MSP430G2312IPW14 +MCU_Texas_MSP430:MSP430G2312IPW20 +MCU_Texas_MSP430:MSP430G2312IRSA16 +MCU_Texas_MSP430:MSP430G2313IN20 +MCU_Texas_MSP430:MSP430G2313IPW20 +MCU_Texas_MSP430:MSP430G2313IPW28 +MCU_Texas_MSP430:MSP430G2313IRHB32 +MCU_Texas_MSP430:MSP430G2332IN20 +MCU_Texas_MSP430:MSP430G2332IPW14 +MCU_Texas_MSP430:MSP430G2332IPW20 +MCU_Texas_MSP430:MSP430G2332IRSA16 +MCU_Texas_MSP430:MSP430G2333IN20 +MCU_Texas_MSP430:MSP430G2333IPW20 +MCU_Texas_MSP430:MSP430G2333IPW28 +MCU_Texas_MSP430:MSP430G2333IRHB32 +MCU_Texas_MSP430:MSP430G2352IN20 +MCU_Texas_MSP430:MSP430G2352IPW14 +MCU_Texas_MSP430:MSP430G2352IPW20 +MCU_Texas_MSP430:MSP430G2352IRSA16 +MCU_Texas_MSP430:MSP430G2353IN20 +MCU_Texas_MSP430:MSP430G2353IPW20 +MCU_Texas_MSP430:MSP430G2353IPW28 +MCU_Texas_MSP430:MSP430G2353IRHB32 +MCU_Texas_MSP430:MSP430G2402IN20 +MCU_Texas_MSP430:MSP430G2402IPW14 +MCU_Texas_MSP430:MSP430G2402IPW20 +MCU_Texas_MSP430:MSP430G2402IRSA16 +MCU_Texas_MSP430:MSP430G2403IN20 +MCU_Texas_MSP430:MSP430G2403IPW20 +MCU_Texas_MSP430:MSP430G2403IPW28 +MCU_Texas_MSP430:MSP430G2403IRHB32 +MCU_Texas_MSP430:MSP430G2412IN20 +MCU_Texas_MSP430:MSP430G2412IPW14 +MCU_Texas_MSP430:MSP430G2412IPW20 +MCU_Texas_MSP430:MSP430G2412IRSA16 +MCU_Texas_MSP430:MSP430G2413IN20 +MCU_Texas_MSP430:MSP430G2413IPW20 +MCU_Texas_MSP430:MSP430G2413IPW28 +MCU_Texas_MSP430:MSP430G2413IRHB32 +MCU_Texas_MSP430:MSP430G2432IN20 +MCU_Texas_MSP430:MSP430G2432IPW14 +MCU_Texas_MSP430:MSP430G2432IPW20 +MCU_Texas_MSP430:MSP430G2432IRSA16 +MCU_Texas_MSP430:MSP430G2433IN20 +MCU_Texas_MSP430:MSP430G2433IPW20 +MCU_Texas_MSP430:MSP430G2433IPW28 +MCU_Texas_MSP430:MSP430G2433IRHB32 +MCU_Texas_MSP430:MSP430G2444IDA38 +MCU_Texas_MSP430:MSP430G2444IRHA40 +MCU_Texas_MSP430:MSP430G2444IYFF +MCU_Texas_MSP430:MSP430G2452IN20 +MCU_Texas_MSP430:MSP430G2452IPW14 +MCU_Texas_MSP430:MSP430G2452IPW20 +MCU_Texas_MSP430:MSP430G2452IRSA16 +MCU_Texas_MSP430:MSP430G2453IN20 +MCU_Texas_MSP430:MSP430G2453IPW20 +MCU_Texas_MSP430:MSP430G2453IPW28 +MCU_Texas_MSP430:MSP430G2453IRHB32 +MCU_Texas_MSP430:MSP430G2513IN20 +MCU_Texas_MSP430:MSP430G2513IPW20 +MCU_Texas_MSP430:MSP430G2513IPW28 +MCU_Texas_MSP430:MSP430G2513IRHB32 +MCU_Texas_MSP430:MSP430G2533IN20 +MCU_Texas_MSP430:MSP430G2533IPW20 +MCU_Texas_MSP430:MSP430G2533IPW28 +MCU_Texas_MSP430:MSP430G2533IRHB32 +MCU_Texas_MSP430:MSP430G2544IDA38 +MCU_Texas_MSP430:MSP430G2544IRHA40 +MCU_Texas_MSP430:MSP430G2544IYFF +MCU_Texas_MSP430:MSP430G2553IN20 +MCU_Texas_MSP430:MSP430G2553IPW20 +MCU_Texas_MSP430:MSP430G2553IPW28 +MCU_Texas_MSP430:MSP430G2553IRHB32 +MCU_Texas_MSP430:MSP430G2744IDA38 +MCU_Texas_MSP430:MSP430G2744IRHA40 +MCU_Texas_MSP430:MSP430G2744IYFF +MCU_Texas_MSP430:MSP430G2755IDA38 +MCU_Texas_MSP430:MSP430G2755IRHA40 +MCU_Texas_MSP430:MSP430G2855IDA38 +MCU_Texas_MSP430:MSP430G2855IRHA40 +MCU_Texas_MSP430:MSP430G2955IDA38 +MCU_Texas_MSP430:MSP430G2955IRHA40 +MCU_Texas_SimpleLink:CC1312R1F3RGZ +MCU_WCH_CH32V0:CH32V003AxMx +MCU_WCH_CH32V0:CH32V003FxPx +MCU_WCH_CH32V0:CH32V003FxUx +MCU_WCH_CH32V0:CH32V003JxMx +MCU_WCH_CH32V2:CH32V203CxTx +MCU_WCH_CH32V2:CH32V203F6P6 +MCU_WCH_CH32V2:CH32V203GxUx +MCU_WCH_CH32V3:CH32V30xCxTx +MCU_WCH_CH32V3:CH32V30xFxPx +MCU_WCH_CH32V3:CH32V30xRxTx +MCU_WCH_CH32V3:CH32V30xVxTx +MCU_WCH_CH32V3:CH32V30xWxUx +MCU_WCH_CH32X0:CH32X035G8U6 +Mechanical:DIN_Rail_Adapter +Mechanical:Fiducial +Mechanical:Heatsink +Mechanical:Heatsink_Pad +Mechanical:Heatsink_Pad_2Pin +Mechanical:Heatsink_Pad_3Pin +Mechanical:Housing +Mechanical:Housing_Pad +Mechanical:MountingHole +Mechanical:MountingHole_Pad +Mechanical:MountingHole_Pad_MP +Memory_EEPROM:24AA02-OT +Memory_EEPROM:24AA025E-OT +Memory_EEPROM:24AA025E-SN +Memory_EEPROM:24AA02E-OT +Memory_EEPROM:24AA02E-SN +Memory_EEPROM:24LC00 +Memory_EEPROM:24LC01 +Memory_EEPROM:24LC02 +Memory_EEPROM:24LC04 +Memory_EEPROM:24LC08 +Memory_EEPROM:24LC1025 +Memory_EEPROM:24LC128 +Memory_EEPROM:24LC16 +Memory_EEPROM:24LC256 +Memory_EEPROM:24LC32 +Memory_EEPROM:24LC512 +Memory_EEPROM:24LC64 +Memory_EEPROM:25CSM04xxMF +Memory_EEPROM:25CSM04xxSN +Memory_EEPROM:25LCxxx +Memory_EEPROM:25LCxxx-MC +Memory_EEPROM:25LCxxx-MF +Memory_EEPROM:28C256 +Memory_EEPROM:93AAxxA +Memory_EEPROM:93AAxxAT-xOT +Memory_EEPROM:93AAxxB +Memory_EEPROM:93AAxxBT-xOT +Memory_EEPROM:93AAxxC +Memory_EEPROM:93CxxA +Memory_EEPROM:93CxxB +Memory_EEPROM:93CxxC +Memory_EEPROM:93LCxxA +Memory_EEPROM:93LCxxAxxOT +Memory_EEPROM:93LCxxB +Memory_EEPROM:93LCxxBxxOT +Memory_EEPROM:93LCxxC +Memory_EEPROM:AT24CS01-MAHM +Memory_EEPROM:AT24CS01-SSHM +Memory_EEPROM:AT24CS01-STUM +Memory_EEPROM:AT24CS01-XHM +Memory_EEPROM:AT24CS02-MAHM +Memory_EEPROM:AT24CS02-SSHM +Memory_EEPROM:AT24CS02-STUM +Memory_EEPROM:AT24CS02-XHM +Memory_EEPROM:AT24CS04-MAHM +Memory_EEPROM:AT24CS04-SSHM +Memory_EEPROM:AT24CS04-STUM +Memory_EEPROM:AT24CS04-XHM +Memory_EEPROM:AT24CS08-MAHM +Memory_EEPROM:AT24CS08-SSHM +Memory_EEPROM:AT24CS08-STUM +Memory_EEPROM:AT24CS08-XHM +Memory_EEPROM:AT24CS16-MAHM +Memory_EEPROM:AT24CS16-SSHM +Memory_EEPROM:AT24CS16-STUM +Memory_EEPROM:AT24CS16-XHM +Memory_EEPROM:AT24CS32-MAHM +Memory_EEPROM:AT24CS32-SSHM +Memory_EEPROM:AT24CS32-STUM +Memory_EEPROM:AT24CS32-XHM +Memory_EEPROM:AT24CS64-MAHM +Memory_EEPROM:AT24CS64-SSHM +Memory_EEPROM:AT24CS64-XHM +Memory_EEPROM:AT25xxx +Memory_EEPROM:AT25xxx-MA +Memory_EEPROM:BR25Sxxx +Memory_EEPROM:BR25xxx-NUX +Memory_EEPROM:CAT24C128 +Memory_EEPROM:CAT24C256 +Memory_EEPROM:CAT24M01L +Memory_EEPROM:CAT24M01W +Memory_EEPROM:CAT24M01X +Memory_EEPROM:CAT24M01Y +Memory_EEPROM:CAT250xxx +Memory_EEPROM:CAT250xxx-HU4 +Memory_EEPROM:DS2431 +Memory_EEPROM:DS2431P +Memory_EEPROM:DS2431Q +Memory_EEPROM:DS28E07 +Memory_EEPROM:DS28E07P +Memory_EEPROM:DS28E07Q +Memory_EEPROM:KM28C64A +Memory_EEPROM:KM28C65A +Memory_EEPROM:M24C01-FDW +Memory_EEPROM:M24C01-FMN +Memory_EEPROM:M24C01-RDW +Memory_EEPROM:M24C01-RMN +Memory_EEPROM:M24C01-WDW +Memory_EEPROM:M24C01-WMN +Memory_EEPROM:M24C02-FDW +Memory_EEPROM:M24C02-FMN +Memory_EEPROM:M24C02-RDW +Memory_EEPROM:M24C02-RMN +Memory_EEPROM:M24C02-WDW +Memory_EEPROM:M24C02-WMN +Memory_EEPROM:M95256-WMN6P +Memory_EEPROM:M95512-Axxx-MF +Memory_EEPROM:TMS4C1050N +Memory_EPROM:27128 +Memory_EPROM:27256 +Memory_EPROM:27512 +Memory_EPROM:2764 +Memory_EPROM:27C010 +Memory_EPROM:27C020 +Memory_EPROM:27C040 +Memory_EPROM:27C080 +Memory_EPROM:27C128 +Memory_EPROM:27C256 +Memory_EPROM:27C512 +Memory_EPROM:27C512PLCC +Memory_EPROM:27C64 +Memory_Flash:28F400 +Memory_Flash:29F010-TSOP-SP +Memory_Flash:29W040 +Memory_Flash:AM29F400BB-90SC +Memory_Flash:AM29F400Bx-xxEx +Memory_Flash:AM29F400Bx-xxSx +Memory_Flash:AM29PDL128G +Memory_Flash:AT25DF041x-UxN-x +Memory_Flash:AT25SF081-SSHD-X +Memory_Flash:AT25SF081-SSHF-X +Memory_Flash:AT25SF081-XMHD-X +Memory_Flash:AT25SF081-XMHF-X +Memory_Flash:AT25SL321-U +Memory_Flash:AT45DB161-JC +Memory_Flash:AT45DB161-RC +Memory_Flash:AT45DB161-TC +Memory_Flash:AT45DB161B-RC +Memory_Flash:AT45DB161B-RC-2.5 +Memory_Flash:AT45DB161B-TC +Memory_Flash:AT45DB161B-TC-2.5 +Memory_Flash:AT45DB161D-SU +Memory_Flash:GD25D05CT +Memory_Flash:GD25D10CT +Memory_Flash:GD25QxxxEY +Memory_Flash:IS25WP256D-xM +Memory_Flash:M25PX32-VMP +Memory_Flash:M25PX32-VMW +Memory_Flash:M29W004 +Memory_Flash:M29W008 +Memory_Flash:MT25QUxxxxxx1xW7 +Memory_Flash:MX25L3233FM +Memory_Flash:MX25L3233FM1 +Memory_Flash:MX25L3233FM2 +Memory_Flash:MX25L3233FZN +Memory_Flash:MX25R3235FM1xx0 +Memory_Flash:MX25R3235FM1xx1 +Memory_Flash:MX25R3235FM2xx0 +Memory_Flash:MX25R3235FM2xx1 +Memory_Flash:MX25R3235FZNxx0 +Memory_Flash:MX25R3235FZNxx1 +Memory_Flash:SST25VF080B-50-4x-S2Ax +Memory_Flash:SST39SF010 +Memory_Flash:SST39SF020 +Memory_Flash:SST39SF040 +Memory_Flash:W25Q128JVE +Memory_Flash:W25Q128JVP +Memory_Flash:W25Q128JVS +Memory_Flash:W25Q16JVSS +Memory_Flash:W25Q32JVSS +Memory_Flash:W25Q32JVZP +Memory_Flash:W25X20CLSN +Memory_Flash:W25X20CLZP +Memory_Flash:W25X40CLSN +Memory_Flash:W25X40CLSS +Memory_Flash:W25X40CLSV +Memory_Flash:XTSD01G +Memory_Flash:XTSD02G +Memory_Flash:XTSD04G +Memory_Flash:XTSD08G +Memory_NVRAM:47C04 +Memory_NVRAM:47C16 +Memory_NVRAM:47L04 +Memory_NVRAM:47L16 +Memory_NVRAM:CY14B256LA-SP +Memory_NVRAM:CY14B256LA-SZ +Memory_NVRAM:CY14B256LA-ZS +Memory_NVRAM:CY14E256LA-SZ +Memory_NVRAM:CY14E256LA-ZS +Memory_NVRAM:CY14U256LA-BA +Memory_NVRAM:CY14V256LA-BA +Memory_NVRAM:FM1608B-SG +Memory_NVRAM:FM16W08-SG +Memory_NVRAM:FM1808B-SG +Memory_NVRAM:FM18W08-SG +Memory_NVRAM:FM24C64B +Memory_NVRAM:FM24C64C +Memory_NVRAM:FM24CL16B +Memory_NVRAM:MB85RS128B +Memory_NVRAM:MB85RS16 +Memory_NVRAM:MB85RS1MT +Memory_NVRAM:MB85RS256B +Memory_NVRAM:MB85RS2MT +Memory_NVRAM:MB85RS512T +Memory_NVRAM:MB85RS64 +Memory_NVRAM:MR20H40 +Memory_NVRAM:MR25H40 +Memory_NVRAM:STK14C88 +Memory_NVRAM:STK14C88-3 +Memory_NVRAM:STK14C88C +Memory_NVRAM:STK14C88C-3 +Memory_RAM:AS4C256M16D3 +Memory_RAM:AS4C4M16SA +Memory_RAM:AS6C1008-xxB +Memory_RAM:AS6C1008-xxP +Memory_RAM:AS6C1008-xxS +Memory_RAM:AS6C1008-xxST +Memory_RAM:AS6C1008-xxT +Memory_RAM:AS6C1616 +Memory_RAM:AS6C4008-55PCN +Memory_RAM:AS7C1024B-xxJ +Memory_RAM:AS7C1024B-xxT +Memory_RAM:AS7C1024B-xxTJ +Memory_RAM:AS7C31024B-xxJ +Memory_RAM:AS7C31024B-xxST +Memory_RAM:AS7C31024B-xxT +Memory_RAM:AS7C31024B-xxTJ +Memory_RAM:CY62128EV30xx-xxS +Memory_RAM:CY62128EV30xx-xxZ +Memory_RAM:CY62128Exx-xxS +Memory_RAM:CY62128Exx-xxZ +Memory_RAM:CY62256-70PC +Memory_RAM:CY7C199 +Memory_RAM:ESP-PSRAM32 +Memory_RAM:H5AN8G8NAFR-UHC +Memory_RAM:HM62256BLP +Memory_RAM:HM628128D_DIP32_SOP32 +Memory_RAM:HM628128D_TSOP32 +Memory_RAM:HM628128_DIP32_SOP32 +Memory_RAM:HM628128_TSOP32 +Memory_RAM:HY6264AxJ +Memory_RAM:HY6264AxP +Memory_RAM:IDT7006PF +Memory_RAM:IDT7027_TQ100 +Memory_RAM:IDT7132 +Memory_RAM:IDT71V65903S +Memory_RAM:IDT7201 +Memory_RAM:IDT7202 +Memory_RAM:IDT7203 +Memory_RAM:IDT7204 +Memory_RAM:IDT7205 +Memory_RAM:IDT7206 +Memory_RAM:IDT7207 +Memory_RAM:IDT7208 +Memory_RAM:IS42S16400J-xC +Memory_RAM:IS42S16400J-xT +Memory_RAM:IS43LQ32256A-062BLI +Memory_RAM:IS43LQ32256AL-062BLI +Memory_RAM:IS61C5128AL-10KLI +Memory_RAM:IS61C5128AL-10TLI +Memory_RAM:IS61C5128AS-25HLI +Memory_RAM:IS61C5128AS-25QLI +Memory_RAM:IS61C5128AS-25TLI +Memory_RAM:IS62C256AL +Memory_RAM:IS64C5128AL-12CTLA3 +Memory_RAM:IS64C5128AL-12KLA3 +Memory_RAM:IS65C256AL +Memory_RAM:IS6xC1024AL-xxH +Memory_RAM:IS6xC1024AL-xxJ +Memory_RAM:IS6xC1024AL-xxK +Memory_RAM:IS6xC1024AL-xxT +Memory_RAM:KM62256CLP +Memory_RAM:M48Tx2 +Memory_RAM:M48Zx2 +Memory_RAM:MK4116N +Memory_RAM:MK4164N +Memory_RAM:MT48LC16M16A2P +Memory_RAM:MT48LC16M16A2TG +Memory_RAM:MT48LC32M8A2P +Memory_RAM:MT48LC32M8A2TG +Memory_RAM:MT48LC64M4A2P +Memory_RAM:MT48LC64M4A2TG +Memory_RAM:R1LP0108ESF +Memory_RAM:R1LP0108ESN +Memory_RAM:W9812G6KH-5 +Memory_RAM:W9812G6KH-6 +Memory_RAM:W9812G6KH-6I +Memory_RAM:W9812G6KH-75 +Memory_ROM:XC18V01SO20 +Memory_ROM:XCF08P +Memory_UniqueID:DS2401P +Memory_UniqueID:DS2401Z +Motor:Fan +Motor:Fan_3pin +Motor:Fan_4pin +Motor:Fan_ALT +Motor:Fan_CPU_4pin +Motor:Fan_IEC-60617 +Motor:Fan_ISO-14617 +Motor:Fan_PC_Chassis +Motor:Fan_Tacho +Motor:Fan_Tacho_PWM +Motor:Motor_AC +Motor:Motor_DC +Motor:Motor_DC_ALT +Motor:Motor_Servo +Motor:Motor_Servo_AirTronics +Motor:Motor_Servo_Futaba_J +Motor:Motor_Servo_Grapner_JR +Motor:Motor_Servo_Hitec +Motor:Motor_Servo_JR +Motor:Motor_Servo_Robbe +Motor:Stepper_Motor_bipolar +Motor:Stepper_Motor_unipolar_5pin +Motor:Stepper_Motor_unipolar_6pin +Oscillator:5P49V6965 +Oscillator:ABLNO +Oscillator:ACO-xxxMHz +Oscillator:ACO-xxxMHz-A +Oscillator:ASCO +Oscillator:ASDMB-xxxMHz +Oscillator:ASE-xxxMHz +Oscillator:ASV-xxxMHz +Oscillator:CFPS-72 +Oscillator:CVCO55xx +Oscillator:CXO_DIP14 +Oscillator:CXO_DIP8 +Oscillator:DFA-S11 +Oscillator:DFA-S15 +Oscillator:DFA-S2 +Oscillator:DFA-S3 +Oscillator:DGOF5S3 +Oscillator:ECS-2520MV-xxx-xx +Oscillator:FT5HN +Oscillator:FT5HV +Oscillator:GTXO-14T +Oscillator:GTXO-14V +Oscillator:GTXO-S14T +Oscillator:GTXO-S14V +Oscillator:IQXO-70 +Oscillator:JTOS-25 +Oscillator:JTOS-50 +Oscillator:KC2520Z +Oscillator:KT2520K-T +Oscillator:LTC6905xS5-100 +Oscillator:LTC6905xS5-133 +Oscillator:LTC6905xS5-80 +Oscillator:LTC6905xS5-96 +Oscillator:MAX7375AXR105 +Oscillator:MAX7375AXR185 +Oscillator:MAX7375AXR365 +Oscillator:MAX7375AXR375 +Oscillator:MAX7375AXR405 +Oscillator:MAX7375AXR425 +Oscillator:MAX7375AXR805 +Oscillator:MV267 +Oscillator:MV317 +Oscillator:NB3N502 +Oscillator:NB3N511 +Oscillator:OCXO-14 +Oscillator:OH300 +Oscillator:SG-210SCD +Oscillator:SG-210SDD +Oscillator:SG-210SED +Oscillator:SG-210STF +Oscillator:SG-211 +Oscillator:SG-3030CM +Oscillator:SG-5032CAN +Oscillator:SG-5032CBN +Oscillator:SG-5032CCN +Oscillator:SG-51 +Oscillator:SG-531 +Oscillator:SG-615 +Oscillator:SG-7050CAN +Oscillator:SG-7050CBN +Oscillator:SG-7050CCN +Oscillator:SG-8002CA +Oscillator:SG-8002CE +Oscillator:SG-8002DB +Oscillator:SG-8002DC +Oscillator:SG-8002JA +Oscillator:SG-8002JC +Oscillator:SG-8002LB +Oscillator:Si512A_2.5x3.2mm +Oscillator:Si513A_2.5x3.2mm +Oscillator:Si5351A-B-GM +Oscillator:Si5351A-B-GT +Oscillator:Si5351B-B-GM +Oscillator:Si5351C-B-GM +Oscillator:Si570 +Oscillator:Si571 +Oscillator:SiT8008xx-1x-xxE +Oscillator:SiT8008xx-1x-xxN +Oscillator:SiT8008xx-1x-xxS +Oscillator:SiT8008xx-2x-xxE +Oscillator:SiT8008xx-2x-xxN +Oscillator:SiT8008xx-2x-xxS +Oscillator:SiT8008xx-3x-xxE +Oscillator:SiT8008xx-3x-xxN +Oscillator:SiT8008xx-3x-xxS +Oscillator:SiT8008xx-7x-xxE +Oscillator:SiT8008xx-7x-xxN +Oscillator:SiT8008xx-7x-xxS +Oscillator:SiT8008xx-8x-xxE +Oscillator:SiT8008xx-8x-xxN +Oscillator:SiT8008xx-8x-xxS +Oscillator:SiT9365xx-xBx-xxE +Oscillator:SiT9365xx-xBx-xxN +Oscillator:SiT9366xx-xBx-xxE +Oscillator:SiT9366xx-xBx-xxN +Oscillator:SiT9367xx-xBx-xxE +Oscillator:SiT9367xx-xBx-xxN +Oscillator:TCXO-14 +Oscillator:TCXO3 +Oscillator:TFT660 +Oscillator:TFT680 +Oscillator:TG2520SMN-xx.xxxxxxMhz-xxxxNM +Oscillator:TXC-7C +Oscillator:VC-81 +Oscillator:VC-83 +Oscillator:VTCXO-14 +Oscillator:XO32 +Oscillator:XO53 +Oscillator:XO91 +Oscillator:XUX51 +Oscillator:XUX52 +Oscillator:XUX53 +Oscillator:XUX71 +Oscillator:XUX72 +Oscillator:XUX73 +Oscillator:XUY51 +Oscillator:XUY52 +Oscillator:XUY53 +Oscillator:XUY71 +Oscillator:XUY72 +Oscillator:XUY73 +Potentiometer_Digital:AD5253 +Potentiometer_Digital:AD5254 +Potentiometer_Digital:AD5272BCP +Potentiometer_Digital:AD5272BRM +Potentiometer_Digital:AD5274BCP +Potentiometer_Digital:AD5274BRM +Potentiometer_Digital:AD5280 +Potentiometer_Digital:AD5282 +Potentiometer_Digital:AD5290 +Potentiometer_Digital:AD5293 +Potentiometer_Digital:DS1267_DIP +Potentiometer_Digital:DS1267_SOIC +Potentiometer_Digital:DS1267_TSSOP +Potentiometer_Digital:DS1882E +Potentiometer_Digital:MAX5436 +Potentiometer_Digital:MAX5438 +Potentiometer_Digital:MCP4011-xxxxMS +Potentiometer_Digital:MCP4011-xxxxSN +Potentiometer_Digital:MCP4012-xxxxCH +Potentiometer_Digital:MCP4013-xxxxCH +Potentiometer_Digital:MCP4014-xxxxOT +Potentiometer_Digital:MCP4017-xxxxLT +Potentiometer_Digital:MCP4018-xxxxLT +Potentiometer_Digital:MCP4019-xxxxLT +Potentiometer_Digital:MCP4021-xxxxMS +Potentiometer_Digital:MCP4021-xxxxSN +Potentiometer_Digital:MCP4022-xxxxCH +Potentiometer_Digital:MCP4023-xxxxCH +Potentiometer_Digital:MCP4024-xxxxOT +Potentiometer_Digital:MCP41010 +Potentiometer_Digital:MCP41050 +Potentiometer_Digital:MCP41100 +Potentiometer_Digital:MCP4131-xxxx-P +Potentiometer_Digital:MCP4132-xxxx-P +Potentiometer_Digital:MCP4141-xxxx-P +Potentiometer_Digital:MCP4142-xxxx-P +Potentiometer_Digital:MCP4151-xxxx-P +Potentiometer_Digital:MCP4152-xxxx-P +Potentiometer_Digital:MCP4161-xxxx-P +Potentiometer_Digital:MCP4162-xxxx-P +Potentiometer_Digital:MCP42010 +Potentiometer_Digital:MCP42050 +Potentiometer_Digital:MCP42100 +Potentiometer_Digital:MCP4251-xxxx-ML +Potentiometer_Digital:MCP4251-xxxx-P +Potentiometer_Digital:MCP4251-xxxx-SL +Potentiometer_Digital:MCP4251-xxxx-ST +Potentiometer_Digital:MCP4431-xxxx-ST +Potentiometer_Digital:MCP4441-xxxx-ST +Potentiometer_Digital:MCP4451-xxxx-ST +Potentiometer_Digital:MCP4461-xxxx-ST +Potentiometer_Digital:MCP45HV31-MQ +Potentiometer_Digital:MCP45HV31-ST +Potentiometer_Digital:MCP45HV51-MQ +Potentiometer_Digital:MCP45HV51-ST +Potentiometer_Digital:TPL0401A-10-Q1 +Potentiometer_Digital:TPL0401B-10-Q1 +Potentiometer_Digital:X9118 +Potentiometer_Digital:X9250 +Potentiometer_Digital:X9258 +power:+10V +power:+12C +power:+12L +power:+12LF +power:+12P +power:+12V +power:+12VA +power:+15V +power:+1V0 +power:+1V1 +power:+1V2 +power:+1V35 +power:+1V5 +power:+1V8 +power:+24V +power:+28V +power:+2V5 +power:+2V8 +power:+3.3V +power:+3.3VA +power:+3.3VADC +power:+3.3VDAC +power:+3.3VP +power:+36V +power:+3V0 +power:+3V3 +power:+3V8 +power:+48V +power:+4V +power:+5C +power:+5F +power:+5P +power:+5V +power:+5VA +power:+5VD +power:+5VL +power:+5VP +power:+6V +power:+7.5V +power:+8V +power:+9V +power:+9VA +power:+BATT +power:+VDC +power:+VSW +power:-10V +power:-12V +power:-12VA +power:-15V +power:-24V +power:-2V5 +power:-36V +power:-3V3 +power:-48V +power:-5V +power:-5VA +power:-6V +power:-8V +power:-9V +power:-9VA +power:-BATT +power:-VDC +power:-VSW +power:AC +power:Earth +power:Earth_Clean +power:Earth_Protective +power:GND +power:GND1 +power:GND2 +power:GND3 +power:GNDA +power:GNDD +power:GNDPWR +power:GNDREF +power:GNDS +power:HT +power:LINE +power:NEUT +power:PRI_HI +power:PRI_LO +power:PRI_MID +power:PWR_FLAG +power:VAA +power:VAC +power:VBUS +power:VCC +power:VCCQ +power:VCOM +power:VD +power:VDC +power:VDD +power:VDDA +power:VDDF +power:VEE +power:VMEM +power:VPP +power:VS +power:VSS +power:VSSA +power:Vdrive +Power_Management:AAT4610BIGV-1-T1 +Power_Management:AAT4610BIGV-T1 +Power_Management:AAT4616IGV-1-T1 +Power_Management:AAT4616IGV-T1 +Power_Management:ADM1270ACPZ +Power_Management:ADM1270ARQZ +Power_Management:AP2161W +Power_Management:AP2171W +Power_Management:AP22804AW5 +Power_Management:AP22804BW5 +Power_Management:AP22814AW5 +Power_Management:AP22814BW5 +Power_Management:AP22816AKEWT +Power_Management:AP22816BKEWT +Power_Management:AP22817AKEWT +Power_Management:AP22817BKEWT +Power_Management:AP22818AKEWT +Power_Management:AP22818BKEWT +Power_Management:AP22913CN4 +Power_Management:AUIPS1041R +Power_Management:AUIPS1042G +Power_Management:AUIPS1051L +Power_Management:AUIPS1052G +Power_Management:AUIPS2031R +Power_Management:AUIPS2041L +Power_Management:AUIPS2051L +Power_Management:AUIPS2052G +Power_Management:AUIPS6011R +Power_Management:AUIPS6031R +Power_Management:AUIPS6041G +Power_Management:AUIPS6044G +Power_Management:AUIPS7081R +Power_Management:AUIPS7081S +Power_Management:AUIPS7091G +Power_Management:AUIPS7111S +Power_Management:AUIPS7121R +Power_Management:AUIPS7125R +Power_Management:AUIPS7141R +Power_Management:AUIPS7142G +Power_Management:AUIPS71451G +Power_Management:AUIPS7145R +Power_Management:AUIPS72211R +Power_Management:AUIPS7221R +Power_Management:AUIR3313S +Power_Management:AUIR3314S +Power_Management:AUIR3315S +Power_Management:AUIR3316S +Power_Management:AUIR3320S +Power_Management:AUIR33402S +Power_Management:BD2222G +Power_Management:BD2242G +Power_Management:BD2243G +Power_Management:BD48ExxG +Power_Management:BD48KxxG +Power_Management:BD48LxxG +Power_Management:BD48xxFVE +Power_Management:BD49ExxG +Power_Management:BD49KxxG +Power_Management:BD49LxxG +Power_Management:BD49xxFVE +Power_Management:BQ24230RGT +Power_Management:BTN8982TA +Power_Management:BTS40K2-1EJC +Power_Management:BTS443P +Power_Management:BTS462TATMA1 +Power_Management:BTS50010-1TAD +Power_Management:BTS50055-1TMA +Power_Management:BTS50055-1TMC +Power_Management:BTS50080-1TEA +Power_Management:BTS50080-1TEB +Power_Management:BTS50080-1TMA +Power_Management:BTS50080-1TMC +Power_Management:BTS50085-1TMA +Power_Management:BTS5012SDA +Power_Management:BTS5014SDA +Power_Management:BTS5016SDA +Power_Management:BTS5030-1EJA +Power_Management:BTS5045-1EJA +Power_Management:BTS5090-1EJA +Power_Management:BTS5200-1EJA +Power_Management:BTS6133D +Power_Management:BTS6142D +Power_Management:BTS6143D +Power_Management:BTS6163D +Power_Management:BTS6200-1EJA +Power_Management:BTS7004-1EPP +Power_Management:BTS711L1 +Power_Management:BTS712N1 +Power_Management:BTS716G +Power_Management:BTS716GB +Power_Management:BTS721L1 +Power_Management:BTS724G +Power_Management:CAP002DG +Power_Management:CAP003DG +Power_Management:CAP004DG +Power_Management:CAP005DG +Power_Management:CAP006DG +Power_Management:CAP007DG +Power_Management:CAP008DG +Power_Management:CAP009DG +Power_Management:CAP012DG +Power_Management:CAP013DG +Power_Management:CAP014DG +Power_Management:CAP015DG +Power_Management:CAP016DG +Power_Management:CAP017DG +Power_Management:CAP018DG +Power_Management:CAP019DG +Power_Management:CAP200DG +Power_Management:CAP300DG +Power_Management:DS1210 +Power_Management:EPC23102 +Power_Management:EPC23103 +Power_Management:EPC23104 +Power_Management:FPF2000 +Power_Management:FPF2001 +Power_Management:FPF2002 +Power_Management:FPF2003 +Power_Management:FPF2004 +Power_Management:FPF2005 +Power_Management:FPF2006 +Power_Management:FPF2007 +Power_Management:HF81 +Power_Management:INA3221 +Power_Management:IPS6011PBF +Power_Management:IPS6011RPBF +Power_Management:IPS6011SPBF +Power_Management:IPS6021PBF +Power_Management:IPS6021RPBF +Power_Management:IPS6021SPBF +Power_Management:IPS6031PBF +Power_Management:IPS6031RPBF +Power_Management:IPS6031SPBF +Power_Management:IPS6041GPBF +Power_Management:IPS6041PBF +Power_Management:IPS6041RPBF +Power_Management:IPS6041SPBF +Power_Management:IPS7091GPBF +Power_Management:IPS7091PBF +Power_Management:IPS7091SPBF +Power_Management:IRS25751L +Power_Management:ITS5215 +Power_Management:LM5050-1 +Power_Management:LM5050-2 +Power_Management:LM5051 +Power_Management:LM5060 +Power_Management:LM50672NPAR +Power_Management:LM5067MM-1 +Power_Management:LM5067MM-2 +Power_Management:LM5067MMX-2 +Power_Management:LM5067MWX-1 +Power_Management:LM66100DCK +Power_Management:LM74700 +Power_Management:LMG3410 +Power_Management:LMG5200 +Power_Management:LT1641-1 +Power_Management:LT1641-2 +Power_Management:LT4230xDD +Power_Management:LT4231xUF +Power_Management:LT4320xDD-1 +Power_Management:LTC4242xUHF +Power_Management:LTC4357DCB +Power_Management:LTC4357MS8 +Power_Management:LTC4359-DCB +Power_Management:LTC4359-MS8 +Power_Management:LTC4364CDE +Power_Management:LTC4364CMS +Power_Management:LTC4364CS +Power_Management:LTC4364HDE +Power_Management:LTC4364HMS +Power_Management:LTC4364HS +Power_Management:LTC4364IDE +Power_Management:LTC4364IMS +Power_Management:LTC4364IS +Power_Management:LTC4365DDB +Power_Management:LTC4365DDB-1 +Power_Management:LTC4365TS8 +Power_Management:LTC4365TS8-1 +Power_Management:LTC4365xTS8 +Power_Management:LTC4370xDE +Power_Management:LTC4370xMS +Power_Management:LTC4412xS6 +Power_Management:LTC4417CGN +Power_Management:LTC4417CUF +Power_Management:LTC4417HGN +Power_Management:LTC4417HUF +Power_Management:LTC4417IGN +Power_Management:LTC4417IUF +Power_Management:MAX14919xUP +Power_Management:MAX8586 +Power_Management:MAX9611 +Power_Management:MAX9612 +Power_Management:MIC2007YM6 +Power_Management:MIC2008YM6 +Power_Management:MIC2017YM6 +Power_Management:MIC2018YM6 +Power_Management:MIC2025-1YM +Power_Management:MIC2025-1YMM +Power_Management:MIC2025-2YM +Power_Management:MIC2025-2YMM +Power_Management:MIC2026-1BN +Power_Management:MIC2026-1xM +Power_Management:MIC2026-2BN +Power_Management:MIC2026-2xM +Power_Management:MIC2090-1YM5 +Power_Management:MIC2090-2YM5 +Power_Management:MIC2091-1YM5 +Power_Management:MIC2091-2YM5 +Power_Management:MIC2544-2YM +Power_Management:MIC2587-1 +Power_Management:MIC2587R-1 +Power_Management:NIS5420MTxTXG +Power_Management:NPC45560-H +Power_Management:NPC45560-L +Power_Management:PD70224 +Power_Management:RT9701 +Power_Management:RT9742AGJ5F +Power_Management:RT9742ANGJ5F +Power_Management:RT9742BGJ5F +Power_Management:RT9742BNGJ5F +Power_Management:SN6505ADBV +Power_Management:SN6505BDBV +Power_Management:SN6507DGQ +Power_Management:STM6600 +Power_Management:STM6601 +Power_Management:SiP32431DR3 +Power_Management:SiP32432DR3 +Power_Management:TEA1708T +Power_Management:TLE8102SG +Power_Management:TLE8104E +Power_Management:TPS2041B +Power_Management:TPS2042D +Power_Management:TPS2044D +Power_Management:TPS2051CDBV +Power_Management:TPS2054D +Power_Management:TPS2065CDBV +Power_Management:TPS2065CDBVx-2 +Power_Management:TPS2069CDBV +Power_Management:TPS2116DRL +Power_Management:TPS22810DRV +Power_Management:TPS22917DBV +Power_Management:TPS22929D +Power_Management:TPS22993 +Power_Management:TPS2412D +Power_Management:TPS2412PW +Power_Management:TPS2419D +Power_Management:TPS2419PW +Power_Management:TPS2592xx +Power_Management:TPS26630RGE +Power_Management:TPS26631PWP +Power_Management:TPS26631RGE +Power_Management:TPS26632RGE +Power_Management:TPS26633PWP +Power_Management:TPS26633RGE +Power_Management:TPS26635RGE +Power_Management:TPS26636PWP +Power_Management:TSM102 +Power_Management:TSM102A +Power_Management:TSM103W +Power_Management:TSM103WA +Power_Management:UCC39002D +Power_Protection:CDNBS08-SLVU2.8-4 +Power_Protection:CDSOT236-0504C +Power_Protection:CM1213A-01SO +Power_Protection:CM1624 +Power_Protection:D3V3X8U9LP3810 +Power_Protection:D3V3XA4B10LP +Power_Protection:DT1240A-08LP3810 +Power_Protection:ECMF02-2AMX6 +Power_Protection:ECMF04-4HSWM10 +Power_Protection:EMI2121MTTAG +Power_Protection:EMI8132 +Power_Protection:ESD224DQA +Power_Protection:ESDA14V2SC5 +Power_Protection:ESDA5V3L +Power_Protection:ESDA5V3SC5 +Power_Protection:ESDA6V1-5SC6 +Power_Protection:ESDA6V1BC6 +Power_Protection:ESDA6V1SC5 +Power_Protection:ESDLC5V0PB8 +Power_Protection:IP3319CX6 +Power_Protection:IP4234CZ6 +Power_Protection:IP4251CZ8-4-TTL +Power_Protection:IP4252CZ12 +Power_Protection:IP4252CZ16 +Power_Protection:IP4252CZ8 +Power_Protection:IP4252CZ8-4-TTL +Power_Protection:IP4253CZ8-4-TTL +Power_Protection:IP4254CZ8-4-TTL +Power_Protection:NCP349MN +Power_Protection:NCP349MNAE +Power_Protection:NCP349MNAM +Power_Protection:NCP349MNBG +Power_Protection:NCP349MNBK +Power_Protection:NCP361MU +Power_Protection:NCP361SN +Power_Protection:NUF4401MN +Power_Protection:NUP2105L +Power_Protection:NUP2202 +Power_Protection:NUP4202 +Power_Protection:PCMF3USB3S +Power_Protection:PESD3V3L4UF +Power_Protection:PESD3V3L4UG +Power_Protection:PESD3V3L4UW +Power_Protection:PESD3V3L5UF +Power_Protection:PESD3V3L5UV +Power_Protection:PESD3V3L5UY +Power_Protection:PESD5V0L4UF +Power_Protection:PESD5V0L4UG +Power_Protection:PESD5V0L4UW +Power_Protection:PESD5V0L5UF +Power_Protection:PESD5V0L5UV +Power_Protection:PESD5V0L5UY +Power_Protection:PRTR5V0U2X +Power_Protection:RCLAMP0502B +Power_Protection:RCLAMP0502BA +Power_Protection:RCLAMP0582B +Power_Protection:RCLAMP3328P +Power_Protection:SN65220 +Power_Protection:SN65240 +Power_Protection:SN75240 +Power_Protection:SP0502BAHT +Power_Protection:SP0502BAJT +Power_Protection:SP0503BAHT +Power_Protection:SP0504BAHT +Power_Protection:SP0504BAJT +Power_Protection:SP0505BAHT +Power_Protection:SP0505BAJT +Power_Protection:SP7538P +Power_Protection:SRV05-4 +Power_Protection:SZNUP2105L +Power_Protection:TBU-CA-025-050-WH +Power_Protection:TBU-CA-025-100-WH +Power_Protection:TBU-CA-025-200-WH +Power_Protection:TBU-CA-025-300-WH +Power_Protection:TBU-CA-025-500-WH +Power_Protection:TBU-CA-040-050-WH +Power_Protection:TBU-CA-040-100-WH +Power_Protection:TBU-CA-040-200-WH +Power_Protection:TBU-CA-040-300-WH +Power_Protection:TBU-CA-040-500-WH +Power_Protection:TBU-CA-050-050-WH +Power_Protection:TBU-CA-050-100-WH +Power_Protection:TBU-CA-050-200-WH +Power_Protection:TBU-CA-050-300-WH +Power_Protection:TBU-CA-050-500-WH +Power_Protection:TBU-CA-065-050-WH +Power_Protection:TBU-CA-065-100-WH +Power_Protection:TBU-CA-065-200-WH +Power_Protection:TBU-CA-065-300-WH +Power_Protection:TBU-CA-065-500-WH +Power_Protection:TBU-CA-085-050-WH +Power_Protection:TBU-CA-085-100-WH +Power_Protection:TBU-CA-085-200-WH +Power_Protection:TBU-CA-085-300-WH +Power_Protection:TBU-CA-085-500-WH +Power_Protection:TPD1E05U06DPY +Power_Protection:TPD1E05U06DYA +Power_Protection:TPD2E2U06DCK +Power_Protection:TPD2E2U06DRL +Power_Protection:TPD2EUSB30 +Power_Protection:TPD2EUSB30A +Power_Protection:TPD2S017 +Power_Protection:TPD3E001DRLR +Power_Protection:TPD3F303DPV +Power_Protection:TPD3S014 +Power_Protection:TPD3S044 +Power_Protection:TPD4E02B04DQA +Power_Protection:TPD4E05U06DQA +Power_Protection:TPD4EUSB30 +Power_Protection:TPD4S014 +Power_Protection:TPD4S1394 +Power_Protection:TPD6E05U06RVZ +Power_Protection:TPD6F003 +Power_Protection:TPD6S300A +Power_Protection:TPD8F003 +Power_Protection:TVS0500DRV +Power_Protection:TVS1400DRV +Power_Protection:TVS1800DRV +Power_Protection:TVS2200DRV +Power_Protection:TVS2700DRV +Power_Protection:TVS3300DRV +Power_Protection:USB6B1 +Power_Protection:USBLC6-2P6 +Power_Protection:USBLC6-2SC6 +Power_Protection:USBLC6-4SC6 +Power_Protection:WE-TVS-82400102 +Power_Protection:WE-TVS-824014881 +Power_Protection:WE-TVS-824015043 +Power_Protection:ZEN056V075A48LS +Power_Protection:ZEN056V115A24LS +Power_Protection:ZEN056V130A24LS +Power_Protection:ZEN056V230A16LS +Power_Protection:ZEN059V130A24LS +Power_Protection:ZEN065V130A24LS +Power_Protection:ZEN065V230A16LS +Power_Protection:ZEN098V130A24LS +Power_Protection:ZEN098V230A16LS +Power_Protection:ZEN132V075A48LS +Power_Protection:ZEN132V130A24LS +Power_Protection:ZEN132V230A16LS +Power_Protection:ZEN164V130A24LS +Power_Supervisor:CAT811JTBI-GT3 +Power_Supervisor:CAT811LTBI-GT3 +Power_Supervisor:CAT811MTBI-GT3 +Power_Supervisor:CAT811RTBI-GT3 +Power_Supervisor:CAT811STBI-GT3 +Power_Supervisor:CAT811TTBI-GT3 +Power_Supervisor:CAT811ZTBI-GT3 +Power_Supervisor:DIO705 +Power_Supervisor:DIO706 +Power_Supervisor:DIO706J +Power_Supervisor:DIO706R +Power_Supervisor:DIO706S +Power_Supervisor:DIO706T +Power_Supervisor:LM3880 +Power_Supervisor:LM809 +Power_Supervisor:LM810 +Power_Supervisor:MAX16050xTI +Power_Supervisor:MAX16051xTI +Power_Supervisor:MAX6355 +Power_Supervisor:MAX6369 +Power_Supervisor:MAX6370 +Power_Supervisor:MAX6371 +Power_Supervisor:MAX6372 +Power_Supervisor:MAX6373 +Power_Supervisor:MAX6374 +Power_Supervisor:MAX690ACSA +Power_Supervisor:MAX690xPA +Power_Supervisor:MAX691xPE +Power_Supervisor:MAX691xWE +Power_Supervisor:MAX692ACSA +Power_Supervisor:MAX692xPA +Power_Supervisor:MAX694xPA +Power_Supervisor:MAX802LCSA +Power_Supervisor:MAX805LCSA +Power_Supervisor:MAX811LEUS-T +Power_Supervisor:MAX811MEUS-T +Power_Supervisor:MAX811REUS-T +Power_Supervisor:MAX811SEUS-T +Power_Supervisor:MAX811TEUS-T +Power_Supervisor:MC34064D +Power_Supervisor:MC34064DM +Power_Supervisor:MC34064P +Power_Supervisor:MC34064SN +Power_Supervisor:MCP100-270D +Power_Supervisor:MCP100-300D +Power_Supervisor:MCP100-315D +Power_Supervisor:MCP100-450D +Power_Supervisor:MCP100-460D +Power_Supervisor:MCP100-475D +Power_Supervisor:MCP100-485D +Power_Supervisor:MCP101-270D +Power_Supervisor:MCP101-300D +Power_Supervisor:MCP101-315D +Power_Supervisor:MCP101-450D +Power_Supervisor:MCP101-460D +Power_Supervisor:MCP101-475D +Power_Supervisor:MCP101-485D +Power_Supervisor:MCP120-xxxDxTO +Power_Supervisor:MCP120-xxxGxTO +Power_Supervisor:MCP120-xxxHxTO +Power_Supervisor:MCP120-xxxxSN +Power_Supervisor:MCP120-xxxxTT +Power_Supervisor:MCP130-xxxDxTO +Power_Supervisor:MCP130-xxxFxTO +Power_Supervisor:MCP130-xxxHxTO +Power_Supervisor:MCP130-xxxxSN +Power_Supervisor:MCP130-xxxxTT +Power_Supervisor:MIC811JUY +Power_Supervisor:MIC811LUY +Power_Supervisor:MIC811MUY +Power_Supervisor:MIC811RUY +Power_Supervisor:MIC811SUY +Power_Supervisor:MIC811TUY +Power_Supervisor:TCM809 +Power_Supervisor:TCM810 +Power_Supervisor:TL7702A +Power_Supervisor:TL7702B +Power_Supervisor:TL7705A +Power_Supervisor:TL7705AxPS +Power_Supervisor:TL7705B +Power_Supervisor:TL7709A +Power_Supervisor:TL7712A +Power_Supervisor:TL7715A +Power_Supervisor:TL7733B +Power_Supervisor:TLV810EA29DBZ +Power_Supervisor:TPS3430WDRC +Power_Supervisor:TPS3702 +Power_Supervisor:TPS3808DBV +Power_Supervisor:TPS3831 +Power_Supervisor:TPS3839DBZ +Power_Supervisor:TPS3839DQN +Reference_Current:LM134H +Reference_Current:LM234Z-3 +Reference_Current:LM234Z-6 +Reference_Current:LM334M +Reference_Current:LM334SM +Reference_Current:LM334Z +Reference_Current:LM334Z-LFT1 +Reference_Current:LT3092xDD +Reference_Current:LT3092xST +Reference_Current:LT3092xTS8 +Reference_Current:PSSI2021SAY +Reference_Current:REF200AU +Reference_Voltage:AD586 +Reference_Voltage:ADR1399KEZ +Reference_Voltage:ADR1399KHZ +Reference_Voltage:ADR420ARMZ +Reference_Voltage:ADR421ARMZ +Reference_Voltage:ADR423ARMZ +Reference_Voltage:ADR425ARMZ +Reference_Voltage:ADR440ARMZ +Reference_Voltage:ADR440xRZ +Reference_Voltage:ADR441ARMZ +Reference_Voltage:ADR441xRZ +Reference_Voltage:ADR443ARMZ +Reference_Voltage:ADR443xRZ +Reference_Voltage:ADR444ARMZ +Reference_Voltage:ADR444xRZ +Reference_Voltage:ADR445ARMZ +Reference_Voltage:ADR445xRZ +Reference_Voltage:ADR4520 +Reference_Voltage:ADR4525 +Reference_Voltage:ADR4530 +Reference_Voltage:ADR4533 +Reference_Voltage:ADR4540 +Reference_Voltage:ADR4550 +Reference_Voltage:CJ432 +Reference_Voltage:ISL21070CIH320Z-TK +Reference_Voltage:ISL21070CIH325Z-TK +Reference_Voltage:ISL21070DIH306Z-TK +Reference_Voltage:LM285D-1.2 +Reference_Voltage:LM285D-2.5 +Reference_Voltage:LM285M-ADJ +Reference_Voltage:LM285S-1.2 +Reference_Voltage:LM285S-2.5 +Reference_Voltage:LM285Z-1.2 +Reference_Voltage:LM285Z-2.5 +Reference_Voltage:LM285Z-ADJ +Reference_Voltage:LM329xZ +Reference_Voltage:LM385BZ-1.2 +Reference_Voltage:LM385BZ-2.5 +Reference_Voltage:LM385D-1.2 +Reference_Voltage:LM385D-2.5 +Reference_Voltage:LM385M-ADJ +Reference_Voltage:LM385S-1.2 +Reference_Voltage:LM385S-2.5 +Reference_Voltage:LM385Z-1.2 +Reference_Voltage:LM385Z-2.5 +Reference_Voltage:LM385Z-ADJ +Reference_Voltage:LM399 +Reference_Voltage:LM4030-2.5 +Reference_Voltage:LM4030-4.096 +Reference_Voltage:LM4040DBZ-10 +Reference_Voltage:LM4040DBZ-2.0 +Reference_Voltage:LM4040DBZ-2.5 +Reference_Voltage:LM4040DBZ-3 +Reference_Voltage:LM4040DBZ-4.1 +Reference_Voltage:LM4040DBZ-5 +Reference_Voltage:LM4040DBZ-8.2 +Reference_Voltage:LM4040DCK-10 +Reference_Voltage:LM4040DCK-2.0 +Reference_Voltage:LM4040DCK-2.5 +Reference_Voltage:LM4040DCK-3 +Reference_Voltage:LM4040DCK-4.1 +Reference_Voltage:LM4040DCK-5 +Reference_Voltage:LM4040DCK-8.2 +Reference_Voltage:LM4040LP-10 +Reference_Voltage:LM4040LP-2.0 +Reference_Voltage:LM4040LP-2.5 +Reference_Voltage:LM4040LP-3 +Reference_Voltage:LM4040LP-4.1 +Reference_Voltage:LM4040LP-5 +Reference_Voltage:LM4040LP-8.2 +Reference_Voltage:LM4041LP-ADJ +Reference_Voltage:LM4125AIM5-2.5 +Reference_Voltage:LM4125IM5-2.0 +Reference_Voltage:LM4125IM5-2.5 +Reference_Voltage:LM4128 +Reference_Voltage:LM4132xMF-1.8 +Reference_Voltage:LM4132xMF-2.0 +Reference_Voltage:LM4132xMF-2.5 +Reference_Voltage:LM4132xMF-3.0 +Reference_Voltage:LM4132xMF-3.3 +Reference_Voltage:LM4132xMF-4.1 +Reference_Voltage:LT1009CMS8 +Reference_Voltage:LT1009xS8 +Reference_Voltage:LT1009xZ +Reference_Voltage:LT1019xN8 +Reference_Voltage:LT1461AxS8-2.5 +Reference_Voltage:LT1461AxS8-3 +Reference_Voltage:LT1461AxS8-3.3 +Reference_Voltage:LT1461AxS8-4 +Reference_Voltage:LT1461AxS8-5 +Reference_Voltage:LT1461BxS8-2.5 +Reference_Voltage:LT1461BxS8-3 +Reference_Voltage:LT1461BxS8-3.3 +Reference_Voltage:LT1461BxS8-4 +Reference_Voltage:LT1461BxS8-5 +Reference_Voltage:LT1461CxS8-2.5 +Reference_Voltage:LT1461CxS8-3 +Reference_Voltage:LT1461CxS8-3.3 +Reference_Voltage:LT1461CxS8-4 +Reference_Voltage:LT1461CxS8-5 +Reference_Voltage:LT1461DxS8-2.5 +Reference_Voltage:LT1461DxS8-3 +Reference_Voltage:LT1461DxS8-3.3 +Reference_Voltage:LT1461DxS8-4 +Reference_Voltage:LT1461DxS8-5 +Reference_Voltage:LT1634BCMS8-1.25 +Reference_Voltage:LT1634BCMS8-2.5 +Reference_Voltage:LT1634CCZ-1.25 +Reference_Voltage:LT1634CCZ-2.5 +Reference_Voltage:LT1634CCZ-4.096 +Reference_Voltage:LT1634CCZ-5 +Reference_Voltage:LT1634xxS8-1.25 +Reference_Voltage:LT1634xxS8-2.5 +Reference_Voltage:LT1634xxS8-4.096 +Reference_Voltage:LT1634xxS8-5 +Reference_Voltage:LT1790-1.25 +Reference_Voltage:LT1790-2.048 +Reference_Voltage:LT1790-2.5 +Reference_Voltage:LT1790-3 +Reference_Voltage:LT1790-3.3 +Reference_Voltage:LT1790-4.096 +Reference_Voltage:LT1790-5 +Reference_Voltage:LT6657AHMS8-2.5 +Reference_Voltage:LT6657AHMS8-3 +Reference_Voltage:LT6657AHMS8-4.096 +Reference_Voltage:LT6657AHMS8-5 +Reference_Voltage:LT6657BHMS8-2.5 +Reference_Voltage:LT6657BHMS8-3 +Reference_Voltage:LT6657BHMS8-4.096 +Reference_Voltage:LT6657BHMS8-5 +Reference_Voltage:MAX6001 +Reference_Voltage:MAX6002 +Reference_Voltage:MAX6003 +Reference_Voltage:MAX6004 +Reference_Voltage:MAX6005 +Reference_Voltage:MAX6035xSA25 +Reference_Voltage:MAX6035xxUR25 +Reference_Voltage:MAX6035xxUR30 +Reference_Voltage:MAX6035xxUR50 +Reference_Voltage:MAX6070AAUT12+T +Reference_Voltage:MAX6070AAUT18+T +Reference_Voltage:MAX6070AAUT18V+T +Reference_Voltage:MAX6070AAUT21+T +Reference_Voltage:MAX6070AAUT25+T +Reference_Voltage:MAX6070AAUT30+T +Reference_Voltage:MAX6070AAUT33+T +Reference_Voltage:MAX6070AAUT33V+T +Reference_Voltage:MAX6070AAUT41+T +Reference_Voltage:MAX6070AAUT50+T +Reference_Voltage:MAX6070AAUT50V+T +Reference_Voltage:MAX6070BAUT12+T +Reference_Voltage:MAX6070BAUT12V+T +Reference_Voltage:MAX6070BAUT18+T +Reference_Voltage:MAX6070BAUT21+T +Reference_Voltage:MAX6070BAUT21V+T +Reference_Voltage:MAX6070BAUT25+T +Reference_Voltage:MAX6070BAUT25V+T +Reference_Voltage:MAX6070BAUT30+T +Reference_Voltage:MAX6070BAUT33+T +Reference_Voltage:MAX6070BAUT33V+T +Reference_Voltage:MAX6070BAUT41+T +Reference_Voltage:MAX6070BAUT41V+T +Reference_Voltage:MAX6070BAUT50+T +Reference_Voltage:MAX6070BAUT50V+T +Reference_Voltage:MAX6070DAUT12V+T +Reference_Voltage:MAX6070DAUT25V+T +Reference_Voltage:MAX6070DAUT30V+T +Reference_Voltage:MAX6070DAUT41V+T +Reference_Voltage:MAX6071AAUT12+T +Reference_Voltage:MAX6071AAUT18+T +Reference_Voltage:MAX6071AAUT21+T +Reference_Voltage:MAX6071AAUT25+T +Reference_Voltage:MAX6071AAUT30+T +Reference_Voltage:MAX6071AAUT30V+T +Reference_Voltage:MAX6071AAUT33+T +Reference_Voltage:MAX6071AAUT41+T +Reference_Voltage:MAX6071AAUT50+T +Reference_Voltage:MAX6071BAUT12+T +Reference_Voltage:MAX6071BAUT18+T +Reference_Voltage:MAX6071BAUT21+T +Reference_Voltage:MAX6071BAUT25+T +Reference_Voltage:MAX6071BAUT25V+T +Reference_Voltage:MAX6071BAUT30+T +Reference_Voltage:MAX6071BAUT33+T +Reference_Voltage:MAX6071BAUT41+T +Reference_Voltage:MAX6071BAUT50+T +Reference_Voltage:MAX6100 +Reference_Voltage:MAX6101 +Reference_Voltage:MAX6102 +Reference_Voltage:MAX6103 +Reference_Voltage:MAX6104 +Reference_Voltage:MAX6105 +Reference_Voltage:MAX6106 +Reference_Voltage:MAX6107 +Reference_Voltage:MAX6225 +Reference_Voltage:MAX6241 +Reference_Voltage:MAX6250 +Reference_Voltage:MAX6325 +Reference_Voltage:MAX6341 +Reference_Voltage:MAX6350 +Reference_Voltage:MAX872 +Reference_Voltage:MAX874 +Reference_Voltage:MCP1501-10xCH +Reference_Voltage:MCP1501-10xRW +Reference_Voltage:MCP1501-10xSN +Reference_Voltage:MCP1501-12xCH +Reference_Voltage:MCP1501-12xRW +Reference_Voltage:MCP1501-12xSN +Reference_Voltage:MCP1501-18xCH +Reference_Voltage:MCP1501-18xRW +Reference_Voltage:MCP1501-18xSN +Reference_Voltage:MCP1501-20xCH +Reference_Voltage:MCP1501-20xRW +Reference_Voltage:MCP1501-20xSN +Reference_Voltage:MCP1501-25xCH +Reference_Voltage:MCP1501-25xRW +Reference_Voltage:MCP1501-25xSN +Reference_Voltage:MCP1501-30xCH +Reference_Voltage:MCP1501-30xRW +Reference_Voltage:MCP1501-30xSN +Reference_Voltage:MCP1501-33xCH +Reference_Voltage:MCP1501-33xRW +Reference_Voltage:MCP1501-33xSN +Reference_Voltage:MCP1501-40xCH +Reference_Voltage:MCP1501-40xRW +Reference_Voltage:MCP1501-40xSN +Reference_Voltage:MCP1525-TO +Reference_Voltage:MCP1525-TT +Reference_Voltage:MCP1541-TO +Reference_Voltage:MCP1541-TT +Reference_Voltage:REF01CP +Reference_Voltage:REF01CS +Reference_Voltage:REF01EZ +Reference_Voltage:REF01HP +Reference_Voltage:REF01HZ +Reference_Voltage:REF02AP +Reference_Voltage:REF02AU +Reference_Voltage:REF02AZ +Reference_Voltage:REF02BP +Reference_Voltage:REF02BU +Reference_Voltage:REF02CP +Reference_Voltage:REF02CS +Reference_Voltage:REF02EZ +Reference_Voltage:REF02HP +Reference_Voltage:REF02HS +Reference_Voltage:REF02HZ +Reference_Voltage:REF02Z +Reference_Voltage:REF03GP +Reference_Voltage:REF03GS +Reference_Voltage:REF102AP +Reference_Voltage:REF102AU +Reference_Voltage:REF102BP +Reference_Voltage:REF102BU +Reference_Voltage:REF102CP +Reference_Voltage:REF102CU +Reference_Voltage:REF191 +Reference_Voltage:REF192 +Reference_Voltage:REF193 +Reference_Voltage:REF194 +Reference_Voltage:REF195 +Reference_Voltage:REF196 +Reference_Voltage:REF198 +Reference_Voltage:REF2025 +Reference_Voltage:REF2030 +Reference_Voltage:REF2033 +Reference_Voltage:REF2041 +Reference_Voltage:REF3012 +Reference_Voltage:REF3020 +Reference_Voltage:REF3025 +Reference_Voltage:REF3030 +Reference_Voltage:REF3033 +Reference_Voltage:REF3040 +Reference_Voltage:REF3212AMDBVREP +Reference_Voltage:REF3220AMDBVREP +Reference_Voltage:REF3225AMDBVREP +Reference_Voltage:REF3230AMDBVREP +Reference_Voltage:REF3233AMDBVREP +Reference_Voltage:REF3240AMDBVREP +Reference_Voltage:REF35102QDBVR +Reference_Voltage:REF35120QDBVR +Reference_Voltage:REF35125QDBVR +Reference_Voltage:REF35160QDBVR +Reference_Voltage:REF35170QDBVR +Reference_Voltage:REF35180QDBVR +Reference_Voltage:REF35205QDBVR +Reference_Voltage:REF35250QDBVR +Reference_Voltage:REF35300QDBVR +Reference_Voltage:REF35330QDBVR +Reference_Voltage:REF35360QDBVR +Reference_Voltage:REF35409QDBVR +Reference_Voltage:REF35500QDBVR +Reference_Voltage:REF5010AD +Reference_Voltage:REF5010ADGK +Reference_Voltage:REF5010ID +Reference_Voltage:REF5010IDGK +Reference_Voltage:REF5020AD +Reference_Voltage:REF5020ADGK +Reference_Voltage:REF5020ID +Reference_Voltage:REF5020IDGK +Reference_Voltage:REF5025AD +Reference_Voltage:REF5025ADGK +Reference_Voltage:REF5025ID +Reference_Voltage:REF5025IDGK +Reference_Voltage:REF5030AD +Reference_Voltage:REF5030ADGK +Reference_Voltage:REF5030ID +Reference_Voltage:REF5030IDGK +Reference_Voltage:REF5040AD +Reference_Voltage:REF5040ADGK +Reference_Voltage:REF5040ID +Reference_Voltage:REF5040IDGK +Reference_Voltage:REF5045AD +Reference_Voltage:REF5045ADGK +Reference_Voltage:REF5045ID +Reference_Voltage:REF5045IDGK +Reference_Voltage:REF5050AD +Reference_Voltage:REF5050ADGK +Reference_Voltage:REF5050ID +Reference_Voltage:REF5050IDGK +Reference_Voltage:REF6025xDGK +Reference_Voltage:REF6030xDGK +Reference_Voltage:REF6033xDGK +Reference_Voltage:REF6041xDGK +Reference_Voltage:REF6045xDGK +Reference_Voltage:REF6050xDGK +Reference_Voltage:TL431D +Reference_Voltage:TL431DBV +Reference_Voltage:TL431DBZ +Reference_Voltage:TL431DCK +Reference_Voltage:TL431KTP +Reference_Voltage:TL431LP +Reference_Voltage:TL431P +Reference_Voltage:TL431PK +Reference_Voltage:TL431PS +Reference_Voltage:TL431PW +Reference_Voltage:TL432DBV +Reference_Voltage:TL432DBZ +Reference_Voltage:TL432PK +Reference_Voltage:TLE2425xD +Reference_Voltage:TLE2425xLP +Reference_Voltage:TLE2426xD +Reference_Voltage:TLE2426xLP +Reference_Voltage:TLE2426xP +Regulator_Controller:ICE1PCS01 +Regulator_Controller:ICE1PCS02 +Regulator_Controller:ICE2PCS01 +Regulator_Controller:ICE2PCS02 +Regulator_Controller:ICE2PCS03 +Regulator_Controller:ICE2PCS04 +Regulator_Controller:ICE2PCS05 +Regulator_Controller:ICE2PCS06 +Regulator_Controller:ICE3PCS01 +Regulator_Controller:ICE3PCS02 +Regulator_Controller:ICE3PCS03 +Regulator_Controller:IR1153S +Regulator_Controller:IR1155S +Regulator_Controller:IR1161L +Regulator_Controller:IR11662S +Regulator_Controller:IR11672AS +Regulator_Controller:IR1167S +Regulator_Controller:IR11682S +Regulator_Controller:IR11688S +Regulator_Controller:IR1168S +Regulator_Controller:IR1169S +Regulator_Controller:IRS2505L +Regulator_Controller:ISL6551 +Regulator_Controller:L4981A +Regulator_Controller:L4981B +Regulator_Controller:L4984D +Regulator_Controller:L6561 +Regulator_Controller:L6562 +Regulator_Controller:L6562A +Regulator_Controller:L6562AT +Regulator_Controller:L6563 +Regulator_Controller:L6563A +Regulator_Controller:L6563H +Regulator_Controller:L6563S +Regulator_Controller:L6564 +Regulator_Controller:L6564H +Regulator_Controller:L6564T +Regulator_Controller:L6598 +Regulator_Controller:L6599 +Regulator_Controller:L6727 +Regulator_Controller:LM25119 +Regulator_Controller:LM3478MA +Regulator_Controller:LM3478MM +Regulator_Controller:LM3478QMM +Regulator_Controller:LM5023 +Regulator_Controller:LT1248 +Regulator_Controller:LT1249 +Regulator_Controller:LT1509 +Regulator_Controller:LT4295xUFD +Regulator_Controller:LTC1624CS8 +Regulator_Controller:LTC3805xMSE +Regulator_Controller:LTC3890 +Regulator_Controller:LTC3890-1 +Regulator_Controller:LTC3892 +Regulator_Controller:LTC3892-1 +Regulator_Controller:LTC3892-2 +Regulator_Controller:LTC7810 +Regulator_Controller:NCP1200D100 +Regulator_Controller:NCP1200D40 +Regulator_Controller:NCP1200D60 +Regulator_Controller:NCP1200P100 +Regulator_Controller:NCP1200P40 +Regulator_Controller:NCP1200P60 +Regulator_Controller:NCP1203D100 +Regulator_Controller:NCP1203D40 +Regulator_Controller:NCP1203D60 +Regulator_Controller:NCP1203P100 +Regulator_Controller:NCP1203P40 +Regulator_Controller:NCP1203P60 +Regulator_Controller:NCP1207A +Regulator_Controller:NCP1207B +Regulator_Controller:NCP1217AD100 +Regulator_Controller:NCP1217AD133 +Regulator_Controller:NCP1217AD65 +Regulator_Controller:NCP1217AP100 +Regulator_Controller:NCP1217AP133 +Regulator_Controller:NCP1217AP65 +Regulator_Controller:NCP1217D100 +Regulator_Controller:NCP1217D133 +Regulator_Controller:NCP1217D65 +Regulator_Controller:NCP1217P100 +Regulator_Controller:NCP1217P133 +Regulator_Controller:NCP1217P65 +Regulator_Controller:NCP1280 +Regulator_Controller:NCP1380A +Regulator_Controller:NCP1380B +Regulator_Controller:NCP1380C +Regulator_Controller:NCP1380D +Regulator_Controller:NCP1653 +Regulator_Controller:NCP1653A +Regulator_Controller:NCP4308AD +Regulator_Controller:NCP4308AMT +Regulator_Controller:NCP4308DD +Regulator_Controller:NCP4308DMN +Regulator_Controller:NCP4308DMT +Regulator_Controller:NCP4308QD +Regulator_Controller:SG3525 +Regulator_Controller:SG3527 +Regulator_Controller:TDA4862 +Regulator_Controller:TDA4863 +Regulator_Controller:TDA4863-2 +Regulator_Controller:TL494 +Regulator_Controller:TPS2375-1 +Regulator_Controller:UC3525 +Regulator_Controller:UC3527 +Regulator_Controller:UC3842_DIP8 +Regulator_Controller:UC3842_SOIC14 +Regulator_Controller:UC3842_SOIC16 +Regulator_Controller:UC3842_SOIC8 +Regulator_Controller:UC3843_DIP8 +Regulator_Controller:UC3843_SOIC14 +Regulator_Controller:UC3843_SOIC8 +Regulator_Controller:UC3844_DIP8 +Regulator_Controller:UC3844_SOIC14 +Regulator_Controller:UC3844_SOIC8 +Regulator_Controller:UC3845_DIP8 +Regulator_Controller:UC3845_SOIC14 +Regulator_Controller:UC3845_SOIC8 +Regulator_Controller:UC3854 +Regulator_Controller:UCC1895J +Regulator_Controller:UCC24610D +Regulator_Controller:UCC24610DRB +Regulator_Controller:UCC24612-1DBV +Regulator_Controller:UCC24612-2DBV +Regulator_Controller:UCC24630DBV +Regulator_Controller:UCC24636DBV +Regulator_Controller:UCC25600 +Regulator_Controller:UCC256301 +Regulator_Controller:UCC25800 +Regulator_Controller:UCC2891 +Regulator_Controller:UCC2892 +Regulator_Controller:UCC2893 +Regulator_Controller:UCC2894 +Regulator_Controller:UCC2895DW +Regulator_Controller:UCC2895N +Regulator_Controller:UCC2895PW +Regulator_Controller:UCC2897 +Regulator_Controller:UCC3800 +Regulator_Controller:UCC3801 +Regulator_Controller:UCC3802 +Regulator_Controller:UCC3803 +Regulator_Controller:UCC3804 +Regulator_Controller:UCC3805 +Regulator_Controller:UCC3808D +Regulator_Controller:UCC3808N +Regulator_Controller:UCC3813-0 +Regulator_Controller:UCC3813-1 +Regulator_Controller:UCC3813-2 +Regulator_Controller:UCC3813-3 +Regulator_Controller:UCC3813-4 +Regulator_Controller:UCC3813-5 +Regulator_Controller:UCC3895DW +Regulator_Controller:UCC3895N +Regulator_Controller:UCC3895PW +Regulator_Current:HV100K5-G +Regulator_Current:HV101K5-G +Regulator_Linear:ADP3336ARMZ +Regulator_Linear:ADP7118ACPZN +Regulator_Linear:ADP7142ARDZ +Regulator_Linear:ADP7142ARDZ-1.8 +Regulator_Linear:ADP7142ARDZ-2.5 +Regulator_Linear:ADP7142ARDZ-3.3 +Regulator_Linear:ADP7142ARDZ-5.0 +Regulator_Linear:ADP7142AUJZ +Regulator_Linear:ADP7142AUJZ-1.8 +Regulator_Linear:ADP7142AUJZ-2.5 +Regulator_Linear:ADP7142AUJZ-3.3 +Regulator_Linear:ADP7142AUJZ-5.0 +Regulator_Linear:ADP7182AUJZ +Regulator_Linear:ADP7182AUJZ-1.8 +Regulator_Linear:ADP7182AUJZ-2.5 +Regulator_Linear:ADP7182AUJZ-3.3 +Regulator_Linear:ADP7182AUJZ-5.0 +Regulator_Linear:AMS1117 +Regulator_Linear:AMS1117-1.5 +Regulator_Linear:AMS1117-1.8 +Regulator_Linear:AMS1117-2.5 +Regulator_Linear:AMS1117-2.85 +Regulator_Linear:AMS1117-3.3 +Regulator_Linear:AMS1117-5.0 +Regulator_Linear:AMS1117CD +Regulator_Linear:AMS1117CD-1.5 +Regulator_Linear:AMS1117CD-1.8 +Regulator_Linear:AMS1117CD-2.5 +Regulator_Linear:AMS1117CD-2.85 +Regulator_Linear:AMS1117CD-3.3 +Regulator_Linear:AMS1117CD-5.0 +Regulator_Linear:AMS1117CS +Regulator_Linear:AMS1117CS-1.5 +Regulator_Linear:AMS1117CS-1.8 +Regulator_Linear:AMS1117CS-2.5 +Regulator_Linear:AMS1117CS-2.85 +Regulator_Linear:AMS1117CS-3.3 +Regulator_Linear:AMS1117CS-5.0 +Regulator_Linear:AP1117-15 +Regulator_Linear:AP1117-18 +Regulator_Linear:AP1117-25 +Regulator_Linear:AP1117-33 +Regulator_Linear:AP1117-50 +Regulator_Linear:AP1117-ADJ +Regulator_Linear:AP130-15Y +Regulator_Linear:AP130-18Y +Regulator_Linear:AP130-20Y +Regulator_Linear:AP130-25Y +Regulator_Linear:AP130-28Y +Regulator_Linear:AP130-30Y +Regulator_Linear:AP130-33Y +Regulator_Linear:AP130-35Y +Regulator_Linear:AP131-15 +Regulator_Linear:AP131-18 +Regulator_Linear:AP131-20 +Regulator_Linear:AP131-25 +Regulator_Linear:AP131-28 +Regulator_Linear:AP131-29 +Regulator_Linear:AP131-30 +Regulator_Linear:AP131-33 +Regulator_Linear:AP131-35 +Regulator_Linear:AP2112K-1.2 +Regulator_Linear:AP2112K-1.8 +Regulator_Linear:AP2112K-2.5 +Regulator_Linear:AP2112K-2.6 +Regulator_Linear:AP2112K-3.3 +Regulator_Linear:AP2127K-1.0 +Regulator_Linear:AP2127K-1.2 +Regulator_Linear:AP2127K-1.5 +Regulator_Linear:AP2127K-1.8 +Regulator_Linear:AP2127K-2.5 +Regulator_Linear:AP2127K-2.8 +Regulator_Linear:AP2127K-3.0 +Regulator_Linear:AP2127K-3.3 +Regulator_Linear:AP2127K-4.2 +Regulator_Linear:AP2127K-4.75 +Regulator_Linear:AP2127K-ADJ +Regulator_Linear:AP2127N-1.0 +Regulator_Linear:AP2127N-1.2 +Regulator_Linear:AP2127N-1.5 +Regulator_Linear:AP2127N-1.8 +Regulator_Linear:AP2127N-2.5 +Regulator_Linear:AP2127N-2.8 +Regulator_Linear:AP2127N-3.0 +Regulator_Linear:AP2127N-3.3 +Regulator_Linear:AP2127N3-1.2 +Regulator_Linear:AP2127N3-1.5 +Regulator_Linear:AP2127R-3.3 +Regulator_Linear:AP2204K-1.5 +Regulator_Linear:AP2204K-1.8 +Regulator_Linear:AP2204K-2.5 +Regulator_Linear:AP2204K-2.8 +Regulator_Linear:AP2204K-3.0 +Regulator_Linear:AP2204K-3.3 +Regulator_Linear:AP2204K-5.0 +Regulator_Linear:AP2204K-ADJ +Regulator_Linear:AP2204MP-ADJ +Regulator_Linear:AP2204R-1.5 +Regulator_Linear:AP2204R-1.8 +Regulator_Linear:AP2204R-2.5 +Regulator_Linear:AP2204R-2.8 +Regulator_Linear:AP2204R-3.0 +Regulator_Linear:AP2204R-3.3 +Regulator_Linear:AP2204R-5.0 +Regulator_Linear:AP2204RA-3.3 +Regulator_Linear:AP2204RA-5.0 +Regulator_Linear:AP2204RB-3.3 +Regulator_Linear:AP2204RB-5.0 +Regulator_Linear:AP22615AWU +Regulator_Linear:AP22615BWU +Regulator_Linear:AP7361C-10E +Regulator_Linear:AP7361C-12E +Regulator_Linear:AP7361C-15E +Regulator_Linear:AP7361C-18E +Regulator_Linear:AP7361C-25E +Regulator_Linear:AP7361C-28E +Regulator_Linear:AP7361C-33E +Regulator_Linear:AP7370-12FDC +Regulator_Linear:AP7370-15FDC +Regulator_Linear:AP7370-18FDC +Regulator_Linear:AP7370-28FDC +Regulator_Linear:AP7370-30FDC +Regulator_Linear:AP7370-33FDC +Regulator_Linear:AP7370-36FDC +Regulator_Linear:AP7370-50FDC +Regulator_Linear:AP7381-28SA-7 +Regulator_Linear:AP7381-33SA-7 +Regulator_Linear:AP7381-50SA-7 +Regulator_Linear:AP7381-70SA-7 +Regulator_Linear:AP7384-28SA +Regulator_Linear:AP7384-28V +Regulator_Linear:AP7384-28Y +Regulator_Linear:AP7384-33SA +Regulator_Linear:AP7384-33V +Regulator_Linear:AP7384-33Y +Regulator_Linear:AP7384-50SA +Regulator_Linear:AP7384-50V +Regulator_Linear:AP7384-50Y +Regulator_Linear:AP7384-70SA +Regulator_Linear:AP7384-70V +Regulator_Linear:AP7384-70Y +Regulator_Linear:APE8865N-12-HF-3 +Regulator_Linear:APE8865N-15-HF-3 +Regulator_Linear:APE8865N-16-HF-3 +Regulator_Linear:APE8865N-17-HF-3 +Regulator_Linear:APE8865N-18-HF-3 +Regulator_Linear:APE8865N-19-HF-3 +Regulator_Linear:APE8865N-20-HF-3 +Regulator_Linear:APE8865N-21-HF-3 +Regulator_Linear:APE8865N-22-HF-3 +Regulator_Linear:APE8865N-23-HF-3 +Regulator_Linear:APE8865N-24-HF-3 +Regulator_Linear:APE8865N-25-HF-3 +Regulator_Linear:APE8865N-26-HF-3 +Regulator_Linear:APE8865N-27-HF-3 +Regulator_Linear:APE8865N-28-HF-3 +Regulator_Linear:APE8865N-29-HF-3 +Regulator_Linear:APE8865N-30-HF-3 +Regulator_Linear:APE8865N-31-HF-3 +Regulator_Linear:APE8865N-32-HF-3 +Regulator_Linear:APE8865N-33-HF-3 +Regulator_Linear:APE8865NL-12-HF-3 +Regulator_Linear:APE8865NL-15-HF-3 +Regulator_Linear:APE8865NL-16-HF-3 +Regulator_Linear:APE8865NL-17-HF-3 +Regulator_Linear:APE8865NL-18-HF-3 +Regulator_Linear:APE8865NL-19-HF-3 +Regulator_Linear:APE8865NL-20-HF-3 +Regulator_Linear:APE8865NL-21-HF-3 +Regulator_Linear:APE8865NL-22-HF-3 +Regulator_Linear:APE8865NL-23-HF-3 +Regulator_Linear:APE8865NL-24-HF-3 +Regulator_Linear:APE8865NL-25-HF-3 +Regulator_Linear:APE8865NL-26-HF-3 +Regulator_Linear:APE8865NL-27-HF-3 +Regulator_Linear:APE8865NL-28-HF-3 +Regulator_Linear:APE8865NL-29-HF-3 +Regulator_Linear:APE8865NL-30-HF-3 +Regulator_Linear:APE8865NL-31-HF-3 +Regulator_Linear:APE8865NL-32-HF-3 +Regulator_Linear:APE8865NL-33-HF-3 +Regulator_Linear:APE8865NR-12-HF-3 +Regulator_Linear:APE8865NR-15-HF-3 +Regulator_Linear:APE8865NR-16-HF-3 +Regulator_Linear:APE8865NR-17-HF-3 +Regulator_Linear:APE8865NR-18-HF-3 +Regulator_Linear:APE8865NR-19-HF-3 +Regulator_Linear:APE8865NR-20-HF-3 +Regulator_Linear:APE8865NR-21-HF-3 +Regulator_Linear:APE8865NR-22-HF-3 +Regulator_Linear:APE8865NR-23-HF-3 +Regulator_Linear:APE8865NR-24-HF-3 +Regulator_Linear:APE8865NR-25-HF-3 +Regulator_Linear:APE8865NR-26-HF-3 +Regulator_Linear:APE8865NR-27-HF-3 +Regulator_Linear:APE8865NR-28-HF-3 +Regulator_Linear:APE8865NR-29-HF-3 +Regulator_Linear:APE8865NR-30-HF-3 +Regulator_Linear:APE8865NR-31-HF-3 +Regulator_Linear:APE8865NR-32-HF-3 +Regulator_Linear:APE8865NR-33-HF-3 +Regulator_Linear:APE8865U4-12-HF-3 +Regulator_Linear:APE8865U4-15-HF-3 +Regulator_Linear:APE8865U4-16-HF-3 +Regulator_Linear:APE8865U4-17-HF-3 +Regulator_Linear:APE8865U4-18-HF-3 +Regulator_Linear:APE8865U4-19-HF-3 +Regulator_Linear:APE8865U4-20-HF-3 +Regulator_Linear:APE8865U4-21-HF-3 +Regulator_Linear:APE8865U4-22-HF-3 +Regulator_Linear:APE8865U4-23-HF-3 +Regulator_Linear:APE8865U4-24-HF-3 +Regulator_Linear:APE8865U4-25-HF-3 +Regulator_Linear:APE8865U4-26-HF-3 +Regulator_Linear:APE8865U4-27-HF-3 +Regulator_Linear:APE8865U4-28-HF-3 +Regulator_Linear:APE8865U4-29-HF-3 +Regulator_Linear:APE8865U4-30-HF-3 +Regulator_Linear:APE8865U4-31-HF-3 +Regulator_Linear:APE8865U4-32-HF-3 +Regulator_Linear:APE8865U4-33-HF-3 +Regulator_Linear:APE8865U5-12-HF-3 +Regulator_Linear:APE8865U5-15-HF-3 +Regulator_Linear:APE8865U5-16-HF-3 +Regulator_Linear:APE8865U5-17-HF-3 +Regulator_Linear:APE8865U5-18-HF-3 +Regulator_Linear:APE8865U5-19-HF-3 +Regulator_Linear:APE8865U5-20-HF-3 +Regulator_Linear:APE8865U5-21-HF-3 +Regulator_Linear:APE8865U5-22-HF-3 +Regulator_Linear:APE8865U5-23-HF-3 +Regulator_Linear:APE8865U5-24-HF-3 +Regulator_Linear:APE8865U5-25-HF-3 +Regulator_Linear:APE8865U5-26-HF-3 +Regulator_Linear:APE8865U5-27-HF-3 +Regulator_Linear:APE8865U5-28-HF-3 +Regulator_Linear:APE8865U5-29-HF-3 +Regulator_Linear:APE8865U5-30-HF-3 +Regulator_Linear:APE8865U5-31-HF-3 +Regulator_Linear:APE8865U5-32-HF-3 +Regulator_Linear:APE8865U5-33-HF-3 +Regulator_Linear:APE8865Y5-12-HF-3 +Regulator_Linear:APE8865Y5-15-HF-3 +Regulator_Linear:APE8865Y5-16-HF-3 +Regulator_Linear:APE8865Y5-17-HF-3 +Regulator_Linear:APE8865Y5-18-HF-3 +Regulator_Linear:APE8865Y5-19-HF-3 +Regulator_Linear:APE8865Y5-20-HF-3 +Regulator_Linear:APE8865Y5-21-HF-3 +Regulator_Linear:APE8865Y5-22-HF-3 +Regulator_Linear:APE8865Y5-23-HF-3 +Regulator_Linear:APE8865Y5-24-HF-3 +Regulator_Linear:APE8865Y5-25-HF-3 +Regulator_Linear:APE8865Y5-26-HF-3 +Regulator_Linear:APE8865Y5-27-HF-3 +Regulator_Linear:APE8865Y5-28-HF-3 +Regulator_Linear:APE8865Y5-29-HF-3 +Regulator_Linear:APE8865Y5-30-HF-3 +Regulator_Linear:APE8865Y5-31-HF-3 +Regulator_Linear:APE8865Y5-32-HF-3 +Regulator_Linear:APE8865Y5-33-HF-3 +Regulator_Linear:AZ1084-1.2 +Regulator_Linear:AZ1084-1.5 +Regulator_Linear:AZ1084-1.8 +Regulator_Linear:AZ1084-2.5 +Regulator_Linear:AZ1084-2.85 +Regulator_Linear:AZ1084-3.3 +Regulator_Linear:AZ1084-5.0 +Regulator_Linear:AZ1117-1.2 +Regulator_Linear:AZ1117-1.5 +Regulator_Linear:AZ1117-1.8 +Regulator_Linear:AZ1117-2.5 +Regulator_Linear:AZ1117-2.85 +Regulator_Linear:AZ1117-3.3 +Regulator_Linear:AZ1117-5.0 +Regulator_Linear:AZ1117-ADJ +Regulator_Linear:AZ1117D-ADJ +Regulator_Linear:AZ1117H-ADJ +Regulator_Linear:AZ1117R-ADJ +Regulator_Linear:AZ1117S-ADJ +Regulator_Linear:AZ1117T-ADJ +Regulator_Linear:BD00FC0WEFJ +Regulator_Linear:BD00FC0WFP +Regulator_Linear:BD15GA3WEFJ +Regulator_Linear:BD15GA5WEFJ +Regulator_Linear:BD18GA3WEFJ +Regulator_Linear:BD18GA5WEFJ +Regulator_Linear:BD25GA3WEFJ +Regulator_Linear:BD25GA5WEFJ +Regulator_Linear:BD30FC0WEFJ +Regulator_Linear:BD30FC0WFP +Regulator_Linear:BD30GA3WEFJ +Regulator_Linear:BD30GA5WEFJ +Regulator_Linear:BD33FC0FP +Regulator_Linear:BD33FC0WEFJ +Regulator_Linear:BD33FC0WFP +Regulator_Linear:BD33GA3WEFJ +Regulator_Linear:BD33GA5WEFJ +Regulator_Linear:BD50FC0FP +Regulator_Linear:BD50FC0WEFJ +Regulator_Linear:BD50FC0WFP +Regulator_Linear:BD50GA3WEFJ +Regulator_Linear:BD50GA5WEFJ +Regulator_Linear:BD60FC0WEFJ +Regulator_Linear:BD60FC0WFP +Regulator_Linear:BD60GA3WEFJ +Regulator_Linear:BD60GA5WEFJ +Regulator_Linear:BD70FC0WEFJ +Regulator_Linear:BD70FC0WFP +Regulator_Linear:BD70GA3WEFJ +Regulator_Linear:BD70GA5WEFJ +Regulator_Linear:BD80FC0WEFJ +Regulator_Linear:BD80FC0WFP +Regulator_Linear:BD80GA3WEFJ +Regulator_Linear:BD80GA5WEFJ +Regulator_Linear:BD90FC0WEFJ +Regulator_Linear:BD90FC0WFP +Regulator_Linear:BD90GA3WEFJ +Regulator_Linear:BD90GA5WEFJ +Regulator_Linear:BDJ0FC0WEFJ +Regulator_Linear:BDJ0FC0WFP +Regulator_Linear:BDJ0GA3WEFJ +Regulator_Linear:BDJ0GA5WEFJ +Regulator_Linear:BDJ2FC0WEFJ +Regulator_Linear:BDJ2FC0WFP +Regulator_Linear:BDJ2GA3WEFJ +Regulator_Linear:BDJ2GA5WEFJ +Regulator_Linear:BDJ5FC0WEFJ +Regulator_Linear:BDJ5FC0WFP +Regulator_Linear:HT75xx-1-SOT89 +Regulator_Linear:ICL7663 +Regulator_Linear:ICL7664 +Regulator_Linear:IFX25401TBV +Regulator_Linear:IFX25401TBV50 +Regulator_Linear:IFX25401TEV +Regulator_Linear:IFX25401TEV50 +Regulator_Linear:IFX27001TFV +Regulator_Linear:IFX27001TFV15 +Regulator_Linear:IFX27001TFV18 +Regulator_Linear:IFX27001TFV26 +Regulator_Linear:IFX27001TFV33 +Regulator_Linear:IFX27001TFV50 +Regulator_Linear:KA378R05 +Regulator_Linear:KA378R12C +Regulator_Linear:KA378R33 +Regulator_Linear:KA78M05_TO252 +Regulator_Linear:KF25BDT +Regulator_Linear:KF33BDT +Regulator_Linear:KF50BDT +Regulator_Linear:KF80BDT +Regulator_Linear:L200 +Regulator_Linear:L7805 +Regulator_Linear:L7806 +Regulator_Linear:L7808 +Regulator_Linear:L7809 +Regulator_Linear:L7812 +Regulator_Linear:L7815 +Regulator_Linear:L7818 +Regulator_Linear:L7824 +Regulator_Linear:L7885 +Regulator_Linear:L78L05_SO8 +Regulator_Linear:L78L05_SOT89 +Regulator_Linear:L78L05_TO92 +Regulator_Linear:L78L06_SO8 +Regulator_Linear:L78L06_SOT89 +Regulator_Linear:L78L06_TO92 +Regulator_Linear:L78L08_SO8 +Regulator_Linear:L78L08_SOT89 +Regulator_Linear:L78L08_TO92 +Regulator_Linear:L78L09_SO8 +Regulator_Linear:L78L09_SOT89 +Regulator_Linear:L78L09_TO92 +Regulator_Linear:L78L10_SO8 +Regulator_Linear:L78L10_SOT89 +Regulator_Linear:L78L10_TO92 +Regulator_Linear:L78L12_SO8 +Regulator_Linear:L78L12_SOT89 +Regulator_Linear:L78L12_TO92 +Regulator_Linear:L78L15_SO8 +Regulator_Linear:L78L15_SOT89 +Regulator_Linear:L78L15_TO92 +Regulator_Linear:L78L18_SO8 +Regulator_Linear:L78L18_SOT89 +Regulator_Linear:L78L18_TO92 +Regulator_Linear:L78L24_SO8 +Regulator_Linear:L78L24_SOT89 +Regulator_Linear:L78L24_TO92 +Regulator_Linear:L78L33_SO8 +Regulator_Linear:L78L33_SOT89 +Regulator_Linear:L78L33_TO92 +Regulator_Linear:L7905 +Regulator_Linear:L7908 +Regulator_Linear:L7912 +Regulator_Linear:L7915 +Regulator_Linear:L79L05_SO8 +Regulator_Linear:L79L05_SOT89 +Regulator_Linear:L79L05_TO92 +Regulator_Linear:L79L08_SO8 +Regulator_Linear:L79L08_SOT89 +Regulator_Linear:L79L08_TO92 +Regulator_Linear:L79L12_SO8 +Regulator_Linear:L79L12_SOT89 +Regulator_Linear:L79L12_TO92 +Regulator_Linear:L79L15_SO8 +Regulator_Linear:L79L15_SOT89 +Regulator_Linear:L79L15_TO92 +Regulator_Linear:LD0186D2T50TR +Regulator_Linear:LD1086D2M33TR +Regulator_Linear:LD1086D2MTR +Regulator_Linear:LD1086D2T12TR +Regulator_Linear:LD1086D2T18TR +Regulator_Linear:LD1086D2T33TR +Regulator_Linear:LD1086D2TTR +Regulator_Linear:LD1086DT18TR +Regulator_Linear:LD1086DT25TR +Regulator_Linear:LD1086DT33TR +Regulator_Linear:LD1086DT50TR +Regulator_Linear:LD1086DTTR +Regulator_Linear:LD1086PUR +Regulator_Linear:LD1086V-DG +Regulator_Linear:LD1086V18-DG +Regulator_Linear:LD1086V33-DG +Regulator_Linear:LD1117S12TR_SOT223 +Regulator_Linear:LD1117S18TR_SOT223 +Regulator_Linear:LD1117S25TR_SOT223 +Regulator_Linear:LD1117S33TR_SOT223 +Regulator_Linear:LD1117S50TR_SOT223 +Regulator_Linear:LD39015M08R +Regulator_Linear:LD39015M10R +Regulator_Linear:LD39015M125R +Regulator_Linear:LD39015M12R +Regulator_Linear:LD39015M15R +Regulator_Linear:LD39015M18R +Regulator_Linear:LD39015M25R +Regulator_Linear:LD39015M33R +Regulator_Linear:LD39150DT18 +Regulator_Linear:LD39150DT25 +Regulator_Linear:LD39150DT33 +Regulator_Linear:LD3985G122R_TSOT23 +Regulator_Linear:LD3985G18R_TSOT23 +Regulator_Linear:LD3985G25R_TSOT23 +Regulator_Linear:LD3985G26R_TSOT23 +Regulator_Linear:LD3985G27R_TSOT23 +Regulator_Linear:LD3985G28R_TSOT23 +Regulator_Linear:LD3985G30R_TSOT23 +Regulator_Linear:LD3985G33R_TSOT23 +Regulator_Linear:LD3985G47R_TSOT23 +Regulator_Linear:LD3985M122R_SOT23 +Regulator_Linear:LD3985M18R_SOT23 +Regulator_Linear:LD3985M25R_SOT23 +Regulator_Linear:LD3985M26R_SOT23 +Regulator_Linear:LD3985M27R_SOT23 +Regulator_Linear:LD3985M28R_SOT23 +Regulator_Linear:LD3985M29R_SOT23 +Regulator_Linear:LD3985M30R_SOT23 +Regulator_Linear:LD3985M33R_SOT23 +Regulator_Linear:LD3985M47R_SOT23 +Regulator_Linear:LDK130-08_SOT23_SOT353 +Regulator_Linear:LDK130-10_SOT23_SOT353 +Regulator_Linear:LDK130-12_SOT23_SOT353 +Regulator_Linear:LDK130-15_SOT23_SOT353 +Regulator_Linear:LDK130-18_SOT23_SOT353 +Regulator_Linear:LDK130-25_SOT23_SOT353 +Regulator_Linear:LDK130-29_SOT23_SOT353 +Regulator_Linear:LDK130-30_SOT23_SOT353 +Regulator_Linear:LDK130-32_SOT23_SOT353 +Regulator_Linear:LDK130-33_SOT23_SOT353 +Regulator_Linear:LDK130-ADJ_DFN6 +Regulator_Linear:LDK130-ADJ_SOT23_SOT353 +Regulator_Linear:LDK130PU08R_DFN6 +Regulator_Linear:LDK130PU10R_DFN6 +Regulator_Linear:LDK130PU12R_DFN6 +Regulator_Linear:LDK130PU15R_DFN6 +Regulator_Linear:LDK130PU18R_DFN6 +Regulator_Linear:LDK130PU25R_DFN6 +Regulator_Linear:LDK130PU29R_DFN6 +Regulator_Linear:LDK130PU30R_DFN6 +Regulator_Linear:LDK130PU32R_DFN6 +Regulator_Linear:LDK130PU33R_DFN6 +Regulator_Linear:LF120_TO220 +Regulator_Linear:LF120_TO252 +Regulator_Linear:LF15_TO220 +Regulator_Linear:LF15_TO252 +Regulator_Linear:LF18_TO220 +Regulator_Linear:LF18_TO252 +Regulator_Linear:LF25_TO220 +Regulator_Linear:LF25_TO252 +Regulator_Linear:LF33_TO220 +Regulator_Linear:LF33_TO252 +Regulator_Linear:LF47_TO220 +Regulator_Linear:LF47_TO252 +Regulator_Linear:LF50_TO220 +Regulator_Linear:LF50_TO252 +Regulator_Linear:LF60_TO220 +Regulator_Linear:LF60_TO252 +Regulator_Linear:LF80_TO220 +Regulator_Linear:LF80_TO252 +Regulator_Linear:LF85_TO220 +Regulator_Linear:LF85_TO252 +Regulator_Linear:LF90_TO220 +Regulator_Linear:LF90_TO252 +Regulator_Linear:LK112M15TR +Regulator_Linear:LK112M18TR +Regulator_Linear:LK112M25TR +Regulator_Linear:LK112M33TR +Regulator_Linear:LK112M50TR +Regulator_Linear:LK112M55TR +Regulator_Linear:LK112M60TR +Regulator_Linear:LK112M80TR +Regulator_Linear:LM1084-3.3 +Regulator_Linear:LM1084-5.0 +Regulator_Linear:LM1084-ADJ +Regulator_Linear:LM1085-12 +Regulator_Linear:LM1085-3.3 +Regulator_Linear:LM1085-5.0 +Regulator_Linear:LM1085-ADJ +Regulator_Linear:LM1117DT-1.8 +Regulator_Linear:LM1117DT-2.5 +Regulator_Linear:LM1117DT-3.3 +Regulator_Linear:LM1117DT-5.0 +Regulator_Linear:LM1117DT-ADJ +Regulator_Linear:LM1117LD-1.8 +Regulator_Linear:LM1117LD-2.5 +Regulator_Linear:LM1117LD-3.3 +Regulator_Linear:LM1117LD-5.0 +Regulator_Linear:LM1117LD-ADJ +Regulator_Linear:LM1117MP-1.8 +Regulator_Linear:LM1117MP-2.5 +Regulator_Linear:LM1117MP-3.3 +Regulator_Linear:LM1117MP-5.0 +Regulator_Linear:LM1117MP-ADJ +Regulator_Linear:LM1117S-3.3 +Regulator_Linear:LM1117S-5.0 +Regulator_Linear:LM1117S-ADJ +Regulator_Linear:LM1117T-2.5 +Regulator_Linear:LM1117T-3.3 +Regulator_Linear:LM1117T-5.0 +Regulator_Linear:LM1117T-ADJ +Regulator_Linear:LM117_TO3 +Regulator_Linear:LM117_TO39 +Regulator_Linear:LM137_TO3 +Regulator_Linear:LM150_TO3 +Regulator_Linear:LM2931-3.3_TO220 +Regulator_Linear:LM2931-5.0_SO8 +Regulator_Linear:LM2931-5.0_TO220 +Regulator_Linear:LM2931-ADJ_TO92 +Regulator_Linear:LM2931AZ-5.0_TO92 +Regulator_Linear:LM2936-3.0 +Regulator_Linear:LM2936-3.0_TO92 +Regulator_Linear:LM2936-3.3 +Regulator_Linear:LM2936-3.3_TO92 +Regulator_Linear:LM2936-5.0 +Regulator_Linear:LM2936-5.0_TO92 +Regulator_Linear:LM2937xMP +Regulator_Linear:LM2937xS +Regulator_Linear:LM2937xT +Regulator_Linear:LM2990SX-12 +Regulator_Linear:LM2990SX-15 +Regulator_Linear:LM2990SX-5.0 +Regulator_Linear:LM317L_SO8 +Regulator_Linear:LM317L_SOT-89 +Regulator_Linear:LM317L_TO92 +Regulator_Linear:LM317_SOT-223 +Regulator_Linear:LM317_TO-220 +Regulator_Linear:LM317_TO-252 +Regulator_Linear:LM317_TO-263 +Regulator_Linear:LM317_TO3 +Regulator_Linear:LM317_TO39 +Regulator_Linear:LM337L_SO8 +Regulator_Linear:LM337L_TO92 +Regulator_Linear:LM337_SOT223 +Regulator_Linear:LM337_TO220 +Regulator_Linear:LM337_TO252 +Regulator_Linear:LM337_TO263 +Regulator_Linear:LM337_TO3 +Regulator_Linear:LM337_TO39 +Regulator_Linear:LM341T-05_TO220 +Regulator_Linear:LM341T-12_TO220 +Regulator_Linear:LM341T-15_TO220 +Regulator_Linear:LM3480-12 +Regulator_Linear:LM3480-15 +Regulator_Linear:LM3480-3.3 +Regulator_Linear:LM3480-5.0 +Regulator_Linear:LM350_TO220 +Regulator_Linear:LM350_TO3 +Regulator_Linear:LM723_DIP14 +Regulator_Linear:LM723_TO100 +Regulator_Linear:LM7805_TO220 +Regulator_Linear:LM7806_TO220 +Regulator_Linear:LM7808_TO220 +Regulator_Linear:LM7809_TO220 +Regulator_Linear:LM7810_TO220 +Regulator_Linear:LM7812_TO220 +Regulator_Linear:LM7815_TO220 +Regulator_Linear:LM7818_TO220 +Regulator_Linear:LM7824_TO220 +Regulator_Linear:LM78L05_SO8 +Regulator_Linear:LM78L05_TO92 +Regulator_Linear:LM78L12_SO8 +Regulator_Linear:LM78L12_TO92 +Regulator_Linear:LM78M05_TO220 +Regulator_Linear:LM78M05_TO252 +Regulator_Linear:LM7905_TO220 +Regulator_Linear:LM7906_TO220 +Regulator_Linear:LM7908_TO220 +Regulator_Linear:LM7909_TO220 +Regulator_Linear:LM7910_TO220 +Regulator_Linear:LM7912_TO220 +Regulator_Linear:LM7915_TO220 +Regulator_Linear:LM7918_TO220 +Regulator_Linear:LM7924_TO220 +Regulator_Linear:LM79L05_TO92 +Regulator_Linear:LM79L12_TO92 +Regulator_Linear:LM79L15_TO92 +Regulator_Linear:LM79M05_TO220 +Regulator_Linear:LM79M12_TO220 +Regulator_Linear:LM79M15_TO220 +Regulator_Linear:LP2950-3.0_TO252 +Regulator_Linear:LP2950-3.0_TO92 +Regulator_Linear:LP2950-3.3_TO252 +Regulator_Linear:LP2950-3.3_TO92 +Regulator_Linear:LP2950-5.0_TO252 +Regulator_Linear:LP2950-5.0_TO92 +Regulator_Linear:LP2951-3.0_DIP +Regulator_Linear:LP2951-3.0_SOIC +Regulator_Linear:LP2951-3.0_VSSOP +Regulator_Linear:LP2951-3.0_WSON +Regulator_Linear:LP2951-3.3_DIP +Regulator_Linear:LP2951-3.3_SOIC +Regulator_Linear:LP2951-3.3_VSSOP +Regulator_Linear:LP2951-3.3_WSON +Regulator_Linear:LP2951-5.0_DIP +Regulator_Linear:LP2951-5.0_SOIC +Regulator_Linear:LP2951-5.0_VSSOP +Regulator_Linear:LP2951-5.0_WSON +Regulator_Linear:LP2980-ADJ +Regulator_Linear:LP2985-1.8 +Regulator_Linear:LP2985-10.0 +Regulator_Linear:LP2985-2.5 +Regulator_Linear:LP2985-2.8 +Regulator_Linear:LP2985-2.9 +Regulator_Linear:LP2985-3.0 +Regulator_Linear:LP2985-3.1 +Regulator_Linear:LP2985-3.3 +Regulator_Linear:LP2985-5.0 +Regulator_Linear:LP2987-3.0_SOIC8_VSSOP8 +Regulator_Linear:LP2987-3.0_WSON8 +Regulator_Linear:LP2987-3.3_SOIC8_VSSOP8 +Regulator_Linear:LP2987-3.3_WSON8 +Regulator_Linear:LP2987-5.0_SOIC8_VSSOP8 +Regulator_Linear:LP2987-5.0_WSON8 +Regulator_Linear:LP2988-2.8_SOIC8_VSSOP8 +Regulator_Linear:LP2988-2.8_WSON8 +Regulator_Linear:LP2988-3.0_SOIC8_VSSOP8 +Regulator_Linear:LP2988-3.0_WSON8 +Regulator_Linear:LP2988-3.3_SOIC8_VSSOP8 +Regulator_Linear:LP2988-3.3_WSON8 +Regulator_Linear:LP2988-3.8_SOIC8_VSSOP8 +Regulator_Linear:LP2988-3.8_WSON8 +Regulator_Linear:LP2988-5.0_SOIC8_VSSOP8 +Regulator_Linear:LP2988-5.0_WSON8 +Regulator_Linear:LP38512MR-ADJ +Regulator_Linear:LP38512TJ-1.8 +Regulator_Linear:LP38512TJ-ADJ +Regulator_Linear:LP38512TS-1.8 +Regulator_Linear:LP38691SD-1.8 +Regulator_Linear:LP38691SD-2.5 +Regulator_Linear:LP38691SD-3.3 +Regulator_Linear:LP38691SD-5.0 +Regulator_Linear:LP38693DT-1.8 +Regulator_Linear:LP38693DT-2.5 +Regulator_Linear:LP38693DT-3.3 +Regulator_Linear:LP38693DT-5.0 +Regulator_Linear:LP38693MP-1.8 +Regulator_Linear:LP38693MP-2.5 +Regulator_Linear:LP38693MP-3.3 +Regulator_Linear:LP38693MP-5.0 +Regulator_Linear:LP38693SD-1.8 +Regulator_Linear:LP38693SD-2.5 +Regulator_Linear:LP38693SD-3.3 +Regulator_Linear:LP38693SD-5.0 +Regulator_Linear:LP3963-1.8 +Regulator_Linear:LP3963-2.5 +Regulator_Linear:LP3963-3.3 +Regulator_Linear:LP3966-1.8 +Regulator_Linear:LP3966-2.5 +Regulator_Linear:LP3966-3.3 +Regulator_Linear:LP3966-ADJ +Regulator_Linear:LP3982ILD-1.8 +Regulator_Linear:LP3982ILD-2.5 +Regulator_Linear:LP3982ILD-3.0 +Regulator_Linear:LP3982ILD-3.3 +Regulator_Linear:LP3982ILD-ADJ +Regulator_Linear:LP3982IMM-1.8 +Regulator_Linear:LP3982IMM-2.5 +Regulator_Linear:LP3982IMM-3.0 +Regulator_Linear:LP3982IMM-3.3 +Regulator_Linear:LP3982IMM-ADJ +Regulator_Linear:LP3982IMMX-2.82 +Regulator_Linear:LP3987H-33B5 +Regulator_Linear:LP3992-18B5 +Regulator_Linear:LP5907MFX-1.2 +Regulator_Linear:LP5907MFX-1.5 +Regulator_Linear:LP5907MFX-1.8 +Regulator_Linear:LP5907MFX-2.5 +Regulator_Linear:LP5907MFX-2.8 +Regulator_Linear:LP5907MFX-2.85 +Regulator_Linear:LP5907MFX-2.9 +Regulator_Linear:LP5907MFX-3.0 +Regulator_Linear:LP5907MFX-3.1 +Regulator_Linear:LP5907MFX-3.2 +Regulator_Linear:LP5907MFX-3.3 +Regulator_Linear:LP5907MFX-4.5 +Regulator_Linear:LP5912-0.9DRV +Regulator_Linear:LP5912-1.0DRV +Regulator_Linear:LP5912-1.1DRV +Regulator_Linear:LP5912-1.2DRV +Regulator_Linear:LP5912-1.5DRV +Regulator_Linear:LP5912-1.8DRV +Regulator_Linear:LP5912-2.5DRV +Regulator_Linear:LP5912-2.8DRV +Regulator_Linear:LP5912-3.0DRV +Regulator_Linear:LP5912-3.3DRV +Regulator_Linear:LP5912-5.0DRV +Regulator_Linear:LR8K4-G +Regulator_Linear:LR8N3-G +Regulator_Linear:LR8N8-G +Regulator_Linear:LT1033C +Regulator_Linear:LT1083-12 +Regulator_Linear:LT1083-3.3 +Regulator_Linear:LT1083-3.6 +Regulator_Linear:LT1083-5.0 +Regulator_Linear:LT1083-ADJ +Regulator_Linear:LT1084-12 +Regulator_Linear:LT1084-3.3 +Regulator_Linear:LT1084-3.6 +Regulator_Linear:LT1084-5.0 +Regulator_Linear:LT1084-ADJ +Regulator_Linear:LT1085-12 +Regulator_Linear:LT1085-3.3 +Regulator_Linear:LT1085-3.6 +Regulator_Linear:LT1085-5.0 +Regulator_Linear:LT1085-ADJ +Regulator_Linear:LT1086-12 +Regulator_Linear:LT1086-2.85 +Regulator_Linear:LT1086-3.3 +Regulator_Linear:LT1086-3.6 +Regulator_Linear:LT1086-5.0 +Regulator_Linear:LT1086-ADJ +Regulator_Linear:LT1117-2.85 +Regulator_Linear:LT1117-3.3 +Regulator_Linear:LT1117-5.0 +Regulator_Linear:LT1117-ADJ +Regulator_Linear:LT1129-3.3_SO8 +Regulator_Linear:LT1129-3.3_SOT223 +Regulator_Linear:LT1129-3.3_TO220_TO263 +Regulator_Linear:LT1129-5.0_SO8 +Regulator_Linear:LT1129-5.0_SOT223 +Regulator_Linear:LT1129-5.0_TO220_TO263 +Regulator_Linear:LT1129-ADJ_SO8 +Regulator_Linear:LT1129-ADJ_TO220_TO263 +Regulator_Linear:LT1175-5_SO8_DIP8 +Regulator_Linear:LT1175-5_SOT223 +Regulator_Linear:LT1175-5_TO263_TO220 +Regulator_Linear:LT1175-ADJ_SO8_DIP8 +Regulator_Linear:LT1175-ADJ_SOT223 +Regulator_Linear:LT1175-ADJ_TO263_TO220 +Regulator_Linear:LT1584-3.3 +Regulator_Linear:LT1584-3.38 +Regulator_Linear:LT1584-3.45 +Regulator_Linear:LT1584-3.6 +Regulator_Linear:LT1584-ADJ +Regulator_Linear:LT1585-3.3 +Regulator_Linear:LT1585-3.38 +Regulator_Linear:LT1585-3.45 +Regulator_Linear:LT1585-3.6 +Regulator_Linear:LT1585-ADJ +Regulator_Linear:LT1587-3.3 +Regulator_Linear:LT1587-3.45 +Regulator_Linear:LT1587-3.6 +Regulator_Linear:LT1587-ADJ +Regulator_Linear:LT1761-1.2 +Regulator_Linear:LT1761-1.5 +Regulator_Linear:LT1761-1.8 +Regulator_Linear:LT1761-2 +Regulator_Linear:LT1761-2.5 +Regulator_Linear:LT1761-2.8 +Regulator_Linear:LT1761-3 +Regulator_Linear:LT1761-3.3 +Regulator_Linear:LT1761-5 +Regulator_Linear:LT1761-BYP +Regulator_Linear:LT1761-SD +Regulator_Linear:LT1762 +Regulator_Linear:LT1762-2.5 +Regulator_Linear:LT1762-3 +Regulator_Linear:LT1762-3.3 +Regulator_Linear:LT1762-5 +Regulator_Linear:LT1962 +Regulator_Linear:LT1962-1.5 +Regulator_Linear:LT1962-1.8 +Regulator_Linear:LT1962-2.5 +Regulator_Linear:LT1962-3 +Regulator_Linear:LT1962-3.3 +Regulator_Linear:LT1962-5 +Regulator_Linear:LT1963AEQ +Regulator_Linear:LT1963AxQ-1.5 +Regulator_Linear:LT1963AxQ-1.8 +Regulator_Linear:LT1963AxQ-2.5 +Regulator_Linear:LT1963AxQ-3.3 +Regulator_Linear:LT1963AxST-1.5 +Regulator_Linear:LT1963AxST-1.8 +Regulator_Linear:LT1963AxST-2.5 +Regulator_Linear:LT1963AxST-3.3 +Regulator_Linear:LT1963EQ +Regulator_Linear:LT1964-5 +Regulator_Linear:LT1964-BYP +Regulator_Linear:LT1964-SD +Regulator_Linear:LT3010 +Regulator_Linear:LT3010-5 +Regulator_Linear:LT3011xDD +Regulator_Linear:LT3011xMSE +Regulator_Linear:LT3014xDD +Regulator_Linear:LT3014xS5 +Regulator_Linear:LT3015Q +Regulator_Linear:LT3015xQ-12 +Regulator_Linear:LT3015xQ-15 +Regulator_Linear:LT3015xQ-2.5 +Regulator_Linear:LT3015xQ-3 +Regulator_Linear:LT3015xQ-3.3 +Regulator_Linear:LT3015xQ-5 +Regulator_Linear:LT3032 +Regulator_Linear:LT3032-12 +Regulator_Linear:LT3032-15 +Regulator_Linear:LT3032-3.3 +Regulator_Linear:LT3032-5 +Regulator_Linear:LT3033xUDC +Regulator_Linear:LT3042xMSE +Regulator_Linear:LT3045xDD +Regulator_Linear:LT3045xMSE +Regulator_Linear:LT3080xDD +Regulator_Linear:LT3080xMS8E +Regulator_Linear:LT3080xQ +Regulator_Linear:LT3080xST +Regulator_Linear:LT3080xT +Regulator_Linear:LT3091xT7 +Regulator_Linear:LT3093xMSE +Regulator_Linear:LT3094xDD +Regulator_Linear:LT3094xMSE +Regulator_Linear:LTC3026-1 +Regulator_Linear:MAX1615xUK +Regulator_Linear:MAX1616xUK +Regulator_Linear:MAX1658ESA +Regulator_Linear:MAX1659ESA +Regulator_Linear:MAX16910 +Regulator_Linear:MAX38908xTD +Regulator_Linear:MAX38909xTD +Regulator_Linear:MAX38911ATA+ +Regulator_Linear:MAX38912ATA+ +Regulator_Linear:MAX5092AATE +Regulator_Linear:MAX5092BATE +Regulator_Linear:MAX5093AATE +Regulator_Linear:MAX5093BATE +Regulator_Linear:MAX603 +Regulator_Linear:MAX604 +Regulator_Linear:MAX663 +Regulator_Linear:MAX664 +Regulator_Linear:MAX666 +Regulator_Linear:MAX882 +Regulator_Linear:MAX883 +Regulator_Linear:MAX884 +Regulator_Linear:MC78L05_SO8 +Regulator_Linear:MC78L05_SOT89 +Regulator_Linear:MC78L05_TO92 +Regulator_Linear:MC78L06_SO8 +Regulator_Linear:MC78L06_TO92 +Regulator_Linear:MC78L08_SO8 +Regulator_Linear:MC78L08_SOT89 +Regulator_Linear:MC78L08_TO92 +Regulator_Linear:MC78L12_SO8 +Regulator_Linear:MC78L12_SOT89 +Regulator_Linear:MC78L12_TO92 +Regulator_Linear:MC78L15_SO8 +Regulator_Linear:MC78L15_TO92 +Regulator_Linear:MC78L18_SO8 +Regulator_Linear:MC78L18_TO92 +Regulator_Linear:MC78L24_SO8 +Regulator_Linear:MC78L24_TO92 +Regulator_Linear:MC78LC18NTR +Regulator_Linear:MC78LC25NTR +Regulator_Linear:MC78LC30NTR +Regulator_Linear:MC78LC33NTR +Regulator_Linear:MC78LC50NTR +Regulator_Linear:MC78M05_TO252 +Regulator_Linear:MC7905 +Regulator_Linear:MC7905.2 +Regulator_Linear:MC7906 +Regulator_Linear:MC7908 +Regulator_Linear:MC7912 +Regulator_Linear:MC7915 +Regulator_Linear:MC7918 +Regulator_Linear:MC7924 +Regulator_Linear:MC79L05_SO8 +Regulator_Linear:MC79L12_SO8 +Regulator_Linear:MC79L15_SO8 +Regulator_Linear:MC79M05_TO220 +Regulator_Linear:MC79M05_TO252 +Regulator_Linear:MC79M08_TO220 +Regulator_Linear:MC79M08_TO252 +Regulator_Linear:MC79M12_TO220 +Regulator_Linear:MC79M12_TO252 +Regulator_Linear:MC79M15_TO220 +Regulator_Linear:MC79M15_TO252 +Regulator_Linear:MCP1700x-120xxMB +Regulator_Linear:MCP1700x-120xxTO +Regulator_Linear:MCP1700x-120xxTT +Regulator_Linear:MCP1700x-180xxMB +Regulator_Linear:MCP1700x-180xxTO +Regulator_Linear:MCP1700x-180xxTT +Regulator_Linear:MCP1700x-250xxMB +Regulator_Linear:MCP1700x-250xxTO +Regulator_Linear:MCP1700x-250xxTT +Regulator_Linear:MCP1700x-280xxMB +Regulator_Linear:MCP1700x-280xxTO +Regulator_Linear:MCP1700x-280xxTT +Regulator_Linear:MCP1700x-300xxMB +Regulator_Linear:MCP1700x-300xxTO +Regulator_Linear:MCP1700x-300xxTT +Regulator_Linear:MCP1700x-330xxMB +Regulator_Linear:MCP1700x-330xxTO +Regulator_Linear:MCP1700x-330xxTT +Regulator_Linear:MCP1700x-500xxMB +Regulator_Linear:MCP1700x-500xxTO +Regulator_Linear:MCP1700x-500xxTT +Regulator_Linear:MCP1703Ax-120xxDB +Regulator_Linear:MCP1703Ax-120xxMB +Regulator_Linear:MCP1703Ax-120xxTT +Regulator_Linear:MCP1703Ax-150xxDB +Regulator_Linear:MCP1703Ax-150xxMB +Regulator_Linear:MCP1703Ax-150xxTT +Regulator_Linear:MCP1703Ax-180xxDB +Regulator_Linear:MCP1703Ax-180xxMB +Regulator_Linear:MCP1703Ax-180xxTT +Regulator_Linear:MCP1703Ax-250xxDB +Regulator_Linear:MCP1703Ax-250xxMB +Regulator_Linear:MCP1703Ax-250xxTT +Regulator_Linear:MCP1703Ax-280xxDB +Regulator_Linear:MCP1703Ax-280xxMB +Regulator_Linear:MCP1703Ax-280xxTT +Regulator_Linear:MCP1703Ax-300xxDB +Regulator_Linear:MCP1703Ax-300xxMB +Regulator_Linear:MCP1703Ax-300xxTT +Regulator_Linear:MCP1703Ax-330xxDB +Regulator_Linear:MCP1703Ax-330xxMB +Regulator_Linear:MCP1703Ax-330xxTT +Regulator_Linear:MCP1703Ax-400xxDB +Regulator_Linear:MCP1703Ax-400xxMB +Regulator_Linear:MCP1703Ax-400xxTT +Regulator_Linear:MCP1703Ax-500xxDB +Regulator_Linear:MCP1703Ax-500xxMB +Regulator_Linear:MCP1703Ax-500xxTT +Regulator_Linear:MCP1727-0802xMF +Regulator_Linear:MCP1727-0802xSN +Regulator_Linear:MCP1727-1202xMF +Regulator_Linear:MCP1727-1202xSN +Regulator_Linear:MCP1727-1802xMF +Regulator_Linear:MCP1727-1802xSN +Regulator_Linear:MCP1727-2502xMF +Regulator_Linear:MCP1727-2502xSN +Regulator_Linear:MCP1727-3002xMF +Regulator_Linear:MCP1727-3002xSN +Regulator_Linear:MCP1727-3302xMF +Regulator_Linear:MCP1727-3302xSN +Regulator_Linear:MCP1727-5002xMF +Regulator_Linear:MCP1727-5002xSN +Regulator_Linear:MCP1727-ADJxMF +Regulator_Linear:MCP1727-ADJxSN +Regulator_Linear:MCP1754S-1802xCB +Regulator_Linear:MCP1754S-1802xMB +Regulator_Linear:MCP1754S-3302xCB +Regulator_Linear:MCP1754S-3302xMB +Regulator_Linear:MCP1754S-5002xCB +Regulator_Linear:MCP1754S-5002xMB +Regulator_Linear:MCP1792x-3302xCB +Regulator_Linear:MCP1792x-3302xDB +Regulator_Linear:MCP1792x-4102xCB +Regulator_Linear:MCP1792x-4102xDB +Regulator_Linear:MCP1792x-5002xCB +Regulator_Linear:MCP1792x-5002xDB +Regulator_Linear:MCP1799x-330xxTT +Regulator_Linear:MCP1799x-500xxTT +Regulator_Linear:MCP1802x-xx02xOT +Regulator_Linear:MCP1804x-1802xDB +Regulator_Linear:MCP1804x-1802xMB +Regulator_Linear:MCP1804x-1802xMT +Regulator_Linear:MCP1804x-1802xOT +Regulator_Linear:MCP1804x-2502xDB +Regulator_Linear:MCP1804x-2502xMB +Regulator_Linear:MCP1804x-2502xMT +Regulator_Linear:MCP1804x-2502xOT +Regulator_Linear:MCP1804x-3002xDB +Regulator_Linear:MCP1804x-3002xMB +Regulator_Linear:MCP1804x-3002xMT +Regulator_Linear:MCP1804x-3002xOT +Regulator_Linear:MCP1804x-3302xDB +Regulator_Linear:MCP1804x-3302xMB +Regulator_Linear:MCP1804x-3302xMT +Regulator_Linear:MCP1804x-3302xOT +Regulator_Linear:MCP1804x-5002xDB +Regulator_Linear:MCP1804x-5002xMB +Regulator_Linear:MCP1804x-5002xMT +Regulator_Linear:MCP1804x-5002xOT +Regulator_Linear:MCP1804x-A002xDB +Regulator_Linear:MCP1804x-A002xMB +Regulator_Linear:MCP1804x-A002xMT +Regulator_Linear:MCP1804x-A002xOT +Regulator_Linear:MCP1804x-C002xDB +Regulator_Linear:MCP1804x-C002xMB +Regulator_Linear:MCP1804x-C002xMT +Regulator_Linear:MCP1804x-C002xOT +Regulator_Linear:MCP1825S +Regulator_Linear:MCP1826S +Regulator_Linear:ME6211C10M5 +Regulator_Linear:ME6211C12M5 +Regulator_Linear:ME6211C15M5 +Regulator_Linear:ME6211C18M5 +Regulator_Linear:ME6211C21M5 +Regulator_Linear:ME6211C25M5 +Regulator_Linear:ME6211C27M5 +Regulator_Linear:ME6211C28M5 +Regulator_Linear:ME6211C29M5 +Regulator_Linear:ME6211C30M5 +Regulator_Linear:ME6211C33M5 +Regulator_Linear:ME6211C50M5 +Regulator_Linear:MIC29152WT +Regulator_Linear:MIC29152WU +Regulator_Linear:MIC29153WT +Regulator_Linear:MIC29153WU +Regulator_Linear:MIC29302AWD +Regulator_Linear:MIC29302AWU +Regulator_Linear:MIC29302WT +Regulator_Linear:MIC29302WU +Regulator_Linear:MIC29303WT +Regulator_Linear:MIC29303WU +Regulator_Linear:MIC29502WT +Regulator_Linear:MIC29502WU +Regulator_Linear:MIC29503WT +Regulator_Linear:MIC29503WU +Regulator_Linear:MIC29752WT +Regulator_Linear:MIC5205-2.5YM5 +Regulator_Linear:MIC5205-2.7YM5 +Regulator_Linear:MIC5205-2.85YM5 +Regulator_Linear:MIC5205-2.8YM5 +Regulator_Linear:MIC5205-2.9YM5 +Regulator_Linear:MIC5205-3.0YM5 +Regulator_Linear:MIC5205-3.1YM5 +Regulator_Linear:MIC5205-3.2YM5 +Regulator_Linear:MIC5205-3.3YM5 +Regulator_Linear:MIC5205-3.6YM5 +Regulator_Linear:MIC5205-3.8YM5 +Regulator_Linear:MIC5205-4.0YM5 +Regulator_Linear:MIC5205-5.0YM5 +Regulator_Linear:MIC5205YM5 +Regulator_Linear:MIC5219-2.5YM5 +Regulator_Linear:MIC5219-2.5YMM +Regulator_Linear:MIC5219-2.6YM5 +Regulator_Linear:MIC5219-2.7YM5 +Regulator_Linear:MIC5219-2.85YM5 +Regulator_Linear:MIC5219-2.85YMM +Regulator_Linear:MIC5219-2.8YM5 +Regulator_Linear:MIC5219-2.9YM5 +Regulator_Linear:MIC5219-3.0YM5 +Regulator_Linear:MIC5219-3.0YMM +Regulator_Linear:MIC5219-3.1YM5 +Regulator_Linear:MIC5219-3.3YM5 +Regulator_Linear:MIC5219-3.3YMM +Regulator_Linear:MIC5219-3.6YM5 +Regulator_Linear:MIC5219-3.6YMM +Regulator_Linear:MIC5219-5.0YM5 +Regulator_Linear:MIC5219-5.0YMM +Regulator_Linear:MIC5219YM5 +Regulator_Linear:MIC5219YMM +Regulator_Linear:MIC5317-1.0xM5 +Regulator_Linear:MIC5317-1.2xM5 +Regulator_Linear:MIC5317-1.5xM5 +Regulator_Linear:MIC5317-1.8xM5 +Regulator_Linear:MIC5317-2.5xM5 +Regulator_Linear:MIC5317-2.8xM5 +Regulator_Linear:MIC5317-3.0xM5 +Regulator_Linear:MIC5317-3.3xM5 +Regulator_Linear:MIC5350 +Regulator_Linear:MIC5353-1.8YMT +Regulator_Linear:MIC5353-2.5YMT +Regulator_Linear:MIC5353-2.6YMT +Regulator_Linear:MIC5353-2.8YMT +Regulator_Linear:MIC5353-3.0YMT +Regulator_Linear:MIC5353-3.3YMT +Regulator_Linear:MIC5353YMT +Regulator_Linear:MIC5355-G4YMME +Regulator_Linear:MIC5355-JGYMME +Regulator_Linear:MIC5355-S4YMME +Regulator_Linear:MIC5355-SCYMME +Regulator_Linear:MIC5355-SGYMME +Regulator_Linear:MIC5356-G4YMME +Regulator_Linear:MIC5356-JGYMME +Regulator_Linear:MIC5356-MGYML +Regulator_Linear:MIC5356-MMYML +Regulator_Linear:MIC5356-S4YMME +Regulator_Linear:MIC5356-SCYMME +Regulator_Linear:MIC5356-SGYMME +Regulator_Linear:MIC5365-3.3YC5 +Regulator_Linear:MIC5365-3.3YD5 +Regulator_Linear:MIC5366-3.3YC5 +Regulator_Linear:MIC5501-3.0YM5 +Regulator_Linear:MIC5504-1.2YM5 +Regulator_Linear:MIC5504-1.8YM5 +Regulator_Linear:MIC5504-2.5YM5 +Regulator_Linear:MIC5504-2.8YM5 +Regulator_Linear:MIC5504-3.3YM5 +Regulator_Linear:NCP1117-1.5_SOT223 +Regulator_Linear:NCP1117-1.5_TO252 +Regulator_Linear:NCP1117-1.8_SOT223 +Regulator_Linear:NCP1117-1.8_TO252 +Regulator_Linear:NCP1117-1.9_TO252 +Regulator_Linear:NCP1117-12_SOT223 +Regulator_Linear:NCP1117-12_TO252 +Regulator_Linear:NCP1117-2.0_SOT223 +Regulator_Linear:NCP1117-2.0_TO252 +Regulator_Linear:NCP1117-2.5_SOT223 +Regulator_Linear:NCP1117-2.5_TO252 +Regulator_Linear:NCP1117-2.85_SOT223 +Regulator_Linear:NCP1117-2.85_TO252 +Regulator_Linear:NCP1117-3.3_SOT223 +Regulator_Linear:NCP1117-3.3_TO252 +Regulator_Linear:NCP1117-5.0_SOT223 +Regulator_Linear:NCP1117-5.0_TO252 +Regulator_Linear:NCP1117-ADJ_SOT223 +Regulator_Linear:NCP1117-ADJ_TO252 +Regulator_Linear:NCP115AMX120TCG +Regulator_Linear:NCP115AMX250TCG +Regulator_Linear:NCP133AMX100TCG +Regulator_Linear:NCP163AFCS120T2G +Regulator_Linear:NCP163AFCS180T2G +Regulator_Linear:NCP163AFCS250T2G +Regulator_Linear:NCP163AFCS260T2G +Regulator_Linear:NCP163AFCS270T2G +Regulator_Linear:NCP163AFCS280T2G +Regulator_Linear:NCP163AFCS285T2G +Regulator_Linear:NCP163AFCS290T2G +Regulator_Linear:NCP163AFCS2925T2G +Regulator_Linear:NCP163AFCS514T2G +Regulator_Linear:NCP163AFCT120T2G +Regulator_Linear:NCP163AFCT180T2G +Regulator_Linear:NCP163AFCT250T2G +Regulator_Linear:NCP163AFCT260T2G +Regulator_Linear:NCP163AFCT270T2G +Regulator_Linear:NCP163AFCT280T2G +Regulator_Linear:NCP163AFCT285T2G +Regulator_Linear:NCP163AFCT290T2G +Regulator_Linear:NCP163AFCT2925T2G +Regulator_Linear:NCP163AFCT300T2G +Regulator_Linear:NCP163AFCT330T2G +Regulator_Linear:NCP163AFCT514T2G +Regulator_Linear:NCP163ASN150T1G +Regulator_Linear:NCP163ASN180T1G +Regulator_Linear:NCP163ASN250T1G +Regulator_Linear:NCP163ASN270T1G +Regulator_Linear:NCP163ASN280T1G +Regulator_Linear:NCP163ASN300T1G +Regulator_Linear:NCP163ASN330T1G +Regulator_Linear:NCP163ASN350T1G +Regulator_Linear:NCP163ASN500T1G +Regulator_Linear:NCP163BFCS180T2G +Regulator_Linear:NCP163BFCS2925T2G +Regulator_Linear:NCP163BFCT180T2G +Regulator_Linear:NCP163CFCS285T2G +Regulator_Linear:NCP662SQ15 +Regulator_Linear:NCP662SQ18 +Regulator_Linear:NCP662SQ33 +Regulator_Linear:NCP662SQ50 +Regulator_Linear:NCP718xSN120 +Regulator_Linear:NCP718xSN150 +Regulator_Linear:NCP718xSN180 +Regulator_Linear:NCP718xSN250 +Regulator_Linear:NCP718xSN300 +Regulator_Linear:NCP718xSN330 +Regulator_Linear:NCP718xSN500 +Regulator_Linear:NCV8114ASN120T1G +Regulator_Linear:NCV8114ASN150T1G +Regulator_Linear:NCV8114ASN165T1G +Regulator_Linear:NCV8114ASN180T1G +Regulator_Linear:NCV8114ASN250T1G +Regulator_Linear:NCV8114ASN280T1G +Regulator_Linear:NCV8114ASN300T1G +Regulator_Linear:NCV8114ASN330T1G +Regulator_Linear:NCV8114BSN120T1G +Regulator_Linear:NCV8114BSN150T1G +Regulator_Linear:NCV8114BSN180T1G +Regulator_Linear:NCV8114BSN280T1G +Regulator_Linear:NCV8114BSN300T1G +Regulator_Linear:NCV8114BSN330T1G +Regulator_Linear:NDP6802SF-33 +Regulator_Linear:NDP6802SF-50 +Regulator_Linear:NDP6802SF-A2 +Regulator_Linear:NVC8674DS120 +Regulator_Linear:NVC8674DS50 +Regulator_Linear:OM1323_TO220 +Regulator_Linear:SPX2920M3-3.3_SOT223 +Regulator_Linear:SPX2920M3-5.0_SOT223 +Regulator_Linear:SPX2920S-3.3_SO8 +Regulator_Linear:SPX2920S-5.0_SO8 +Regulator_Linear:SPX2920T-3.3_TO263 +Regulator_Linear:SPX2920T-5.0_TO263 +Regulator_Linear:SPX2920U-3.3_TO220 +Regulator_Linear:SPX2920U-5.0_TO220 +Regulator_Linear:SPX3819M5-L +Regulator_Linear:SPX3819M5-L-1-2 +Regulator_Linear:SPX3819M5-L-1-5 +Regulator_Linear:SPX3819M5-L-1-8 +Regulator_Linear:SPX3819M5-L-2-5 +Regulator_Linear:SPX3819M5-L-3-0 +Regulator_Linear:SPX3819M5-L-3-3 +Regulator_Linear:SPX3819M5-L-5-0 +Regulator_Linear:TC1014-xCT +Regulator_Linear:TC1015-xCT +Regulator_Linear:TC1017-xCT +Regulator_Linear:TC1017-xLT +Regulator_Linear:TC1017R-xLT +Regulator_Linear:TC1054 +Regulator_Linear:TC1055 +Regulator_Linear:TC1185-xCT +Regulator_Linear:TC1186 +Regulator_Linear:TC1262-25 +Regulator_Linear:TC1262-28 +Regulator_Linear:TC1262-30 +Regulator_Linear:TC1262-33 +Regulator_Linear:TC1262-50 +Regulator_Linear:TC2014-1.8VxCTTR +Regulator_Linear:TC2014-2.5VxCTTR +Regulator_Linear:TC2014-2.6VxCTTR +Regulator_Linear:TC2014-2.7VxCTTR +Regulator_Linear:TC2014-2.85VxCTTR +Regulator_Linear:TC2014-2.8VxCTTR +Regulator_Linear:TC2014-3.0VxCTTR +Regulator_Linear:TC2014-3.3VxCTTR +Regulator_Linear:TC2014-5.0VxCTTR +Regulator_Linear:TC2015-1.8VxCTTR +Regulator_Linear:TC2015-2.5VxCTTR +Regulator_Linear:TC2015-2.6VxCTTR +Regulator_Linear:TC2015-2.7VxCTTR +Regulator_Linear:TC2015-2.85VxCTTR +Regulator_Linear:TC2015-2.8VxCTTR +Regulator_Linear:TC2015-3.0VxCTTR +Regulator_Linear:TC2015-3.3VxCTTR +Regulator_Linear:TC2015-5.0VxCTTR +Regulator_Linear:TC2185-1.8VxCTTR +Regulator_Linear:TC2185-2.5VxCTTR +Regulator_Linear:TC2185-2.6VxCTTR +Regulator_Linear:TC2185-2.7VxCTTR +Regulator_Linear:TC2185-2.85VxCTTR +Regulator_Linear:TC2185-2.8VxCTTR +Regulator_Linear:TC2185-3.0VxCTTR +Regulator_Linear:TC2185-3.3VxCTTR +Regulator_Linear:TC2185-5.0VxCTTR +Regulator_Linear:TCR2EE10 +Regulator_Linear:TCR2EE105 +Regulator_Linear:TCR2EE11 +Regulator_Linear:TCR2EE115 +Regulator_Linear:TCR2EE12 +Regulator_Linear:TCR2EE125 +Regulator_Linear:TCR2EE13 +Regulator_Linear:TCR2EE135 +Regulator_Linear:TCR2EE14 +Regulator_Linear:TCR2EE145 +Regulator_Linear:TCR2EE15 +Regulator_Linear:TCR2EE17 +Regulator_Linear:TCR2EE18 +Regulator_Linear:TCR2EE185 +Regulator_Linear:TCR2EE19 +Regulator_Linear:TCR2EE20 +Regulator_Linear:TCR2EE24 +Regulator_Linear:TCR2EE25 +Regulator_Linear:TCR2EE27 +Regulator_Linear:TCR2EE275 +Regulator_Linear:TLV1117-15 +Regulator_Linear:TLV1117-18 +Regulator_Linear:TLV1117-25 +Regulator_Linear:TLV1117-33 +Regulator_Linear:TLV1117-50 +Regulator_Linear:TLV1117-ADJ +Regulator_Linear:TLV70012_SOT23-5 +Regulator_Linear:TLV70012_SOT353 +Regulator_Linear:TLV70012_WSON6 +Regulator_Linear:TLV70013_SOT23-5 +Regulator_Linear:TLV70015_SOT23-5 +Regulator_Linear:TLV70015_SOT353 +Regulator_Linear:TLV70015_WSON6 +Regulator_Linear:TLV70018_SOT23-5 +Regulator_Linear:TLV70018_SOT353 +Regulator_Linear:TLV70018_WSON6 +Regulator_Linear:TLV70019_SOT23-5 +Regulator_Linear:TLV70025_SOT23-5 +Regulator_Linear:TLV70025_SOT353 +Regulator_Linear:TLV70025_WSON6 +Regulator_Linear:TLV70028_SOT353 +Regulator_Linear:TLV70028_WSON6 +Regulator_Linear:TLV70029_WSON6 +Regulator_Linear:TLV70030_SOT23-5 +Regulator_Linear:TLV70030_SOT353 +Regulator_Linear:TLV70030_WSON6 +Regulator_Linear:TLV70031_WSON6 +Regulator_Linear:TLV70032_SOT23-5 +Regulator_Linear:TLV70033_SOT23-5 +Regulator_Linear:TLV70033_SOT353 +Regulator_Linear:TLV70033_WSON6 +Regulator_Linear:TLV70036_SOT23-5 +Regulator_Linear:TLV70036_WSON6 +Regulator_Linear:TLV70212_SOT23-5 +Regulator_Linear:TLV70215_SOT23-5 +Regulator_Linear:TLV70218_SOT23-5 +Regulator_Linear:TLV70225_SOT23-5 +Regulator_Linear:TLV70225_WSON6 +Regulator_Linear:TLV70228_SOT23-5 +Regulator_Linear:TLV70228_WSON6 +Regulator_Linear:TLV70229_WSON6 +Regulator_Linear:TLV70230_SOT23-5 +Regulator_Linear:TLV70231_SOT23-5 +Regulator_Linear:TLV70233_SOT23-5 +Regulator_Linear:TLV70233_WSON6 +Regulator_Linear:TLV70235_SOT23-5 +Regulator_Linear:TLV70236_WSON6 +Regulator_Linear:TLV70237_SOT23-5 +Regulator_Linear:TLV70237_WSON6 +Regulator_Linear:TLV70242PDSE +Regulator_Linear:TLV70245_SOT23-5 +Regulator_Linear:TLV702475_SOT23-5 +Regulator_Linear:TLV7113318DDSE +Regulator_Linear:TLV7113333DDSE +Regulator_Linear:TLV71209_SOT23-5 +Regulator_Linear:TLV71210_SOT23-5 +Regulator_Linear:TLV71211_SOT23-5 +Regulator_Linear:TLV71310PDBV +Regulator_Linear:TLV71311PDBV +Regulator_Linear:TLV71312PDBV +Regulator_Linear:TLV71315PDBV +Regulator_Linear:TLV713185PDBV +Regulator_Linear:TLV71318PDBV +Regulator_Linear:TLV71325PDBV +Regulator_Linear:TLV713285PDBV +Regulator_Linear:TLV71328PDBV +Regulator_Linear:TLV71330PDBV +Regulator_Linear:TLV71333PDBV +Regulator_Linear:TLV71x_WSON-6 +Regulator_Linear:TLV73310PDBV +Regulator_Linear:TLV73311PDBV +Regulator_Linear:TLV73312PDBV +Regulator_Linear:TLV73315PDBV +Regulator_Linear:TLV73318PDBV +Regulator_Linear:TLV73325PDBV +Regulator_Linear:TLV733285PDBV +Regulator_Linear:TLV73328PDBV +Regulator_Linear:TLV73330PDBV +Regulator_Linear:TLV73333PDBV +Regulator_Linear:TLV75509PDBV +Regulator_Linear:TLV75509PDRV +Regulator_Linear:TLV75510PDBV +Regulator_Linear:TLV75510PDRV +Regulator_Linear:TLV75512PDBV +Regulator_Linear:TLV75512PDRV +Regulator_Linear:TLV75515PDBV +Regulator_Linear:TLV75515PDRV +Regulator_Linear:TLV75518PDBV +Regulator_Linear:TLV75518PDRV +Regulator_Linear:TLV75519PDBV +Regulator_Linear:TLV75519PDRV +Regulator_Linear:TLV75525PDBV +Regulator_Linear:TLV75525PDRV +Regulator_Linear:TLV75528PDBV +Regulator_Linear:TLV75528PDRV +Regulator_Linear:TLV75529PDBV +Regulator_Linear:TLV75529PDRV +Regulator_Linear:TLV75530PDBV +Regulator_Linear:TLV75530PDRV +Regulator_Linear:TLV75533PDBV +Regulator_Linear:TLV75533PDRV +Regulator_Linear:TLV75709PDBV +Regulator_Linear:TLV75709PDRV +Regulator_Linear:TLV75710PDBV +Regulator_Linear:TLV75710PDRV +Regulator_Linear:TLV75712PDBV +Regulator_Linear:TLV75712PDRV +Regulator_Linear:TLV75715PDBV +Regulator_Linear:TLV75715PDRV +Regulator_Linear:TLV75718PDBV +Regulator_Linear:TLV75718PDRV +Regulator_Linear:TLV75719PDBV +Regulator_Linear:TLV75719PDRV +Regulator_Linear:TLV75725PDBV +Regulator_Linear:TLV75725PDRV +Regulator_Linear:TLV75728PDBV +Regulator_Linear:TLV75728PDRV +Regulator_Linear:TLV75729PDBV +Regulator_Linear:TLV75730PDBV +Regulator_Linear:TLV75730PDRV +Regulator_Linear:TLV75733PDBV +Regulator_Linear:TLV75733PDRV +Regulator_Linear:TLV75740PDRV +Regulator_Linear:TLV75801PDBV +Regulator_Linear:TLV75801PDRV +Regulator_Linear:TLV76133DCY +Regulator_Linear:TLV76150DCY +Regulator_Linear:TLV76701DRVx +Regulator_Linear:TLV76701QWDRBxQ1 +Regulator_Linear:TLV76708DRVx +Regulator_Linear:TLV76718DRVx +Regulator_Linear:TLV76728DRVx +Regulator_Linear:TLV76733DRVx +Regulator_Linear:TLV76733QWDRBxQ1 +Regulator_Linear:TLV76750DRVx +Regulator_Linear:TLV76750QWDRBxQ1 +Regulator_Linear:TLV76760QWDRBxQ1 +Regulator_Linear:TLV76780QWDRBxQ1 +Regulator_Linear:TLV76790QWDRBxQ1 +Regulator_Linear:TPS51200DRC +Regulator_Linear:TPS70202_HTSSOP20 +Regulator_Linear:TPS70245_HTSSOP20 +Regulator_Linear:TPS70248_HTSSOP20 +Regulator_Linear:TPS70251_HTSSOP20 +Regulator_Linear:TPS70258_HTSSOP20 +Regulator_Linear:TPS70302 +Regulator_Linear:TPS70345 +Regulator_Linear:TPS70348 +Regulator_Linear:TPS70351 +Regulator_Linear:TPS70358 +Regulator_Linear:TPS70402 +Regulator_Linear:TPS70445 +Regulator_Linear:TPS70448 +Regulator_Linear:TPS70451 +Regulator_Linear:TPS70458 +Regulator_Linear:TPS7101 +Regulator_Linear:TPS7133 +Regulator_Linear:TPS7148 +Regulator_Linear:TPS7150 +Regulator_Linear:TPS71518__SC70 +Regulator_Linear:TPS71519__SC70 +Regulator_Linear:TPS71523__SC70 +Regulator_Linear:TPS71525__SC70 +Regulator_Linear:TPS71530__SC70 +Regulator_Linear:TPS71533__SC70 +Regulator_Linear:TPS715345__SC70 +Regulator_Linear:TPS71550__SC70 +Regulator_Linear:TPS72201 +Regulator_Linear:TPS72215 +Regulator_Linear:TPS72216 +Regulator_Linear:TPS72218 +Regulator_Linear:TPS72301DBV +Regulator_Linear:TPS72301DDC +Regulator_Linear:TPS72325DBV +Regulator_Linear:TPS73018DBV +Regulator_Linear:TPS730285DBV +Regulator_Linear:TPS73101DBV +Regulator_Linear:TPS731125DBV +Regulator_Linear:TPS73115DBV +Regulator_Linear:TPS73118DBV +Regulator_Linear:TPS73125DBV +Regulator_Linear:TPS73130DBV +Regulator_Linear:TPS73131DBV +Regulator_Linear:TPS73132DBV +Regulator_Linear:TPS73133DBV +Regulator_Linear:TPS73150DBV +Regulator_Linear:TPS73601DBV +Regulator_Linear:TPS736125DBV +Regulator_Linear:TPS73615DBV +Regulator_Linear:TPS73616DBV +Regulator_Linear:TPS73618DBV +Regulator_Linear:TPS73619DBV +Regulator_Linear:TPS73625DBV +Regulator_Linear:TPS73630DBV +Regulator_Linear:TPS73632DBV +Regulator_Linear:TPS73633DBV +Regulator_Linear:TPS73643DBV +Regulator_Linear:TPS74401_VQFN +Regulator_Linear:TPS74801AWDRC +Regulator_Linear:TPS74801DRC +Regulator_Linear:TPS75005RGW +Regulator_Linear:TPS76301 +Regulator_Linear:TPS76316 +Regulator_Linear:TPS76318 +Regulator_Linear:TPS76325 +Regulator_Linear:TPS76327 +Regulator_Linear:TPS76329 +Regulator_Linear:TPS76330 +Regulator_Linear:TPS76333 +Regulator_Linear:TPS76338 +Regulator_Linear:TPS76350 +Regulator_Linear:TPS76901 +Regulator_Linear:TPS76912 +Regulator_Linear:TPS76915 +Regulator_Linear:TPS76918 +Regulator_Linear:TPS76925 +Regulator_Linear:TPS76927 +Regulator_Linear:TPS76928 +Regulator_Linear:TPS76930 +Regulator_Linear:TPS76933 +Regulator_Linear:TPS76950 +Regulator_Linear:TPS77701_HTSSOP20 +Regulator_Linear:TPS77701_SO8 +Regulator_Linear:TPS77715_HTSSOP20 +Regulator_Linear:TPS77715_SO8 +Regulator_Linear:TPS77718_HTSSOP20 +Regulator_Linear:TPS77718_SO8 +Regulator_Linear:TPS77725_HTSSOP20 +Regulator_Linear:TPS77725_SO8 +Regulator_Linear:TPS77733_HTSSOP20 +Regulator_Linear:TPS77733_SO8 +Regulator_Linear:TPS77801_HTSSOP20 +Regulator_Linear:TPS77801_SO8 +Regulator_Linear:TPS77815_HTSSOP20 +Regulator_Linear:TPS77815_SO8 +Regulator_Linear:TPS77818_HTSSOP20 +Regulator_Linear:TPS77818_SO8 +Regulator_Linear:TPS77825_HTSSOP20 +Regulator_Linear:TPS77825_SO8 +Regulator_Linear:TPS77833_HTSSOP20 +Regulator_Linear:TPS77833_SO8 +Regulator_Linear:TPS78218DDC +Regulator_Linear:TPS78223DDC +Regulator_Linear:TPS78225DDC +Regulator_Linear:TPS78227DDC +Regulator_Linear:TPS78228DDC +Regulator_Linear:TPS78230DDC +Regulator_Linear:TPS78233DDC +Regulator_Linear:TPS78236DDC +Regulator_Linear:TPS79301-EP +Regulator_Linear:TPS79318-EP +Regulator_Linear:TPS79325-EP +Regulator_Linear:TPS79328-EP +Regulator_Linear:TPS793285-EP +Regulator_Linear:TPS79330-EP +Regulator_Linear:TPS79333-EP +Regulator_Linear:TPS793475-EP +Regulator_Linear:TPS7A0508PDBV +Regulator_Linear:TPS7A0508PDBZ +Regulator_Linear:TPS7A0510PDBV +Regulator_Linear:TPS7A0512PDBV +Regulator_Linear:TPS7A0512PDBZ +Regulator_Linear:TPS7A0515PDBV +Regulator_Linear:TPS7A0518PDBV +Regulator_Linear:TPS7A0518PDBZ +Regulator_Linear:TPS7A0520PDBZ +Regulator_Linear:TPS7A0522PDBV +Regulator_Linear:TPS7A0522PDBZ +Regulator_Linear:TPS7A0525PDBV +Regulator_Linear:TPS7A0527PDBZ +Regulator_Linear:TPS7A05285PDBV +Regulator_Linear:TPS7A0528PDBZ +Regulator_Linear:TPS7A0530PDBV +Regulator_Linear:TPS7A0530PDBZ +Regulator_Linear:TPS7A0531PDBV +Regulator_Linear:TPS7A0533PDBV +Regulator_Linear:TPS7A0533PDBZ +Regulator_Linear:TPS7A20xxxDQN +Regulator_Linear:TPS7A3301RGW +Regulator_Linear:TPS7A39 +Regulator_Linear:TPS7A4101DGN +Regulator_Linear:TPS7A4701xRGW +Regulator_Linear:TPS7A7001DDA +Regulator_Linear:TPS7A7200RGW +Regulator_Linear:TPS7A90 +Regulator_Linear:TPS7A91 +Regulator_Linear:UA78M05QDCYRQ1 +Regulator_Linear:UA78M08QDCYRQ1 +Regulator_Linear:UA78M10QDCYRQ1 +Regulator_Linear:UA78M33QDCYRQ1 +Regulator_Linear:XC6206PxxxMR +Regulator_Linear:XC6210B332MR +Regulator_Linear:XC6220B331MR +Regulator_Linear:uA7805 +Regulator_Linear:uA7808 +Regulator_Linear:uA7810 +Regulator_Linear:uA7812 +Regulator_Linear:uA7815 +Regulator_Linear:uA7824 +Regulator_SwitchedCapacitor:CAT3200 +Regulator_SwitchedCapacitor:CAT3200-5 +Regulator_SwitchedCapacitor:ICL7660 +Regulator_SwitchedCapacitor:LM2665M6 +Regulator_SwitchedCapacitor:LM2775DSG +Regulator_SwitchedCapacitor:LM2776 +Regulator_SwitchedCapacitor:LM27761 +Regulator_SwitchedCapacitor:LM27762 +Regulator_SwitchedCapacitor:LM7705 +Regulator_SwitchedCapacitor:LMC7660 +Regulator_SwitchedCapacitor:LT1054 +Regulator_SwitchedCapacitor:LT1054L +Regulator_SwitchedCapacitor:LT1054xSW +Regulator_SwitchedCapacitor:LTC1044 +Regulator_SwitchedCapacitor:LTC1502xMS8-3.3 +Regulator_SwitchedCapacitor:LTC1502xS8-3.3 +Regulator_SwitchedCapacitor:LTC1503CMS8-1.8 +Regulator_SwitchedCapacitor:LTC1503CMS8-2 +Regulator_SwitchedCapacitor:LTC1503xS8-1.8 +Regulator_SwitchedCapacitor:LTC1503xS8-2 +Regulator_SwitchedCapacitor:LTC1751 +Regulator_SwitchedCapacitor:LTC1754 +Regulator_SwitchedCapacitor:LTC3260xDE +Regulator_SwitchedCapacitor:LTC3260xMSE +Regulator_SwitchedCapacitor:LTC660 +Regulator_SwitchedCapacitor:MAX1044 +Regulator_SwitchedCapacitor:RT9361AxE +Regulator_SwitchedCapacitor:RT9361BxE +Regulator_SwitchedCapacitor:TPS60151DRV +Regulator_SwitchedCapacitor:TPS60400DBV +Regulator_SwitchedCapacitor:TPS60401DBV +Regulator_SwitchedCapacitor:TPS60402DBV +Regulator_SwitchedCapacitor:TPS60403DBV +Regulator_SwitchedCapacitor:TPS60500DGS +Regulator_SwitchedCapacitor:TPS60501DGS +Regulator_SwitchedCapacitor:TPS60502DGS +Regulator_SwitchedCapacitor:TPS60503DGS +Regulator_Switching:171050601 +Regulator_Switching:A4403GEU +Regulator_Switching:AAT1217ICA-1.2 +Regulator_Switching:AAT1217ICA-3.3 +Regulator_Switching:AAT1217ICA-5.0 +Regulator_Switching:AAT1217IGU-3.3 +Regulator_Switching:ADP1108AN +Regulator_Switching:ADP1108AN-12 +Regulator_Switching:ADP1108AN-3.3 +Regulator_Switching:ADP1108AN-5 +Regulator_Switching:ADP1108AR +Regulator_Switching:ADP1108AR-12 +Regulator_Switching:ADP1108AR-3.3 +Regulator_Switching:ADP1108AR-5 +Regulator_Switching:ADP2108AUJ-1.0 +Regulator_Switching:ADP2108AUJ-1.1 +Regulator_Switching:ADP2108AUJ-1.2 +Regulator_Switching:ADP2108AUJ-1.3 +Regulator_Switching:ADP2108AUJ-1.5 +Regulator_Switching:ADP2108AUJ-1.8 +Regulator_Switching:ADP2108AUJ-1.82 +Regulator_Switching:ADP2108AUJ-2.3 +Regulator_Switching:ADP2108AUJ-2.5 +Regulator_Switching:ADP2108AUJ-3.0 +Regulator_Switching:ADP2108AUJ-3.3 +Regulator_Switching:ADP2302ARDZ +Regulator_Switching:ADP2302ARDZ-2.5 +Regulator_Switching:ADP2302ARDZ-3.3 +Regulator_Switching:ADP2302ARDZ-5.0 +Regulator_Switching:ADP2303ARDZ +Regulator_Switching:ADP2303ARDZ-2.5 +Regulator_Switching:ADP2303ARDZ-3.3 +Regulator_Switching:ADP2303ARDZ-5.0 +Regulator_Switching:ADP2360xCP +Regulator_Switching:ADP2360xCP-3.3 +Regulator_Switching:ADP2360xCP-5.0 +Regulator_Switching:ADP5054 +Regulator_Switching:ADP5070AREZ +Regulator_Switching:ADP5071AREZ +Regulator_Switching:ADuM6000 +Regulator_Switching:AOZ1280CI +Regulator_Switching:AOZ1282CI +Regulator_Switching:AOZ1282CI-1 +Regulator_Switching:AOZ6663DI +Regulator_Switching:AOZ6663DI-01 +Regulator_Switching:AP3012 +Regulator_Switching:AP3211K +Regulator_Switching:AP3402 +Regulator_Switching:AP3441SHE +Regulator_Switching:AP62150WU +Regulator_Switching:AP62150Z6 +Regulator_Switching:AP62250WU +Regulator_Switching:AP62250Z6 +Regulator_Switching:AP62300TWU +Regulator_Switching:AP62300WU +Regulator_Switching:AP62300Z6 +Regulator_Switching:AP62301WU +Regulator_Switching:AP63200WU +Regulator_Switching:AP63201WU +Regulator_Switching:AP63203WU +Regulator_Switching:AP63205WU +Regulator_Switching:AP6502 +Regulator_Switching:AP6503 +Regulator_Switching:AP65111AWU +Regulator_Switching:APE1707H-12-HF +Regulator_Switching:APE1707H-33-HF +Regulator_Switching:APE1707H-50-HF +Regulator_Switching:APE1707H-HF +Regulator_Switching:APE1707M-12-HF +Regulator_Switching:APE1707M-33-HF +Regulator_Switching:APE1707M-50-HF +Regulator_Switching:APE1707M-HF +Regulator_Switching:APE1707S-12-HF +Regulator_Switching:APE1707S-33-HF +Regulator_Switching:APE1707S-50-HF +Regulator_Switching:APE1707S-HF +Regulator_Switching:BD9001F +Regulator_Switching:BD9778F +Regulator_Switching:BD9778HFP +Regulator_Switching:BD9781HFP +Regulator_Switching:BD9G341EFJ +Regulator_Switching:CRE1S0305S3C +Regulator_Switching:CRE1S0505DC +Regulator_Switching:CRE1S0505S3C +Regulator_Switching:CRE1S0505SC +Regulator_Switching:CRE1S0515SC +Regulator_Switching:CRE1S1205SC +Regulator_Switching:CRE1S1212SC +Regulator_Switching:CRE1S2405SC +Regulator_Switching:CRE1S2412SC +Regulator_Switching:DIO6970 +Regulator_Switching:FSBH0170 +Regulator_Switching:FSBH0170A +Regulator_Switching:FSBH0170W +Regulator_Switching:FSBH0270 +Regulator_Switching:FSBH0270A +Regulator_Switching:FSBH0270W +Regulator_Switching:FSBH0370 +Regulator_Switching:FSBH0F70A +Regulator_Switching:FSBH0F70WA +Regulator_Switching:FSDH321 +Regulator_Switching:FSDH321L +Regulator_Switching:FSDL321 +Regulator_Switching:FSDL321L +Regulator_Switching:FSL136MRT +Regulator_Switching:FSQ0565RQLDTU +Regulator_Switching:FSQ0565RQWDTU +Regulator_Switching:FSQ0565RSLDTU +Regulator_Switching:FSQ0565RSWDTU +Regulator_Switching:GL2576-12SF8DR +Regulator_Switching:GL2576-12TA5R +Regulator_Switching:GL2576-12TB5T +Regulator_Switching:GL2576-15SF8DR +Regulator_Switching:GL2576-15TA5R +Regulator_Switching:GL2576-15TB5T +Regulator_Switching:GL2576-3.3SF8DR +Regulator_Switching:GL2576-3.3TA5R +Regulator_Switching:GL2576-3.3TB5T +Regulator_Switching:GL2576-5.0SF8DR +Regulator_Switching:GL2576-5.0TA5R +Regulator_Switching:GL2576-5.0TB5T +Regulator_Switching:GL2576-ASF8DR +Regulator_Switching:GL2576-ATA5R +Regulator_Switching:GL2576-ATB5T +Regulator_Switching:HT7463A +Regulator_Switching:HT7463B +Regulator_Switching:ISL8117FRZ +Regulator_Switching:ISL8117FVEZ +Regulator_Switching:KA5H02659RN +Regulator_Switching:KA5H0265RCTU +Regulator_Switching:KA5H0265RCYDTU +Regulator_Switching:KA5H0280RTU +Regulator_Switching:KA5H0280RYDTU +Regulator_Switching:KA5L0265RTU +Regulator_Switching:KA5L0265RYDTU +Regulator_Switching:KA5M02659RN +Regulator_Switching:KA5M0265RTU +Regulator_Switching:KA5M0265RYDTU +Regulator_Switching:KA5M0280RTU +Regulator_Switching:KA5M0280RYDTU +Regulator_Switching:L4962-A +Regulator_Switching:L4962E-A +Regulator_Switching:L4962EH-A +Regulator_Switching:L5973D +Regulator_Switching:L7980A +Regulator_Switching:LD7575 +Regulator_Switching:LGS5116B +Regulator_Switching:LGS5145 +Regulator_Switching:LGS6302B5 +Regulator_Switching:LM22676MR-5 +Regulator_Switching:LM22676MR-ADJ +Regulator_Switching:LM22678TJ-5 +Regulator_Switching:LM22678TJ-ADJ +Regulator_Switching:LM25085MM +Regulator_Switching:LM25085MY +Regulator_Switching:LM25085SD +Regulator_Switching:LM2574HVM-12 +Regulator_Switching:LM2574HVM-15 +Regulator_Switching:LM2574HVM-3.3 +Regulator_Switching:LM2574HVM-5 +Regulator_Switching:LM2574HVM-ADJ +Regulator_Switching:LM2574HVN-12 +Regulator_Switching:LM2574HVN-15 +Regulator_Switching:LM2574HVN-3.3 +Regulator_Switching:LM2574HVN-5 +Regulator_Switching:LM2574HVN-ADJ +Regulator_Switching:LM2574M-12 +Regulator_Switching:LM2574M-15 +Regulator_Switching:LM2574M-3.3 +Regulator_Switching:LM2574M-5 +Regulator_Switching:LM2574M-ADJ +Regulator_Switching:LM2574N-12 +Regulator_Switching:LM2574N-15 +Regulator_Switching:LM2574N-3.3 +Regulator_Switching:LM2574N-5 +Regulator_Switching:LM2574N-ADJ +Regulator_Switching:LM2575-12BT +Regulator_Switching:LM2575-12BU +Regulator_Switching:LM2575-3.3BT +Regulator_Switching:LM2575-3.3BU +Regulator_Switching:LM2575-5.0BT +Regulator_Switching:LM2575-5.0BU +Regulator_Switching:LM2575BT-ADJ +Regulator_Switching:LM2575BU-ADJ +Regulator_Switching:LM2576HVS-12 +Regulator_Switching:LM2576HVS-15 +Regulator_Switching:LM2576HVS-3.3 +Regulator_Switching:LM2576HVS-5 +Regulator_Switching:LM2576HVS-ADJ +Regulator_Switching:LM2576HVT-12 +Regulator_Switching:LM2576HVT-15 +Regulator_Switching:LM2576HVT-3.3 +Regulator_Switching:LM2576HVT-5 +Regulator_Switching:LM2576HVT-ADJ +Regulator_Switching:LM2576S-12 +Regulator_Switching:LM2576S-15 +Regulator_Switching:LM2576S-3.3 +Regulator_Switching:LM2576S-5 +Regulator_Switching:LM2576S-ADJ +Regulator_Switching:LM2576T-12 +Regulator_Switching:LM2576T-15 +Regulator_Switching:LM2576T-3.3 +Regulator_Switching:LM2576T-5 +Regulator_Switching:LM2576T-ADJ +Regulator_Switching:LM2578 +Regulator_Switching:LM2594HVM-12 +Regulator_Switching:LM2594HVM-3.3 +Regulator_Switching:LM2594HVM-5.0 +Regulator_Switching:LM2594HVM-ADJ +Regulator_Switching:LM2594HVN-12 +Regulator_Switching:LM2594HVN-3.3 +Regulator_Switching:LM2594HVN-5.0 +Regulator_Switching:LM2594HVN-ADJ +Regulator_Switching:LM2594M-12 +Regulator_Switching:LM2594M-3.3 +Regulator_Switching:LM2594M-5.0 +Regulator_Switching:LM2594M-ADJ +Regulator_Switching:LM2594N-12 +Regulator_Switching:LM2594N-3.3 +Regulator_Switching:LM2594N-5.0 +Regulator_Switching:LM2594N-ADJ +Regulator_Switching:LM2595S-12 +Regulator_Switching:LM2595S-3.3 +Regulator_Switching:LM2595S-5 +Regulator_Switching:LM2595S-ADJ +Regulator_Switching:LM2595T-12 +Regulator_Switching:LM2595T-3.3 +Regulator_Switching:LM2595T-5 +Regulator_Switching:LM2595T-ADJ +Regulator_Switching:LM2596S-12 +Regulator_Switching:LM2596S-3.3 +Regulator_Switching:LM2596S-5 +Regulator_Switching:LM2596S-ADJ +Regulator_Switching:LM2596T-12 +Regulator_Switching:LM2596T-3.3 +Regulator_Switching:LM2596T-5 +Regulator_Switching:LM2596T-ADJ +Regulator_Switching:LM2611xMF +Regulator_Switching:LM26480SQ +Regulator_Switching:LM2672M-12 +Regulator_Switching:LM2672M-3.3 +Regulator_Switching:LM2672M-5.0 +Regulator_Switching:LM2672M-ADJ +Regulator_Switching:LM2672N-12 +Regulator_Switching:LM2672N-3.3 +Regulator_Switching:LM2672N-5.0 +Regulator_Switching:LM2672N-ADJ +Regulator_Switching:LM2674M-12 +Regulator_Switching:LM2674M-3.3 +Regulator_Switching:LM2674M-5.0 +Regulator_Switching:LM2674M-ADJ +Regulator_Switching:LM2674N-12 +Regulator_Switching:LM2674N-3.3 +Regulator_Switching:LM2674N-5.0 +Regulator_Switching:LM2674N-ADJ +Regulator_Switching:LM2675M-12 +Regulator_Switching:LM2675M-3.3 +Regulator_Switching:LM2675M-5 +Regulator_Switching:LM2675M-ADJ +Regulator_Switching:LM2675N-12 +Regulator_Switching:LM2675N-3.3 +Regulator_Switching:LM2675N-5 +Regulator_Switching:LM2675N-ADJ +Regulator_Switching:LM27313XMF +Regulator_Switching:LM2731XMF +Regulator_Switching:LM2731YMF +Regulator_Switching:LM2733XMF +Regulator_Switching:LM2733YMF +Regulator_Switching:LM2734X +Regulator_Switching:LM2734Y +Regulator_Switching:LM2735XMF +Regulator_Switching:LM2840X +Regulator_Switching:LM2840Y +Regulator_Switching:LM2841X +Regulator_Switching:LM2841Y +Regulator_Switching:LM2842X +Regulator_Switching:LM2842Y +Regulator_Switching:LM3150MH +Regulator_Switching:LM3407MY +Regulator_Switching:LM3578 +Regulator_Switching:LM3670MF +Regulator_Switching:LM5001MA +Regulator_Switching:LM5006MM +Regulator_Switching:LM5007MM +Regulator_Switching:LM5007SD +Regulator_Switching:LM5008MM +Regulator_Switching:LM5008SD +Regulator_Switching:LM5009MM +Regulator_Switching:LM5009SD +Regulator_Switching:LM5017MR +Regulator_Switching:LM5017SD +Regulator_Switching:LM5022MM +Regulator_Switching:LM5088-1 +Regulator_Switching:LM5088-2 +Regulator_Switching:LM5118MH +Regulator_Switching:LM5161PWP +Regulator_Switching:LM5164DDA +Regulator_Switching:LM5165 +Regulator_Switching:LM5165X +Regulator_Switching:LM5165Y +Regulator_Switching:LM5166 +Regulator_Switching:LM5166X +Regulator_Switching:LM5166Y +Regulator_Switching:LM5175PWP +Regulator_Switching:LM5175RHF +Regulator_Switching:LM5176PWP +Regulator_Switching:LM5176RHF +Regulator_Switching:LMR10510XMF +Regulator_Switching:LMR10510YMF +Regulator_Switching:LMR10510YSD +Regulator_Switching:LMR14206 +Regulator_Switching:LMR16006YQ +Regulator_Switching:LMR16006YQ3 +Regulator_Switching:LMR16006YQ5 +Regulator_Switching:LMR33610ADDAR +Regulator_Switching:LMR33610BDDAR +Regulator_Switching:LMR33620ADDA +Regulator_Switching:LMR33620BDDA +Regulator_Switching:LMR33620CDDA +Regulator_Switching:LMR33630ADDA +Regulator_Switching:LMR33630BDDA +Regulator_Switching:LMR33630CDDA +Regulator_Switching:LMR33640ADDA +Regulator_Switching:LMR33640DDDA +Regulator_Switching:LMR36510ADDA +Regulator_Switching:LMR50410 +Regulator_Switching:LMR51430 +Regulator_Switching:LMR62014XMF +Regulator_Switching:LMR62421XMF +Regulator_Switching:LMR62421XSD +Regulator_Switching:LMR64010XMF +Regulator_Switching:LMZ13608 +Regulator_Switching:LMZ22003TZ +Regulator_Switching:LMZ22005TZ +Regulator_Switching:LMZ23603TZ +Regulator_Switching:LMZ23605TZ +Regulator_Switching:LMZM23600 +Regulator_Switching:LMZM23600V3 +Regulator_Switching:LMZM23600V5 +Regulator_Switching:LMZM23601 +Regulator_Switching:LMZM23601V3 +Regulator_Switching:LMZM23601V5 +Regulator_Switching:LNK302D +Regulator_Switching:LNK302G +Regulator_Switching:LNK302P +Regulator_Switching:LNK304D +Regulator_Switching:LNK304G +Regulator_Switching:LNK304P +Regulator_Switching:LNK305D +Regulator_Switching:LNK305G +Regulator_Switching:LNK305P +Regulator_Switching:LNK306D +Regulator_Switching:LNK306G +Regulator_Switching:LNK306P +Regulator_Switching:LNK3202D +Regulator_Switching:LNK3202G +Regulator_Switching:LNK3202P +Regulator_Switching:LNK3204D +Regulator_Switching:LNK3204G +Regulator_Switching:LNK3204P +Regulator_Switching:LNK3205D +Regulator_Switching:LNK3205G +Regulator_Switching:LNK3205P +Regulator_Switching:LNK3206D +Regulator_Switching:LNK3206G +Regulator_Switching:LNK3206P +Regulator_Switching:LNK362D +Regulator_Switching:LNK362G +Regulator_Switching:LNK362P +Regulator_Switching:LNK363D +Regulator_Switching:LNK363G +Regulator_Switching:LNK363P +Regulator_Switching:LNK364D +Regulator_Switching:LNK364G +Regulator_Switching:LNK364P +Regulator_Switching:LNK403EG +Regulator_Switching:LNK403LG +Regulator_Switching:LNK404EG +Regulator_Switching:LNK404LG +Regulator_Switching:LNK405EG +Regulator_Switching:LNK405LG +Regulator_Switching:LNK406EG +Regulator_Switching:LNK406LG +Regulator_Switching:LNK407EG +Regulator_Switching:LNK407LG +Regulator_Switching:LNK408EG +Regulator_Switching:LNK408LG +Regulator_Switching:LNK409EG +Regulator_Switching:LNK409LG +Regulator_Switching:LNK410EG +Regulator_Switching:LNK410LG +Regulator_Switching:LNK413EG +Regulator_Switching:LNK413LG +Regulator_Switching:LNK414EG +Regulator_Switching:LNK414LG +Regulator_Switching:LNK415EG +Regulator_Switching:LNK415LG +Regulator_Switching:LNK416EG +Regulator_Switching:LNK416LG +Regulator_Switching:LNK417EG +Regulator_Switching:LNK417LG +Regulator_Switching:LNK418EG +Regulator_Switching:LNK418LG +Regulator_Switching:LNK419EG +Regulator_Switching:LNK419LG +Regulator_Switching:LNK420EG +Regulator_Switching:LNK420LG +Regulator_Switching:LNK454D +Regulator_Switching:LNK456D +Regulator_Switching:LNK457D +Regulator_Switching:LNK457K +Regulator_Switching:LNK457V +Regulator_Switching:LNK458K +Regulator_Switching:LNK458V +Regulator_Switching:LNK460K +Regulator_Switching:LNK460V +Regulator_Switching:LNK562D +Regulator_Switching:LNK562G +Regulator_Switching:LNK562P +Regulator_Switching:LNK563D +Regulator_Switching:LNK563G +Regulator_Switching:LNK563P +Regulator_Switching:LNK564D +Regulator_Switching:LNK564G +Regulator_Switching:LNK564P +Regulator_Switching:LNK603DG +Regulator_Switching:LNK603PG +Regulator_Switching:LNK604DG +Regulator_Switching:LNK604PG +Regulator_Switching:LNK605DG +Regulator_Switching:LNK605PG +Regulator_Switching:LNK606DG +Regulator_Switching:LNK606GG +Regulator_Switching:LNK606PG +Regulator_Switching:LNK613DG +Regulator_Switching:LNK613PG +Regulator_Switching:LNK614DG +Regulator_Switching:LNK614PG +Regulator_Switching:LNK615DG +Regulator_Switching:LNK615PG +Regulator_Switching:LNK616DG +Regulator_Switching:LNK616GG +Regulator_Switching:LNK616PG +Regulator_Switching:LNK623DG +Regulator_Switching:LNK623PG +Regulator_Switching:LNK624DG +Regulator_Switching:LNK624PG +Regulator_Switching:LNK625DG +Regulator_Switching:LNK625PG +Regulator_Switching:LNK626DG +Regulator_Switching:LNK626PG +Regulator_Switching:LNK632DG +Regulator_Switching:LT1073CN +Regulator_Switching:LT1073CN-12 +Regulator_Switching:LT1073CN-5 +Regulator_Switching:LT1073CS +Regulator_Switching:LT1073CS-12 +Regulator_Switching:LT1073CS-5 +Regulator_Switching:LT1108CN +Regulator_Switching:LT1108CN-12 +Regulator_Switching:LT1108CN-5 +Regulator_Switching:LT1108CS +Regulator_Switching:LT1108CS-12 +Regulator_Switching:LT1108CS-5 +Regulator_Switching:LT1301 +Regulator_Switching:LT1307BCMS8 +Regulator_Switching:LT1307BCS8 +Regulator_Switching:LT1307CMS8 +Regulator_Switching:LT1307CN8 +Regulator_Switching:LT1307CS8 +Regulator_Switching:LT1372CN8 +Regulator_Switching:LT1372CS8 +Regulator_Switching:LT1372HVCN8 +Regulator_Switching:LT1372HVCS8 +Regulator_Switching:LT1373CN8 +Regulator_Switching:LT1373CS8 +Regulator_Switching:LT1373HVCN8 +Regulator_Switching:LT1373HVCS8 +Regulator_Switching:LT1377CN8 +Regulator_Switching:LT1377CS8 +Regulator_Switching:LT1945 +Regulator_Switching:LT3430 +Regulator_Switching:LT3430-1 +Regulator_Switching:LT3439 +Regulator_Switching:LT3471 +Regulator_Switching:LT3472 +Regulator_Switching:LT3483AxS6 +Regulator_Switching:LT3483xS6 +Regulator_Switching:LT3514xUFD +Regulator_Switching:LT3580xDD +Regulator_Switching:LT3580xMS8E +Regulator_Switching:LT3748xMS +Regulator_Switching:LT3757AEDD +Regulator_Switching:LT3757AEMSE +Regulator_Switching:LT3757EDD +Regulator_Switching:LT3757EMSE +Regulator_Switching:LT3988 +Regulator_Switching:LT8303 +Regulator_Switching:LT8306 +Regulator_Switching:LT8610 +Regulator_Switching:LT8610AC +Regulator_Switching:LT8610AC-1 +Regulator_Switching:LT8705AxFE +Regulator_Switching:LTC1436A +Regulator_Switching:LTC1436A-PLL +Regulator_Switching:LTC1437A +Regulator_Switching:LTC1878EMS8 +Regulator_Switching:LTC3105xDD +Regulator_Switching:LTC3105xMS +Regulator_Switching:LTC3245xDE +Regulator_Switching:LTC3245xMSE +Regulator_Switching:LTC3406AES5 +Regulator_Switching:LTC3406B-2ES5 +Regulator_Switching:LTC3406BES5-1.2 +Regulator_Switching:LTC3406ES5 +Regulator_Switching:LTC3406ES5-1.2 +Regulator_Switching:LTC3406ES5-1.5 +Regulator_Switching:LTC3406ES5-1.8 +Regulator_Switching:LTC3429 +Regulator_Switching:LTC3429B +Regulator_Switching:LTC3442 +Regulator_Switching:LTC3525 +Regulator_Switching:LTC3525-3 +Regulator_Switching:LTC3525-3.3 +Regulator_Switching:LTC3525-5 +Regulator_Switching:LTC3525D-3.3 +Regulator_Switching:LTC3525L-3 +Regulator_Switching:LTC3561EDD +Regulator_Switching:LTC3630AxDHC +Regulator_Switching:LTC3630AxMSE +Regulator_Switching:LTC3630xDHC +Regulator_Switching:LTC3630xMSE +Regulator_Switching:LTC3638xMSE +Regulator_Switching:LTC3639xMSE +Regulator_Switching:LTC3886 +Regulator_Switching:LTC7138xMSE +Regulator_Switching:LTM4626 +Regulator_Switching:LTM4637xV +Regulator_Switching:LTM4637xY +Regulator_Switching:LTM4638 +Regulator_Switching:LTM4657 +Regulator_Switching:LTM4668 +Regulator_Switching:LTM4668A +Regulator_Switching:LTM4671 +Regulator_Switching:LTM8049 +Regulator_Switching:LTM8063 +Regulator_Switching:LV2862XDDC +Regulator_Switching:LV2862YDDC +Regulator_Switching:MAX15062A +Regulator_Switching:MAX15062B +Regulator_Switching:MAX15062C +Regulator_Switching:MAX1522 +Regulator_Switching:MAX1523 +Regulator_Switching:MAX1524 +Regulator_Switching:MAX17501AxTB +Regulator_Switching:MAX17501BxTB +Regulator_Switching:MAX17501ExTB +Regulator_Switching:MAX17501FxTB +Regulator_Switching:MAX17501GxTB +Regulator_Switching:MAX17501HxTB +Regulator_Switching:MAX17572 +Regulator_Switching:MAX17574 +Regulator_Switching:MAX17620ATA +Regulator_Switching:MAX1771xSA +Regulator_Switching:MAX5035AUPA +Regulator_Switching:MAX5035AUSA +Regulator_Switching:MAX5035BUPA +Regulator_Switching:MAX5035BUSA +Regulator_Switching:MAX5035CUPA +Regulator_Switching:MAX5035CUSA +Regulator_Switching:MAX5035DUPA +Regulator_Switching:MAX5035DUSA +Regulator_Switching:MAX5035EUSA +Regulator_Switching:MAX777L +Regulator_Switching:MAX77827AEFD +Regulator_Switching:MAX778L +Regulator_Switching:MAX779L +Regulator_Switching:MC33063AD +Regulator_Switching:MC33063AP +Regulator_Switching:MC33063MNTXG +Regulator_Switching:MC34063AD +Regulator_Switching:MC34063AP +Regulator_Switching:MCP1623x-xCHY +Regulator_Switching:MCP1623x-xMC +Regulator_Switching:MCP16301Hx-xCH +Regulator_Switching:MCP16301x-xCH +Regulator_Switching:MCP16311x-xMNY +Regulator_Switching:MCP16311x-xMS +Regulator_Switching:MCP16312x-xMNY +Regulator_Switching:MCP16312x-xMS +Regulator_Switching:MCP16331x-xCH +Regulator_Switching:MCP16331x-xMNY +Regulator_Switching:MCP1640Bx-xCHY +Regulator_Switching:MCP1640Bx-xMC +Regulator_Switching:MCP1640Cx-xCHY +Regulator_Switching:MCP1640Cx-xMC +Regulator_Switching:MCP1640Dx-xCHY +Regulator_Switching:MCP1640Dx-xMC +Regulator_Switching:MCP1640x-xCHY +Regulator_Switching:MCP1640x-xMC +Regulator_Switching:MCP1650x-xMC +Regulator_Switching:MCP1651x-xMC +Regulator_Switching:MCP1652x-xMC +Regulator_Switching:MCP1653x-xUN +Regulator_Switching:MIC2177 +Regulator_Switching:MIC2177-3.3 +Regulator_Switching:MIC2177-5.0 +Regulator_Switching:MIC2178 +Regulator_Switching:MIC2178-3.3 +Regulator_Switching:MIC2178-5.0 +Regulator_Switching:MIC2207 +Regulator_Switching:MIC2253 +Regulator_Switching:MIC2290 +Regulator_Switching:MIC23050-4YML +Regulator_Switching:MIC23050-CYML +Regulator_Switching:MIC23050-GYML +Regulator_Switching:MIC23050-SYML +Regulator_Switching:MIC4684 +Regulator_Switching:MIC4690 +Regulator_Switching:MP1470 +Regulator_Switching:MP171GJ +Regulator_Switching:MP171GS +Regulator_Switching:MP2303ADN +Regulator_Switching:MP2303ADP +Regulator_Switching:MPM3550EGLE +Regulator_Switching:MT3608 +Regulator_Switching:MUN12AD01-SH +Regulator_Switching:MUN12AD03-SH +Regulator_Switching:NBM5100A +Regulator_Switching:NBM7100A +Regulator_Switching:NCP1070P065 +Regulator_Switching:NCP1070P100 +Regulator_Switching:NCP1070P130 +Regulator_Switching:NCP1070STAT +Regulator_Switching:NCP1070STBT +Regulator_Switching:NCP1070STCT +Regulator_Switching:NCP1071P065 +Regulator_Switching:NCP1071P100 +Regulator_Switching:NCP1071P130 +Regulator_Switching:NCP1071STAT +Regulator_Switching:NCP1071STBT +Regulator_Switching:NCP1071STCT +Regulator_Switching:NCP1072P065 +Regulator_Switching:NCP1072P100 +Regulator_Switching:NCP1072P130 +Regulator_Switching:NCP1072STAT +Regulator_Switching:NCP1072STBT +Regulator_Switching:NCP1072STCT +Regulator_Switching:NCP1075P065 +Regulator_Switching:NCP1075P100 +Regulator_Switching:NCP1075P130 +Regulator_Switching:NCP1075STAT +Regulator_Switching:NCP1075STBT +Regulator_Switching:NCP1075STCT +Regulator_Switching:NCP1076P065 +Regulator_Switching:NCP1076P100 +Regulator_Switching:NCP1076P130 +Regulator_Switching:NCP1076STAT +Regulator_Switching:NCP1076STBT +Regulator_Switching:NCP1076STCT +Regulator_Switching:NCP1077P065 +Regulator_Switching:NCP1077P100 +Regulator_Switching:NCP1077P130 +Regulator_Switching:NCP1077STAT +Regulator_Switching:NCP1077STBT +Regulator_Switching:NCP1077STCT +Regulator_Switching:NCP1529A +Regulator_Switching:NCV33063AVD +Regulator_Switching:NID30S24-05 +Regulator_Switching:NID30S24-12 +Regulator_Switching:NID30S24-15 +Regulator_Switching:NID30S48-24 +Regulator_Switching:NID60S24-05 +Regulator_Switching:NID60S24-12 +Regulator_Switching:NID60S24-15 +Regulator_Switching:NID60S48-24 +Regulator_Switching:NMA0505DC +Regulator_Switching:NMA0505SC +Regulator_Switching:NMA0509DC +Regulator_Switching:NMA0509SC +Regulator_Switching:NMA0512DC +Regulator_Switching:NMA0512SC +Regulator_Switching:NMA0515DC +Regulator_Switching:NMA0515SC +Regulator_Switching:NMA1205DC +Regulator_Switching:NMA1205SC +Regulator_Switching:NMA1209DC +Regulator_Switching:NMA1209SC +Regulator_Switching:NMA1212DC +Regulator_Switching:NMA1212SC +Regulator_Switching:NMA1215DC +Regulator_Switching:NMA1215SC +Regulator_Switching:NMA1505DC +Regulator_Switching:NMA1505SC +Regulator_Switching:NMA1512DC +Regulator_Switching:NMA1512SC +Regulator_Switching:NMA1515DC +Regulator_Switching:NMA1515SC +Regulator_Switching:NXE1S0303MC +Regulator_Switching:NXE1S0305MC +Regulator_Switching:NXE1S0505MC +Regulator_Switching:NXE2S0505MC +Regulator_Switching:NXE2S1205MC +Regulator_Switching:NXE2S1212MC +Regulator_Switching:NXE2S1215MC +Regulator_Switching:PAM2301CAAB120 +Regulator_Switching:PAM2301CAAB330 +Regulator_Switching:PAM2301CAABADJ +Regulator_Switching:PAM2305AAB120 +Regulator_Switching:PAM2305AAB150 +Regulator_Switching:PAM2305AAB180 +Regulator_Switching:PAM2305AAB250 +Regulator_Switching:PAM2305AAB280 +Regulator_Switching:PAM2305AAB330 +Regulator_Switching:PAM2305AABADJ +Regulator_Switching:PAM2305BJE120 +Regulator_Switching:PAM2305BJE150 +Regulator_Switching:PAM2305BJE180 +Regulator_Switching:PAM2305BJE250 +Regulator_Switching:PAM2305BJE280 +Regulator_Switching:PAM2305BJE330 +Regulator_Switching:PAM2305BJEADJ +Regulator_Switching:PAM2305CGF120 +Regulator_Switching:PAM2305CGF150 +Regulator_Switching:PAM2305CGF180 +Regulator_Switching:PAM2305CGF250 +Regulator_Switching:PAM2305CGF280 +Regulator_Switching:PAM2305CGF330 +Regulator_Switching:PAM2305CGFADJ +Regulator_Switching:PAM2306AYPAA +Regulator_Switching:PAM2306AYPBB +Regulator_Switching:PAM2306AYPBK +Regulator_Switching:PAM2306AYPCB +Regulator_Switching:PAM2306AYPKB +Regulator_Switching:PAM2306AYPKE +Regulator_Switching:PAM2306DYPAA +Regulator_Switching:R-781.5-0.5 +Regulator_Switching:R-781.8-0.5 +Regulator_Switching:R-781.8-1.0 +Regulator_Switching:R-7812-0.5 +Regulator_Switching:R-7815-0.5 +Regulator_Switching:R-782.5-0.5 +Regulator_Switching:R-782.5-1.0 +Regulator_Switching:R-783.3-0.5 +Regulator_Switching:R-783.3-1.0 +Regulator_Switching:R-785.0-0.5 +Regulator_Switching:R-785.0-1.0 +Regulator_Switching:R-786.5-0.5 +Regulator_Switching:R-78B1.2-2.0 +Regulator_Switching:R-78B1.5-2.0 +Regulator_Switching:R-78B1.8-2.0 +Regulator_Switching:R-78B12-2.0 +Regulator_Switching:R-78B15-2.0 +Regulator_Switching:R-78B2.5-2.0 +Regulator_Switching:R-78B3.3-2.0 +Regulator_Switching:R-78B5.0-2.0 +Regulator_Switching:R-78B9.0-2.0 +Regulator_Switching:R-78C1.8-1.0 +Regulator_Switching:R-78C12-1.0 +Regulator_Switching:R-78C15-1.0 +Regulator_Switching:R-78C3.3-1.0 +Regulator_Switching:R-78C5.0-1.0 +Regulator_Switching:R-78C9.0-1.0 +Regulator_Switching:R-78E12-0.5 +Regulator_Switching:R-78E15-0.5 +Regulator_Switching:R-78E3.3-0.5 +Regulator_Switching:R-78E3.3-1.0 +Regulator_Switching:R-78E5.0-0.5 +Regulator_Switching:R-78E5.0-1.0 +Regulator_Switching:R-78E9.0-0.5 +Regulator_Switching:R-78HB12-0.5 +Regulator_Switching:R-78HB15-0.5 +Regulator_Switching:R-78HB24-0.3 +Regulator_Switching:R-78HB3.3-0.5 +Regulator_Switching:R-78HB5.0-0.5 +Regulator_Switching:R-78HB6.5-0.5 +Regulator_Switching:R-78HB9.0-0.5 +Regulator_Switching:R-78S3.3-0.1 +Regulator_Switching:SC33063AD +Regulator_Switching:SC34063AP +Regulator_Switching:SC4503TSK +Regulator_Switching:SIC431A +Regulator_Switching:SIC431B +Regulator_Switching:SIC431C +Regulator_Switching:SIC431D +Regulator_Switching:SIC437A +Regulator_Switching:SIC437B +Regulator_Switching:SIC437C +Regulator_Switching:SIC437D +Regulator_Switching:SIC438A +Regulator_Switching:SIC438B +Regulator_Switching:SIC438C +Regulator_Switching:SIC438D +Regulator_Switching:ST1S10PHR +Regulator_Switching:ST1S10PUR +Regulator_Switching:ST1S12XX +Regulator_Switching:ST1S14PHR +Regulator_Switching:TDN_5-0910WISM +Regulator_Switching:TDN_5-0911WISM +Regulator_Switching:TDN_5-0912WISM +Regulator_Switching:TDN_5-0913WISM +Regulator_Switching:TDN_5-0915WISM +Regulator_Switching:TDN_5-0919WISM +Regulator_Switching:TDN_5-2410WISM +Regulator_Switching:TDN_5-2411WISM +Regulator_Switching:TDN_5-2412WISM +Regulator_Switching:TDN_5-2413WISM +Regulator_Switching:TDN_5-2415WISM +Regulator_Switching:TDN_5-2419WISM +Regulator_Switching:TDN_5-4810WISM +Regulator_Switching:TDN_5-4811WISM +Regulator_Switching:TDN_5-4812WISM +Regulator_Switching:TDN_5-4813WISM +Regulator_Switching:TDN_5-4815WISM +Regulator_Switching:TDN_5-4819WISM +Regulator_Switching:TL497 +Regulator_Switching:TL497A +Regulator_Switching:TL5001 +Regulator_Switching:TL5001A +Regulator_Switching:TLV61046ADB +Regulator_Switching:TLV61070ADBV +Regulator_Switching:TLV61225DC +Regulator_Switching:TLV62080DSGx +Regulator_Switching:TLV62084ADSGx +Regulator_Switching:TLV62084DSGx +Regulator_Switching:TLV62095RGTx +Regulator_Switching:TLV62565DBVx +Regulator_Switching:TLV62566DBVx +Regulator_Switching:TLV62568ADRL +Regulator_Switching:TLV62568DBV +Regulator_Switching:TLV62568DDC +Regulator_Switching:TLV62568DRL +Regulator_Switching:TLV62569ADRL +Regulator_Switching:TLV62569DBV +Regulator_Switching:TLV62569DDC +Regulator_Switching:TLV62569DRL +Regulator_Switching:TMR_1-0511 +Regulator_Switching:TMR_1-0511SM +Regulator_Switching:TMR_1-0512 +Regulator_Switching:TMR_1-0512SM +Regulator_Switching:TMR_1-0513 +Regulator_Switching:TMR_1-0513SM +Regulator_Switching:TMR_1-0515 +Regulator_Switching:TMR_1-0522 +Regulator_Switching:TMR_1-0522SM +Regulator_Switching:TMR_1-0523 +Regulator_Switching:TMR_1-0523SM +Regulator_Switching:TMR_1-1211 +Regulator_Switching:TMR_1-1211SM +Regulator_Switching:TMR_1-1212 +Regulator_Switching:TMR_1-1212SM +Regulator_Switching:TMR_1-1213 +Regulator_Switching:TMR_1-1213SM +Regulator_Switching:TMR_1-1215 +Regulator_Switching:TMR_1-1222 +Regulator_Switching:TMR_1-1222SM +Regulator_Switching:TMR_1-1223 +Regulator_Switching:TMR_1-1223SM +Regulator_Switching:TMR_1-2411 +Regulator_Switching:TMR_1-2411SM +Regulator_Switching:TMR_1-2412 +Regulator_Switching:TMR_1-2412SM +Regulator_Switching:TMR_1-2413 +Regulator_Switching:TMR_1-2413SM +Regulator_Switching:TMR_1-2415 +Regulator_Switching:TMR_1-2422 +Regulator_Switching:TMR_1-2422SM +Regulator_Switching:TMR_1-2423 +Regulator_Switching:TMR_1-2423SM +Regulator_Switching:TMR_1-4811 +Regulator_Switching:TMR_1-4811SM +Regulator_Switching:TMR_1-4812 +Regulator_Switching:TMR_1-4812SM +Regulator_Switching:TMR_1-4813 +Regulator_Switching:TMR_1-4813SM +Regulator_Switching:TMR_1-4815 +Regulator_Switching:TMR_1-4822 +Regulator_Switching:TMR_1-4822SM +Regulator_Switching:TMR_1-4823 +Regulator_Switching:TMR_1-4823SM +Regulator_Switching:TNY263G +Regulator_Switching:TNY263P +Regulator_Switching:TNY264G +Regulator_Switching:TNY264P +Regulator_Switching:TNY265G +Regulator_Switching:TNY265P +Regulator_Switching:TNY266G +Regulator_Switching:TNY266P +Regulator_Switching:TNY267G +Regulator_Switching:TNY267P +Regulator_Switching:TNY268G +Regulator_Switching:TNY268P +Regulator_Switching:TNY274G +Regulator_Switching:TNY274P +Regulator_Switching:TNY275G +Regulator_Switching:TNY275P +Regulator_Switching:TNY276G +Regulator_Switching:TNY276P +Regulator_Switching:TNY277G +Regulator_Switching:TNY277P +Regulator_Switching:TNY278G +Regulator_Switching:TNY278P +Regulator_Switching:TNY279G +Regulator_Switching:TNY279P +Regulator_Switching:TNY280G +Regulator_Switching:TNY280P +Regulator_Switching:TNY284D +Regulator_Switching:TNY284K +Regulator_Switching:TNY284P +Regulator_Switching:TNY285D +Regulator_Switching:TNY285K +Regulator_Switching:TNY285P +Regulator_Switching:TNY286D +Regulator_Switching:TNY286K +Regulator_Switching:TNY286P +Regulator_Switching:TNY287D +Regulator_Switching:TNY287K +Regulator_Switching:TNY287P +Regulator_Switching:TNY288D +Regulator_Switching:TNY288K +Regulator_Switching:TNY288P +Regulator_Switching:TNY289K +Regulator_Switching:TNY289P +Regulator_Switching:TNY290K +Regulator_Switching:TNY290P +Regulator_Switching:TOP100YN +Regulator_Switching:TOP101YN +Regulator_Switching:TOP102YN +Regulator_Switching:TOP103YN +Regulator_Switching:TOP104YN +Regulator_Switching:TOP200YAI +Regulator_Switching:TOP201YAI +Regulator_Switching:TOP202YAI +Regulator_Switching:TOP203YAI +Regulator_Switching:TOP204YAI +Regulator_Switching:TOP209G +Regulator_Switching:TOP209P +Regulator_Switching:TOP210G +Regulator_Switching:TOP210PFI +Regulator_Switching:TOP214YAI +Regulator_Switching:TOP252EG +Regulator_Switching:TOP252EN +Regulator_Switching:TOP252GN +Regulator_Switching:TOP252MN +Regulator_Switching:TOP252PN +Regulator_Switching:TOP253EG +Regulator_Switching:TOP253EN +Regulator_Switching:TOP253GN +Regulator_Switching:TOP253MN +Regulator_Switching:TOP253PN +Regulator_Switching:TOP254EG +Regulator_Switching:TOP254EN +Regulator_Switching:TOP254GN +Regulator_Switching:TOP254MN +Regulator_Switching:TOP254PN +Regulator_Switching:TOP254YN +Regulator_Switching:TOP255EG +Regulator_Switching:TOP255EN +Regulator_Switching:TOP255GN +Regulator_Switching:TOP255LN +Regulator_Switching:TOP255MN +Regulator_Switching:TOP255PN +Regulator_Switching:TOP255YN +Regulator_Switching:TOP256EG +Regulator_Switching:TOP256EN +Regulator_Switching:TOP256GN +Regulator_Switching:TOP256LN +Regulator_Switching:TOP256MN +Regulator_Switching:TOP256PN +Regulator_Switching:TOP256YN +Regulator_Switching:TOP257EG +Regulator_Switching:TOP257EN +Regulator_Switching:TOP257GN +Regulator_Switching:TOP257LN +Regulator_Switching:TOP257MN +Regulator_Switching:TOP257PN +Regulator_Switching:TOP257YN +Regulator_Switching:TOP258EG +Regulator_Switching:TOP258EN +Regulator_Switching:TOP258GN +Regulator_Switching:TOP258LN +Regulator_Switching:TOP258MN +Regulator_Switching:TOP258PN +Regulator_Switching:TOP258YN +Regulator_Switching:TOP259EG +Regulator_Switching:TOP259EN +Regulator_Switching:TOP259LN +Regulator_Switching:TOP259YN +Regulator_Switching:TOP260EG +Regulator_Switching:TOP260EN +Regulator_Switching:TOP260LN +Regulator_Switching:TOP260YN +Regulator_Switching:TOP261EG +Regulator_Switching:TOP261EN +Regulator_Switching:TOP261LN +Regulator_Switching:TOP261YN +Regulator_Switching:TOP262EN +Regulator_Switching:TOP262LN +Regulator_Switching:TOP264EG +Regulator_Switching:TOP264KG +Regulator_Switching:TOP264VG +Regulator_Switching:TOP265EG +Regulator_Switching:TOP265KG +Regulator_Switching:TOP265VG +Regulator_Switching:TOP266EG +Regulator_Switching:TOP266KG +Regulator_Switching:TOP266VG +Regulator_Switching:TOP267EG +Regulator_Switching:TOP267KG +Regulator_Switching:TOP267VG +Regulator_Switching:TOP268EG +Regulator_Switching:TOP268KG +Regulator_Switching:TOP268VG +Regulator_Switching:TOP269EG +Regulator_Switching:TOP269KG +Regulator_Switching:TOP269VG +Regulator_Switching:TOP270EG +Regulator_Switching:TOP270KG +Regulator_Switching:TOP270VG +Regulator_Switching:TOP271EG +Regulator_Switching:TOP271KG +Regulator_Switching:TOP271VG +Regulator_Switching:TOS06-05SIL +Regulator_Switching:TOS06-12SIL +Regulator_Switching:TPS51363 +Regulator_Switching:TPS5403 +Regulator_Switching:TPS54061DRB +Regulator_Switching:TPS54202DDC +Regulator_Switching:TPS5420D +Regulator_Switching:TPS54233 +Regulator_Switching:TPS54260DGQ +Regulator_Switching:TPS54260DRC +Regulator_Switching:TPS54302 +Regulator_Switching:TPS54308 +Regulator_Switching:TPS5430DDA +Regulator_Switching:TPS5431DDA +Regulator_Switching:TPS54336ADDA +Regulator_Switching:TPS54340DDA +Regulator_Switching:TPS54360DDA +Regulator_Switching:TPS54560BDDA +Regulator_Switching:TPS560200 +Regulator_Switching:TPS562200 +Regulator_Switching:TPS562202 +Regulator_Switching:TPS562202S +Regulator_Switching:TPS562203 +Regulator_Switching:TPS562206 +Regulator_Switching:TPS563200 +Regulator_Switching:TPS563202S +Regulator_Switching:TPS563203 +Regulator_Switching:TPS563206 +Regulator_Switching:TPS563240DDC +Regulator_Switching:TPS563300 +Regulator_Switching:TPS56339DDC +Regulator_Switching:TPS565208 +Regulator_Switching:TPS56528DDA +Regulator_Switching:TPS568215RNN +Regulator_Switching:TPS61040DBV +Regulator_Switching:TPS61040DDC +Regulator_Switching:TPS61040DRV +Regulator_Switching:TPS61041DBV +Regulator_Switching:TPS61041DDC +Regulator_Switching:TPS61041DRV +Regulator_Switching:TPS61085DGK +Regulator_Switching:TPS61085PW +Regulator_Switching:TPS61089 +Regulator_Switching:TPS610891 +Regulator_Switching:TPS61090 +Regulator_Switching:TPS61091 +Regulator_Switching:TPS61092 +Regulator_Switching:TPS610991DRV +Regulator_Switching:TPS610992DRV +Regulator_Switching:TPS610993DRV +Regulator_Switching:TPS610994DRV +Regulator_Switching:TPS610995DRV +Regulator_Switching:TPS610996DRV +Regulator_Switching:TPS610997DRV +Regulator_Switching:TPS61099DRV +Regulator_Switching:TPS61200DRC +Regulator_Switching:TPS61201DRC +Regulator_Switching:TPS61202DRC +Regulator_Switching:TPS61202DSC +Regulator_Switching:TPS61220DCK +Regulator_Switching:TPS61221DCK +Regulator_Switching:TPS61222DCK +Regulator_Switching:TPS61230DRC +Regulator_Switching:TPS61252DSG +Regulator_Switching:TPS613221ADBV +Regulator_Switching:TPS613221ADBZ +Regulator_Switching:TPS613222ADBV +Regulator_Switching:TPS613222ADBZ +Regulator_Switching:TPS613223ADBV +Regulator_Switching:TPS613223ADBZ +Regulator_Switching:TPS613224ADBV +Regulator_Switching:TPS613224ADBZ +Regulator_Switching:TPS613225ADBV +Regulator_Switching:TPS613225ADBZ +Regulator_Switching:TPS613226ADBV +Regulator_Switching:TPS613226ADBZ +Regulator_Switching:TPS61322DBZ +Regulator_Switching:TPS62056DGS +Regulator_Switching:TPS62125DSG +Regulator_Switching:TPS62130 +Regulator_Switching:TPS62130A +Regulator_Switching:TPS62131 +Regulator_Switching:TPS62132 +Regulator_Switching:TPS62133 +Regulator_Switching:TPS62140 +Regulator_Switching:TPS62140A +Regulator_Switching:TPS62141 +Regulator_Switching:TPS62142 +Regulator_Switching:TPS62143 +Regulator_Switching:TPS62150 +Regulator_Switching:TPS62150A +Regulator_Switching:TPS62151 +Regulator_Switching:TPS62152 +Regulator_Switching:TPS62153 +Regulator_Switching:TPS62160DGK +Regulator_Switching:TPS62160DSG +Regulator_Switching:TPS62161DSG +Regulator_Switching:TPS62162DSG +Regulator_Switching:TPS62163DSG +Regulator_Switching:TPS62170DSG +Regulator_Switching:TPS62171DSG +Regulator_Switching:TPS62172DSG +Regulator_Switching:TPS62173DSG +Regulator_Switching:TPS62175DQC +Regulator_Switching:TPS62177DQC +Regulator_Switching:TPS62200DBV +Regulator_Switching:TPS62201DBV +Regulator_Switching:TPS62202DBV +Regulator_Switching:TPS62203DBV +Regulator_Switching:TPS62204DBV +Regulator_Switching:TPS62205DBV +Regulator_Switching:TPS62207DBV +Regulator_Switching:TPS62208DBV +Regulator_Switching:TPS62821DLC +Regulator_Switching:TPS62822DLC +Regulator_Switching:TPS62823DLC +Regulator_Switching:TPS628436DRL +Regulator_Switching:TPS628436YKA +Regulator_Switching:TPS628437DRL +Regulator_Switching:TPS628437YKA +Regulator_Switching:TPS628438DRL +Regulator_Switching:TPS628438YKA +Regulator_Switching:TPS62912 +Regulator_Switching:TPS62913 +Regulator_Switching:TPS62932 +Regulator_Switching:TPS62933 +Regulator_Switching:TPS62933F +Regulator_Switching:TPS62933O +Regulator_Switching:TPS62933P +Regulator_Switching:TPS62A01ADRL +Regulator_Switching:TPS62A01APDDC +Regulator_Switching:TPS62A01DRL +Regulator_Switching:TPS62A01PDDC +Regulator_Switching:TPS62A02ADRL +Regulator_Switching:TPS62A02APDDC +Regulator_Switching:TPS62A02DRL +Regulator_Switching:TPS62A02NADRL +Regulator_Switching:TPS62A02NDRL +Regulator_Switching:TPS62A02PDDC +Regulator_Switching:TPS63000 +Regulator_Switching:TPS63000-Q1 +Regulator_Switching:TPS63001 +Regulator_Switching:TPS63002 +Regulator_Switching:TPS63030DSK +Regulator_Switching:TPS63031DSK +Regulator_Switching:TPS63060 +Regulator_Switching:TPS63061 +Regulator_Switching:TPS63900 +Regulator_Switching:TPS65130RGE +Regulator_Switching:TPS65131RGE +Regulator_Switching:TPS82130 +Regulator_Switching:TPS82140 +Regulator_Switching:TPS82150 +Regulator_Switching:TSR0.6-48120WI +Regulator_Switching:TSR0.6-48150WI +Regulator_Switching:TSR0.6-48240WI +Regulator_Switching:TSR0.6-4833WI +Regulator_Switching:TSR0.6-4850WI +Regulator_Switching:TSR0.6-4865WI +Regulator_Switching:TSR0.6-4890WI +Regulator_Switching:TSR1-2433E +Regulator_Switching:TSR1-2450E +Regulator_Switching:TSR2-24120N +Regulator_Switching:TSR2-2412N +Regulator_Switching:TSR2-24150N +Regulator_Switching:TSR2-2415N +Regulator_Switching:TSR2-2418N +Regulator_Switching:TSR2-2425N +Regulator_Switching:TSR2-2433N +Regulator_Switching:TSR2-2450N +Regulator_Switching:TSR2-2465N +Regulator_Switching:TSR2-2490N +Regulator_Switching:TSR_1-2412 +Regulator_Switching:TSR_1-24120 +Regulator_Switching:TSR_1-2415 +Regulator_Switching:TSR_1-24150 +Regulator_Switching:TSR_1-2418 +Regulator_Switching:TSR_1-2425 +Regulator_Switching:TSR_1-2433 +Regulator_Switching:TSR_1-2450 +Regulator_Switching:TSR_1-2465 +Regulator_Switching:TSR_1-2490 +Regulator_Switching:VIPer22ADIP-E +Regulator_Switching:VIPer22AS +Regulator_Switching:VIPer25HN +Regulator_Switching:VIPer25LN +Regulator_Switching:VIPer26HD +Regulator_Switching:VIPer26HN +Regulator_Switching:VIPer26LD +Regulator_Switching:VIPer26LN +Regulator_Switching:XL1509-12 +Regulator_Switching:XL1509-3.3 +Regulator_Switching:XL1509-5.0 +Regulator_Switching:XL1509-ADJ +Regulator_Switching:XL4015 +Relay:ADW11 +Relay:AZ850-x +Relay:AZ850P1-x +Relay:AZ850P2-x +Relay:AZSR131-1AE-12D +Relay:COTO_3602_Split +Relay:COTO_3650_Split +Relay:COTO_3660_Split +Relay:DIPxx-1Axx-11x +Relay:DIPxx-1Axx-12x +Relay:DIPxx-1Axx-12xD +Relay:DIPxx-1Axx-13x +Relay:DIPxx-1Cxx-51x +Relay:DIPxx-2Axx-21x +Relay:DR-24V +Relay:DR-3V +Relay:DR-5V +Relay:DR-L-3V +Relay:DR-L2-3V_Form1 +Relay:DR-L2-3V_Form2 +Relay:EC2-12NU +Relay:EC2-12SNU +Relay:EC2-12TNU +Relay:EC2-24NU +Relay:EC2-24SNU +Relay:EC2-24TNU +Relay:EC2-3NU +Relay:EC2-3SNU +Relay:EC2-3TNU +Relay:EC2-4.5NU +Relay:EC2-4.5SNU +Relay:EC2-4.5TNU +Relay:EC2-5NU +Relay:EC2-5SNU +Relay:EC2-5TNU +Relay:EE2-12NKX +Relay:EE2-12NU +Relay:EE2-12NUH +Relay:EE2-12NUX +Relay:EE2-12SNU +Relay:EE2-12SNUH +Relay:EE2-12SNUX +Relay:EE2-12TNU +Relay:EE2-12TNUH +Relay:EE2-12TNUX +Relay:EE2-24NU +Relay:EE2-24NUH +Relay:EE2-24NUX +Relay:EE2-24SNU +Relay:EE2-24SNUH +Relay:EE2-24SNUX +Relay:EE2-24TNU +Relay:EE2-24TNUH +Relay:EE2-24TNUX +Relay:EE2-3NKX +Relay:EE2-3NU +Relay:EE2-3NUH +Relay:EE2-3NUX +Relay:EE2-3SNU +Relay:EE2-3SNUH +Relay:EE2-3SNUX +Relay:EE2-3TNU +Relay:EE2-3TNUH +Relay:EE2-3TNUX +Relay:EE2-4.5NKX +Relay:EE2-4.5NU +Relay:EE2-4.5NUH +Relay:EE2-4.5NUX +Relay:EE2-4.5SNU +Relay:EE2-4.5SNUH +Relay:EE2-4.5SNUX +Relay:EE2-4.5TNU +Relay:EE2-4.5TNUH +Relay:EE2-4.5TNUX +Relay:EE2-5NU +Relay:EE2-5NUH +Relay:EE2-5NUX +Relay:EE2-5SNU +Relay:EE2-5SNUH +Relay:EE2-5SNUX +Relay:EE2-5TNU +Relay:EE2-5TNUH +Relay:EE2-5TNUX +Relay:FINDER-30.22 +Relay:FINDER-32.21-x000 +Relay:FINDER-32.21-x300 +Relay:FINDER-34.51 +Relay:FINDER-34.51.7xxx.x019 +Relay:FINDER-36.11 +Relay:FINDER-40.11 +Relay:FINDER-40.11-2016 +Relay:FINDER-40.31 +Relay:FINDER-40.41 +Relay:FINDER-40.51 +Relay:FINDER-40.52 +Relay:FINDER-41.52 +Relay:FINDER-44.52 +Relay:FINDER-44.62 +Relay:FRT5 +Relay:FRT5_separated +Relay:Fujitsu_FTR-F1A +Relay:Fujitsu_FTR-F1C +Relay:Fujitsu_FTR-LYAA005x +Relay:Fujitsu_FTR-LYCA005x +Relay:G2RL-1 +Relay:G2RL-1-E +Relay:G2RL-1-H +Relay:G2RL-1A +Relay:G2RL-1A-E +Relay:G2RL-1A-H +Relay:G2RL-2 +Relay:G2RL-2A +Relay:G5LE-1 +Relay:G5NB +Relay:G5Q-1 +Relay:G5Q-1A +Relay:G5V-1 +Relay:G5V-2 +Relay:G5V-2_Split +Relay:G6A +Relay:G6AK +Relay:G6AU +Relay:G6E +Relay:G6EU +Relay:G6H-2 +Relay:G6HU-2 +Relay:G6K-2 +Relay:G6KU-2 +Relay:G6S-2 +Relay:G6SK-2 +Relay:G6SU-2 +Relay:HF115F-2Z-x4 +Relay:HF3-01 +Relay:HF3-02 +Relay:HF3-03 +Relay:HF3-04 +Relay:HF3-05 +Relay:HF3-06 +Relay:HF3-07 +Relay:HF3-51 +Relay:HF3-52 +Relay:HF3-53 +Relay:HF3-54 +Relay:HF3-55 +Relay:HF3-56 +Relay:HF3-57 +Relay:HK19F-DCxxV-SHC +Relay:HONGFA_HFD2-0xx-x-L2-x +Relay:IM00 +Relay:IM01 +Relay:IM02 +Relay:IM03 +Relay:IM04 +Relay:IM05 +Relay:IM06 +Relay:IM07 +Relay:IM08 +Relay:IM11 +Relay:IM12 +Relay:IM13 +Relay:IM16 +Relay:IM17 +Relay:IM21 +Relay:IM22 +Relay:IM23 +Relay:IM26 +Relay:IM40 +Relay:IM41 +Relay:IM42 +Relay:IM43 +Relay:IM44 +Relay:IM45 +Relay:IM46 +Relay:IM47 +Relay:IM48 +Relay:JQC-3FF-005-1H +Relay:JQC-3FF-005-1Z +Relay:JQC-3FF-006-1H +Relay:JQC-3FF-006-1Z +Relay:JQC-3FF-009-1H +Relay:JQC-3FF-009-1Z +Relay:JQC-3FF-012-1H +Relay:JQC-3FF-012-1Z +Relay:JQC-3FF-018-1H +Relay:JQC-3FF-018-1Z +Relay:JQC-3FF-024-1H +Relay:JQC-3FF-024-1Z +Relay:JQC-3FF-048-1H +Relay:JQC-3FF-048-1Z +Relay:JW2 +Relay:MSxx-1Axx-75 +Relay:MSxx-1Bxx-75 +Relay:Panasonic_ALFG1PF09 +Relay:Panasonic_ALFG1PF091 +Relay:Panasonic_ALFG1PF12 +Relay:Panasonic_ALFG1PF121 +Relay:Panasonic_ALFG1PF18 +Relay:Panasonic_ALFG1PF181 +Relay:Panasonic_ALFG1PF24 +Relay:Panasonic_ALFG1PF241 +Relay:Panasonic_ALFG2PF09 +Relay:Panasonic_ALFG2PF091 +Relay:Panasonic_ALFG2PF12 +Relay:Panasonic_ALFG2PF121 +Relay:Panasonic_ALFG2PF18 +Relay:Panasonic_ALFG2PF181 +Relay:Panasonic_ALFG2PF24 +Relay:Panasonic_ALFG2PF241 +Relay:RAYEX-L90 +Relay:RAYEX-L90A +Relay:RAYEX-L90AS +Relay:RAYEX-L90B +Relay:RAYEX-L90BS +Relay:RAYEX-L90S +Relay:RM50-xx21 +Relay:RM84 +Relay:RSM822 +Relay:RT314A03 +Relay:RT314A05 +Relay:RT314A06 +Relay:RT314A12 +Relay:RT314A24 +Relay:RT42xAxx +Relay:RT42xFxx +Relay:RT42xxxx +Relay:RT44xxxx +Relay:RTE2xAxx +Relay:RTE2xFxx +Relay:RTE2xxxx +Relay:RTE4xxxx +Relay:Relay_DPDT +Relay:Relay_DPDT_Latching_1coil +Relay:Relay_DPDT_Latching_2coil +Relay:Relay_DPST-NC +Relay:Relay_DPST-NO +Relay:Relay_DPST_Latching_1coil +Relay:Relay_DPST_Latching_2coil +Relay:Relay_SPDT +Relay:Relay_SPDT_Latching_1coil +Relay:Relay_SPDT_Latching_2coil +Relay:Relay_SPST-NC +Relay:Relay_SPST-NO +Relay:Relay_SPST_Latching_1coil +Relay:Relay_SPST_Latching_2coil +Relay:SANYOU_SRD_Form_A +Relay:SANYOU_SRD_Form_B +Relay:SANYOU_SRD_Form_C +Relay:SILxx-1Axx-71x +Relay:SILxx-1Bxx-71x +Relay:SILxx-1Cxx-51x +Relay:TE_PCH-1xxx2M +Relay:TIANBO-HJR-4102-L +Relay:UMS05-1A80-75D +Relay:UMS05-1A80-75L +Relay:V23072-Cx061-xxx8 +Relay:V23072-Cx062-xxx8 +Relay:Y14x-1C-xxDS +Relay_SolidState:34.81-7048 +Relay_SolidState:34.81-8240 +Relay_SolidState:34.81-9024 +Relay_SolidState:AQH0213 +Relay_SolidState:AQH0213A +Relay_SolidState:AQH0223 +Relay_SolidState:AQH0223A +Relay_SolidState:AQH1213 +Relay_SolidState:AQH1213A +Relay_SolidState:AQH1223 +Relay_SolidState:AQH1223A +Relay_SolidState:AQH2213 +Relay_SolidState:AQH2213A +Relay_SolidState:AQH2223 +Relay_SolidState:AQH2223A +Relay_SolidState:AQH3213 +Relay_SolidState:AQH3213A +Relay_SolidState:AQH3223 +Relay_SolidState:AQH3223A +Relay_SolidState:ASSR-1218 +Relay_SolidState:BC2213A +Relay_SolidState:CPC1002N +Relay_SolidState:CPC1017N +Relay_SolidState:CPC1117N +Relay_SolidState:FOD420 +Relay_SolidState:FOD4208 +Relay_SolidState:FOD4216 +Relay_SolidState:FOD4218 +Relay_SolidState:FODM3011 +Relay_SolidState:FODM3012 +Relay_SolidState:FODM3022 +Relay_SolidState:FODM3023 +Relay_SolidState:FODM3052 +Relay_SolidState:FODM3053 +Relay_SolidState:HHG1D-1 +Relay_SolidState:LAA110 +Relay_SolidState:LBB110 +Relay_SolidState:LCC110 +Relay_SolidState:MOC3010M +Relay_SolidState:MOC3011M +Relay_SolidState:MOC3012M +Relay_SolidState:MOC3020M +Relay_SolidState:MOC3021M +Relay_SolidState:MOC3022M +Relay_SolidState:MOC3023M +Relay_SolidState:MOC3031M +Relay_SolidState:MOC3032M +Relay_SolidState:MOC3033M +Relay_SolidState:MOC3041M +Relay_SolidState:MOC3042M +Relay_SolidState:MOC3043M +Relay_SolidState:MOC3051M +Relay_SolidState:MOC3052M +Relay_SolidState:MOC3061M +Relay_SolidState:MOC3062M +Relay_SolidState:MOC3063M +Relay_SolidState:MOC3081M +Relay_SolidState:MOC3082M +Relay_SolidState:MOC3083M +Relay_SolidState:MOC3162M +Relay_SolidState:MOC3163M +Relay_SolidState:S102S01 +Relay_SolidState:S102S02 +Relay_SolidState:S112S01 +Relay_SolidState:S116S01 +Relay_SolidState:S116S02 +Relay_SolidState:S202S01 +Relay_SolidState:S202S02 +Relay_SolidState:S212S01 +Relay_SolidState:S216S01 +Relay_SolidState:S216S02 +Relay_SolidState:TLP141G +Relay_SolidState:TLP148G +Relay_SolidState:TLP160G +Relay_SolidState:TLP160J +Relay_SolidState:TLP161G +Relay_SolidState:TLP161J +Relay_SolidState:TLP175A +Relay_SolidState:TLP222A +Relay_SolidState:TLP222A-2 +Relay_SolidState:TLP3123 +Relay_SolidState:TLP3542 +Relay_SolidState:TLP3543 +Relay_SolidState:TLP3544 +Relay_SolidState:TLP3545 +Relay_SolidState:TLP3546 +RF:0900PC15J0013 +RF:ADC-10-1R +RF:ADCH-80 +RF:ADCH-80A +RF:ADL5904 +RF:ADP-2-1W +RF:AMK-2-13 +RF:AX5043 +RF:CC1000 +RF:CC1200 +RF:CC2500 +RF:DC4759J5020AHF-1 +RF:DC4759J5020AHF-2 +RF:DW1000 +RF:F113 +RF:F115 +RF:F117 +RF:HMC394LP4 +RF:HMC431 +RF:LAT-3 +RF:LRPS-2-1 +RF:LTC5507ES6 +RF:MAADSS0008 +RF:MAAVSS0004 +RF:MC12080 +RF:MC12093D +RF:MICRF112YMM +RF:MICRF220AYQS +RF:MRF89XA +RF:NRF24L01 +RF:NRF24L01_Breakout +RF:PAT1220-C-0DB +RF:PAT1220-C-10DB +RF:PAT1220-C-1DB +RF:PAT1220-C-2DB +RF:PAT1220-C-3DB +RF:PAT1220-C-4DB +RF:PAT1220-C-5DB +RF:PAT1220-C-6DB +RF:PAT1220-C-7DB +RF:PAT1220-C-8DB +RF:PAT1220-C-9DB +RF:PD4859J5050S2HF +RF:RMK-3-451 +RF:RMK-5-51 +RF:SE5004L +RF:SX1231IMLTRT +RF:SX1261IMLTRT +RF:SX1262IMLTRT +RF:SX1272 +RF:SX1273 +RF:SX1276 +RF:SX1277 +RF:SX1278 +RF:SX1279 +RF:SYPD-1 +RF:SYPD-2 +RF:SYPD-52 +RF:Si4460 +RF:Si4461 +RF:Si4463 +RF:Si4464 +RF:TCP-2-10X +RF:nRF24L01P +RF_Amplifier:AD8313xRM +RF_Amplifier:ADL5541 +RF_Amplifier:ADL5542 +RF_Amplifier:ADL5610 +RF_Amplifier:BGA2800 +RF_Amplifier:BGA2801 +RF_Amplifier:BGA2803 +RF_Amplifier:BGA2815 +RF_Amplifier:BGA2817 +RF_Amplifier:BGA2818 +RF_Amplifier:BGA2850 +RF_Amplifier:BGA2851 +RF_Amplifier:BGA2865 +RF_Amplifier:BGA2866 +RF_Amplifier:BGA2867 +RF_Amplifier:BGA2869 +RF_Amplifier:BGA2870 +RF_Amplifier:BGA2874 +RF_Amplifier:CMX901 +RF_Amplifier:GALI-1 +RF_Amplifier:GALI-19 +RF_Amplifier:GALI-2 +RF_Amplifier:GALI-21 +RF_Amplifier:GALI-24 +RF_Amplifier:GALI-29 +RF_Amplifier:GALI-3 +RF_Amplifier:GALI-33 +RF_Amplifier:GALI-39 +RF_Amplifier:GALI-4 +RF_Amplifier:GALI-49 +RF_Amplifier:GALI-4F +RF_Amplifier:GALI-5 +RF_Amplifier:GALI-51 +RF_Amplifier:GALI-51F +RF_Amplifier:GALI-52 +RF_Amplifier:GALI-55 +RF_Amplifier:GALI-59 +RF_Amplifier:GALI-5F +RF_Amplifier:GALI-6 +RF_Amplifier:GALI-6F +RF_Amplifier:GALI-74 +RF_Amplifier:GALI-84 +RF_Amplifier:GALI-S66 +RF_Amplifier:GVA-123 +RF_Amplifier:GVA-60 +RF_Amplifier:GVA-62 +RF_Amplifier:GVA-63 +RF_Amplifier:GVA-81 +RF_Amplifier:GVA-82 +RF_Amplifier:GVA-83 +RF_Amplifier:GVA-84 +RF_Amplifier:GVA-93 +RF_Amplifier:HMC1099PM5E +RF_Amplifier:HMC8500PM5E +RF_Amplifier:MAX2679 +RF_Amplifier:MAX2679B +RF_Amplifier:MMZ09332BT1 +RF_Amplifier:PGA-102 +RF_Amplifier:PGA-1021 +RF_Amplifier:PGA-103 +RF_Amplifier:PGA-105 +RF_Amplifier:PGA-106-75 +RF_Amplifier:PGA-106R-75 +RF_Amplifier:PGA-122-75 +RF_Amplifier:PGA-32-75 +RF_Amplifier:PHA-1 +RF_Amplifier:PHA-101 +RF_Amplifier:PHA-13HLN +RF_Amplifier:PHA-13LN +RF_Amplifier:PHA-1H +RF_Amplifier:PHA-23HLN +RF_Amplifier:PHA-23LN +RF_Amplifier:QPL9547 +RF_Amplifier:SGL0622Z +RF_Amplifier:SKY65404 +RF_Amplifier:SPF5189Z +RF_Amplifier:TRF37A73 +RF_AM_FM:LA1185 +RF_AM_FM:MCS3142 +RF_AM_FM:SA605D +RF_AM_FM:SA605DK +RF_AM_FM:SA636DK +RF_AM_FM:Si4362 +RF_AM_FM:Si4730-D60-GU +RF_AM_FM:Si4731-D60-GU +RF_AM_FM:Si4734-D60-GU +RF_AM_FM:Si4735-D60-GU +RF_AM_FM:ZETA-433-SO +RF_AM_FM:ZETA-868-SO +RF_AM_FM:ZETA-915-SO +RF_Bluetooth:BL652 +RF_Bluetooth:BM78SPPS5MC2 +RF_Bluetooth:BM78SPPS5NC2 +RF_Bluetooth:BTM112 +RF_Bluetooth:BTM222 +RF_Bluetooth:MOD-nRF8001 +RF_Bluetooth:Microchip_BM83 +RF_Bluetooth:RFD77101 +RF_Bluetooth:RN42 +RF_Bluetooth:RN42N +RF_Bluetooth:RN4871 +RF_Bluetooth:SPBTLE-RF +RF_Bluetooth:SPBTLE-RF0 +RF_Bluetooth:nRF8001 +RF_Filter:B3715 +RF_Filter:BFCN-1445 +RF_Filter:BFCN-1525 +RF_Filter:BFCN-152W-75 +RF_Filter:BFCN-1560 +RF_Filter:BFCN-1575 +RF_Filter:BFCN-1690 +RF_Filter:BFCN-1840 +RF_Filter:BFCN-1855 +RF_Filter:BFCN-1860 +RF_Filter:BFCN-1900 +RF_Filter:BFCN-1945 +RF_Filter:BFCN-2275 +RF_Filter:BFCN-2360 +RF_Filter:BFCN-2435 +RF_Filter:BFCN-2450 +RF_Filter:BFCN-2500 +RF_Filter:BFCN-2555 +RF_Filter:BFCN-2700 +RF_Filter:BFCN-2840 +RF_Filter:BFCN-2850 +RF_Filter:BFCN-2900 +RF_Filter:BFCN-2910 +RF_Filter:BFCN-2975 +RF_Filter:BFCN-3010 +RF_Filter:BFCN-3085 +RF_Filter:BFCN-3085A +RF_Filter:BFCN-3115 +RF_Filter:BFCN-3600 +RF_Filter:BFCN-3700 +RF_Filter:BFCN-4100 +RF_Filter:BFCN-4440 +RF_Filter:BFCN-4800 +RF_Filter:BFCN-5100 +RF_Filter:BFCN-5200 +RF_Filter:BFCN-5540 +RF_Filter:BFCN-5750 +RF_Filter:BFCN-7200 +RF_Filter:BFCN-7331 +RF_Filter:BFCN-7350 +RF_Filter:BFCN-7500 +RF_Filter:BFCN-7700 +RF_Filter:BFCN-7900 +RF_Filter:BFCN-8000 +RF_Filter:BFCN-8350 +RF_Filter:BFCN-8450 +RF_Filter:BFCN-8650 +RF_Filter:BPF-A355 +RF_Filter:HFCN-1000 +RF_Filter:HFCN-1080 +RF_Filter:HFCN-1100 +RF_Filter:HFCN-1150 +RF_Filter:HFCN-1200 +RF_Filter:HFCN-1200D +RF_Filter:HFCN-1300 +RF_Filter:HFCN-1300D +RF_Filter:HFCN-1320 +RF_Filter:HFCN-1320D +RF_Filter:HFCN-1322 +RF_Filter:HFCN-1500 +RF_Filter:HFCN-1500D +RF_Filter:HFCN-1600 +RF_Filter:HFCN-1600D +RF_Filter:HFCN-1760 +RF_Filter:HFCN-1810 +RF_Filter:HFCN-1810D +RF_Filter:HFCN-1910 +RF_Filter:HFCN-1910D +RF_Filter:HFCN-2000 +RF_Filter:HFCN-2100 +RF_Filter:HFCN-2100D +RF_Filter:HFCN-2275 +RF_Filter:HFCN-2700 +RF_Filter:HFCN-2700A +RF_Filter:HFCN-2700AD +RF_Filter:HFCN-3100 +RF_Filter:HFCN-3100D +RF_Filter:HFCN-3500 +RF_Filter:HFCN-3500D +RF_Filter:HFCN-3800 +RF_Filter:HFCN-3800D +RF_Filter:HFCN-440 +RF_Filter:HFCN-4400 +RF_Filter:HFCN-4400D +RF_Filter:HFCN-4600 +RF_Filter:HFCN-5050 +RF_Filter:HFCN-5500 +RF_Filter:HFCN-5500D +RF_Filter:HFCN-6010 +RF_Filter:HFCN-650 +RF_Filter:HFCN-650D +RF_Filter:HFCN-672 +RF_Filter:HFCN-7150 +RF_Filter:HFCN-740 +RF_Filter:HFCN-740D +RF_Filter:HFCN-7971 +RF_Filter:HFCN-8400 +RF_Filter:HFCN-8400D +RF_Filter:HFCN-880 +RF_Filter:HFCN-880D +RF_Filter:HFCN-9700 +RF_Filter:LFCN-1000 +RF_Filter:LFCN-1000D +RF_Filter:LFCN-105 +RF_Filter:LFCN-113 +RF_Filter:LFCN-120 +RF_Filter:LFCN-1200 +RF_Filter:LFCN-1200D +RF_Filter:LFCN-123 +RF_Filter:LFCN-1282 +RF_Filter:LFCN-1325 +RF_Filter:LFCN-1400 +RF_Filter:LFCN-1400D +RF_Filter:LFCN-1450 +RF_Filter:LFCN-1500 +RF_Filter:LFCN-1500D +RF_Filter:LFCN-1525 +RF_Filter:LFCN-1525D +RF_Filter:LFCN-1575 +RF_Filter:LFCN-1575D +RF_Filter:LFCN-160 +RF_Filter:LFCN-1700 +RF_Filter:LFCN-1700D +RF_Filter:LFCN-180 +RF_Filter:LFCN-1800 +RF_Filter:LFCN-1800D +RF_Filter:LFCN-190 +RF_Filter:LFCN-2000 +RF_Filter:LFCN-2000D +RF_Filter:LFCN-225 +RF_Filter:LFCN-2250 +RF_Filter:LFCN-2250D +RF_Filter:LFCN-225D +RF_Filter:LFCN-2290 +RF_Filter:LFCN-2400 +RF_Filter:LFCN-2400D +RF_Filter:LFCN-2500 +RF_Filter:LFCN-2500D +RF_Filter:LFCN-2600 +RF_Filter:LFCN-2600D +RF_Filter:LFCN-2750 +RF_Filter:LFCN-2750D +RF_Filter:LFCN-2850 +RF_Filter:LFCN-2850D +RF_Filter:LFCN-3000 +RF_Filter:LFCN-3000D +RF_Filter:LFCN-320 +RF_Filter:LFCN-320D +RF_Filter:LFCN-3400 +RF_Filter:LFCN-3400D +RF_Filter:LFCN-3800 +RF_Filter:LFCN-3800D +RF_Filter:LFCN-400 +RF_Filter:LFCN-400D +RF_Filter:LFCN-4400 +RF_Filter:LFCN-4400D +RF_Filter:LFCN-490 +RF_Filter:LFCN-490D +RF_Filter:LFCN-5000 +RF_Filter:LFCN-5000D +RF_Filter:LFCN-530 +RF_Filter:LFCN-530D +RF_Filter:LFCN-5500 +RF_Filter:LFCN-5500D +RF_Filter:LFCN-575 +RF_Filter:LFCN-575D +RF_Filter:LFCN-5850 +RF_Filter:LFCN-5850D +RF_Filter:LFCN-6000 +RF_Filter:LFCN-6000D +RF_Filter:LFCN-630 +RF_Filter:LFCN-630D +RF_Filter:LFCN-6400 +RF_Filter:LFCN-6400D +RF_Filter:LFCN-6700 +RF_Filter:LFCN-6700D +RF_Filter:LFCN-7200 +RF_Filter:LFCN-7200D +RF_Filter:LFCN-722 +RF_Filter:LFCN-80 +RF_Filter:LFCN-800 +RF_Filter:LFCN-800D +RF_Filter:LFCN-8400 +RF_Filter:LFCN-8440 +RF_Filter:LFCN-900 +RF_Filter:LFCN-900D +RF_Filter:LFCN-9170 +RF_Filter:LFCN-95 +RF_Filter:LPF-B0R3 +RF_Filter:RBP-280 +RF_Filter:RBPF-246 +RF_Filter:RLP-30 +RF_Filter:SCHF-31 +RF_Filter:STA0232A +RF_Filter:STA1090EC +RF_Filter:SXBP-100 +RF_Filter:SXBP-140 +RF_Filter:SXBP-202 +RF_Filter:SXBP-27R5 +RF_Filter:TA0232A +RF_Filter:TA0970B +RF_GPS:L70-R +RF_GPS:L80-R +RF_GPS:LEA-M8F +RF_GPS:LEA-M8S +RF_GPS:LEA-M8T +RF_GPS:MAX-8C +RF_GPS:MAX-8Q +RF_GPS:MAX-M10S +RF_GPS:MAX-M8C +RF_GPS:MAX-M8Q +RF_GPS:MAX-M8W +RF_GPS:NEO-8Q +RF_GPS:NEO-M8M +RF_GPS:NEO-M8N +RF_GPS:NEO-M8P +RF_GPS:NEO-M8Q +RF_GPS:NEO-M8T +RF_GPS:NEO-M9N +RF_GPS:RXM-GPS-FM +RF_GPS:RXM-GPS-RM +RF_GPS:SAM-M8Q +RF_GPS:SIM28ML +RF_GPS:ZED-F9P +RF_GPS:ZOE-M8G +RF_GPS:ZOE-M8Q +RF_GSM:BC66 +RF_GSM:BC95 +RF_GSM:BG95-M1 +RF_GSM:BG95-M2 +RF_GSM:BG95-M3 +RF_GSM:BG95-M4 +RF_GSM:BG95-M5 +RF_GSM:BG95-M6 +RF_GSM:BG95-M8 +RF_GSM:BG95-MF +RF_GSM:LENA-R8001 +RF_GSM:M95 +RF_GSM:SARA-U201 +RF_GSM:SARA-U260 +RF_GSM:SARA-U270 +RF_GSM:SARA-U280 +RF_GSM:SE150A4 +RF_GSM:SIM7020C +RF_GSM:SIM7020E +RF_GSM:SIM800C +RF_GSM:SIM900 +RF_GSM:UL865 +RF_Mixer:AD831AP +RF_Mixer:ADE-6 +RF_Mixer:ADEX-10 +RF_Mixer:ADL5801 +RF_Mixer:ADL5802 +RF_Mixer:HMC213A +RF_Mixer:HMC213B +RF_Mixer:LT5560 +RF_Module:AST50147-xx +RF_Module:ATSAMR21G18-MR210UA_NoRFPads +RF_Module:AX-SIP-SFEU +RF_Module:AX-SIP-SFEU-API +RF_Module:Ai-Thinker-Ra-01 +RF_Module:Ai-Thinker-Ra-02 +RF_Module:CMWX1ZZABZ-078 +RF_Module:CMWX1ZZABZ-091 +RF_Module:D52MxxM8 +RF_Module:DCTR-52DA +RF_Module:DCTR-52DAT +RF_Module:DWM1000 +RF_Module:DWM1001 +RF_Module:DWM3000 +RF_Module:E18-MS1-PCB +RF_Module:E73-2G4M04S-52810 +RF_Module:E73-2G4M04S-52832 +RF_Module:ESP-07 +RF_Module:ESP-12E +RF_Module:ESP-12F +RF_Module:ESP-WROOM-02 +RF_Module:ESP32-C3-DevKitM-1 +RF_Module:ESP32-C3-WROOM-02 +RF_Module:ESP32-C3-WROOM-02U +RF_Module:ESP32-C6-MINI-1 +RF_Module:ESP32-S2-WROVER +RF_Module:ESP32-S2-WROVER-I +RF_Module:ESP32-S3-MINI-1 +RF_Module:ESP32-S3-MINI-1U +RF_Module:ESP32-S3-WROOM-1 +RF_Module:ESP32-S3-WROOM-2 +RF_Module:ESP32-WROOM-32 +RF_Module:ESP32-WROOM-32D +RF_Module:ESP32-WROOM-32E +RF_Module:ESP32-WROOM-32E-R2 +RF_Module:ESP32-WROOM-32U +RF_Module:ESP32-WROOM-32UE +RF_Module:ESP32-WROOM-32UE-R2 +RF_Module:HT-CT62 +RF_Module:Jadak_Thingmagic_M6e-Nano +RF_Module:MDBT42Q-512K +RF_Module:MDBT50Q-1MV2 +RF_Module:MDBT50Q-512K +RF_Module:MDBT50Q-P1MV2 +RF_Module:MDBT50Q-P512K +RF_Module:MDBT50Q-U1MV2 +RF_Module:MDBT50Q-U512K +RF_Module:MM002 +RF_Module:Particle_P1 +RF_Module:RAK4200 +RF_Module:RAK811-HF-AS923 +RF_Module:RAK811-HF-AU915 +RF_Module:RAK811-HF-EU868 +RF_Module:RAK811-HF-IN865 +RF_Module:RAK811-HF-KR920 +RF_Module:RAK811-HF-US915 +RF_Module:RAK811-LF-CN470 +RF_Module:RAK811-LF-EU433 +RF_Module:RFM69HCW +RF_Module:RFM69HW +RF_Module:RFM69W +RF_Module:RFM95W-868S2 +RF_Module:RFM95W-915S2 +RF_Module:RFM96W-315S2 +RF_Module:RFM96W-433S2 +RF_Module:RFM97W-868S2 +RF_Module:RFM97W-915S2 +RF_Module:RFM98W-315S2 +RF_Module:RFM98W-433S2 +RF_Module:STM32WB5MMG +RF_Module:TD1205 +RF_Module:TD1208 +RF_Module:TR-52DA +RF_Module:TR-52DAT +RF_Module:TR-72DA +RF_Module:TR-72DAT +RF_Module:WEMOS_C3_mini +RF_Module:WEMOS_D1_mini +RF_Module:iM880A +RF_Module:iM880B +RF_NFC:PN5321A3HN_C1xx +RF_NFC:ST25DV04K-IER8C3 +RF_NFC:ST25DV04K-JFR6D3 +RF_NFC:ST25DV16K-IER8C3 +RF_NFC:ST25DV16K-JFR6D3 +RF_NFC:ST25DV64K-IER8C3 +RF_NFC:ST25DV64K-JFR6D3 +RF_NFC:ST25R3911B-AQF +RF_NFC:ST25R3911B-AQW +RF_RFID:HTRC11001T +RF_RFID:PN5120A0HN1 +RF_Switch:ADG901BCPZ +RF_Switch:ADG901BRMZ +RF_Switch:ADG902BRMZ +RF_Switch:ADG918BCPZ +RF_Switch:ADG918BRM +RF_Switch:ADG919BCPZ +RF_Switch:ADG919BRMZ +RF_Switch:AS179-92LF +RF_Switch:BGS12WN6E6327 +RF_Switch:HMC7992 +RF_Switch:HMC849A +RF_Switch:KSW-2-46 +RF_Switch:KSWA-2-46 +RF_Switch:KSWHA-1-20 +RF_Switch:MASW-007221 +RF_Switch:MASWSS0115 +RF_Switch:MASWSS0136 +RF_Switch:MASWSS0143 +RF_Switch:MASWSS0151 +RF_Switch:MASWSS0166 +RF_Switch:MASWSS0176 +RF_Switch:MASWSS0178 +RF_Switch:MASWSS0179 +RF_Switch:MASWSS0192 +RF_Switch:MSW-2-20 +RF_Switch:MSW2-50 +RF_Switch:MSWA-2-20 +RF_Switch:MSWA2-50 +RF_Switch:SKY13380-350LF +RF_Switch:SKY13575-639LF +RF_WiFi:HF-A11-SMT +RF_WiFi:USR-C322 +RF_ZigBee:CC2520 +RF_ZigBee:MC13192 +RF_ZigBee:MW-R-DP-W +RF_ZigBee:MW-R-WX +RF_ZigBee:TWE-L-DP-W +RF_ZigBee:TWE-L-WX +RF_ZigBee:XBee_SMT +Security:ATAES132A-SH +Security:ATECC508A-MAHDA +Security:ATECC508A-SSHDA +Security:ATECC608A-MAHDA +Security:ATECC608A-SSHDA +Security:ATECC608B-MAHDA +Security:ATECC608B-SSHDA +Sensor:ADE7758 +Sensor:ADE7763xRS +Sensor:ADE7953xCP +Sensor:AM2302 +Sensor:APDS-9960 +Sensor:AS3935 +Sensor:BL0937 +Sensor:BME280 +Sensor:BME680 +Sensor:CHT11 +Sensor:DHT11 +Sensor:INA260 +Sensor:LTC2990 +Sensor:MAX30102 +Sensor:Nuclear-Radiation_Detector +Sensor:RPR-0521RS +Sensor:SHT1x +Sensor_Audio:ICS-43434 +Sensor_Audio:IM69D120 +Sensor_Audio:IM69D130 +Sensor_Audio:IM73A135V01 +Sensor_Audio:MP45DT02 +Sensor_Audio:SPH0641LU4H-1 +Sensor_Audio:SPH0645LM4H +Sensor_Audio:SPM0687LR5H-1 +Sensor_Current:A1363xKTTN-1 +Sensor_Current:A1363xKTTN-10 +Sensor_Current:A1363xKTTN-2 +Sensor_Current:A1363xKTTN-5 +Sensor_Current:A1365xKTTN-1 +Sensor_Current:A1365xKTTN-10 +Sensor_Current:A1365xKTTN-2 +Sensor_Current:A1365xKTTN-5 +Sensor_Current:A1366xKTTN-1 +Sensor_Current:A1366xKTTN-10 +Sensor_Current:A1366xKTTN-2 +Sensor_Current:A1366xKTTN-5 +Sensor_Current:A1367xKTTN-1 +Sensor_Current:A1367xKTTN-10 +Sensor_Current:A1367xKTTN-2 +Sensor_Current:A1367xKTTN-5 +Sensor_Current:A1369xUA-10 +Sensor_Current:A1369xUA-24 +Sensor_Current:ACS706xLC-05C +Sensor_Current:ACS709xLFTR-10BB +Sensor_Current:ACS709xLFTR-20BB +Sensor_Current:ACS709xLFTR-35BB +Sensor_Current:ACS709xLFTR-6BB +Sensor_Current:ACS710xLATR-10BB +Sensor_Current:ACS710xLATR-10BB-NL +Sensor_Current:ACS710xLATR-12BB +Sensor_Current:ACS710xLATR-12BB-NL +Sensor_Current:ACS710xLATR-25BB +Sensor_Current:ACS710xLATR-25BB-NL +Sensor_Current:ACS710xLATR-6BB +Sensor_Current:ACS710xLATR-6BB-NL +Sensor_Current:ACS711xEXLT-15AB +Sensor_Current:ACS711xEXLT-31AB +Sensor_Current:ACS711xLCTR-12AB +Sensor_Current:ACS711xLCTR-25AB +Sensor_Current:ACS712xLCTR-05B +Sensor_Current:ACS712xLCTR-20A +Sensor_Current:ACS712xLCTR-30A +Sensor_Current:ACS713xLCTR-20A +Sensor_Current:ACS713xLCTR-30A +Sensor_Current:ACS714xLCTR-05B +Sensor_Current:ACS714xLCTR-20A +Sensor_Current:ACS714xLCTR-30A +Sensor_Current:ACS714xLCTR-50A +Sensor_Current:ACS715xLCTR-20A +Sensor_Current:ACS715xLCTR-30A +Sensor_Current:ACS716xLATR-12BB +Sensor_Current:ACS716xLATR-12BB-NL +Sensor_Current:ACS716xLATR-25BB +Sensor_Current:ACS716xLATR-25BB-NL +Sensor_Current:ACS716xLATR-6BB +Sensor_Current:ACS716xLATR-6BB-NL +Sensor_Current:ACS717xMATR-10B +Sensor_Current:ACS717xMATR-20B +Sensor_Current:ACS718xMATR-10B +Sensor_Current:ACS718xMATR-20B +Sensor_Current:ACS720xMATR-15B +Sensor_Current:ACS720xMATR-35B +Sensor_Current:ACS720xMATR-65B +Sensor_Current:ACS722xLCTR-05AB +Sensor_Current:ACS722xLCTR-10AB +Sensor_Current:ACS722xLCTR-10AU +Sensor_Current:ACS722xLCTR-20AB +Sensor_Current:ACS722xLCTR-20AU +Sensor_Current:ACS722xLCTR-40AB +Sensor_Current:ACS722xLCTR-40AU +Sensor_Current:ACS722xMATR-10AB +Sensor_Current:ACS722xMATR-20AB +Sensor_Current:ACS722xMATR-40AB +Sensor_Current:ACS723xLCTR-05AB +Sensor_Current:ACS723xLCTR-10AB +Sensor_Current:ACS723xLCTR-10AU +Sensor_Current:ACS723xLCTR-20AB +Sensor_Current:ACS723xLCTR-20AU +Sensor_Current:ACS723xLCTR-40AB +Sensor_Current:ACS723xLCTR-40AU +Sensor_Current:ACS723xMATR-10AB +Sensor_Current:ACS723xMATR-20AB +Sensor_Current:ACS723xMATR-40AB +Sensor_Current:ACS724xLCTR-05AB +Sensor_Current:ACS724xLCTR-10AB +Sensor_Current:ACS724xLCTR-10AU +Sensor_Current:ACS724xLCTR-20AB +Sensor_Current:ACS724xLCTR-20AU +Sensor_Current:ACS724xLCTR-30AB +Sensor_Current:ACS724xLCTR-30AU +Sensor_Current:ACS724xLCTR-50AB +Sensor_Current:ACS724xMATR-12AB +Sensor_Current:ACS724xMATR-20AB +Sensor_Current:ACS724xMATR-30AB +Sensor_Current:ACS724xMATR-30AU +Sensor_Current:ACS724xMATR-65AB +Sensor_Current:ACS725xLCTR-10AU +Sensor_Current:ACS725xLCTR-20AB +Sensor_Current:ACS725xLCTR-20AU +Sensor_Current:ACS725xLCTR-30AB +Sensor_Current:ACS725xLCTR-30AU +Sensor_Current:ACS725xLCTR-40AB +Sensor_Current:ACS725xLCTR-50AB +Sensor_Current:ACS725xMATR-20AB +Sensor_Current:ACS725xMATR-30AB +Sensor_Current:ACS725xMATR-30AU +Sensor_Current:ACS726xLFTR-20B +Sensor_Current:ACS726xLFTR-40B +Sensor_Current:ACS730xLCTR-20AB +Sensor_Current:ACS730xLCTR-40AB +Sensor_Current:ACS730xLCTR-40AU +Sensor_Current:ACS730xLCTR-50AB +Sensor_Current:ACS730xLCTR-80AU +Sensor_Current:ACS732xLATR-40AB +Sensor_Current:ACS73369xUAA-010B5 +Sensor_Current:ACS733xLATR-20AB +Sensor_Current:ACS733xLATR-40AB +Sensor_Current:ACS733xLATR-40AU +Sensor_Current:ACS733xLATR-65AB +Sensor_Current:ACS756xCB-050B-PFF +Sensor_Current:ACS756xCB-100B-PFF +Sensor_Current:ACS758xCB-050B-PFF +Sensor_Current:ACS758xCB-050U-PFF +Sensor_Current:ACS758xCB-100B-PFF +Sensor_Current:ACS758xCB-100B-PSF +Sensor_Current:ACS758xCB-100U-PFF +Sensor_Current:ACS758xCB-150B-PFF +Sensor_Current:ACS758xCB-150B-PSS +Sensor_Current:ACS758xCB-150U-PFF +Sensor_Current:ACS758xCB-150U-PSF +Sensor_Current:ACS758xCB-200B-PFF +Sensor_Current:ACS758xCB-200B-PSF +Sensor_Current:ACS758xCB-200B-PSS +Sensor_Current:ACS758xCB-200U-PFF +Sensor_Current:ACS758xCB-200U-PSF +Sensor_Current:ACS759xCB-050B-PFF +Sensor_Current:ACS759xCB-100B-PFF +Sensor_Current:ACS759xCB-150B-PFF +Sensor_Current:ACS759xCB-150B-PSS +Sensor_Current:ACS759xCB-200B-PFF +Sensor_Current:ACS759xCB-200B-PSS +Sensor_Current:ACS770xCB-050B-PFF +Sensor_Current:ACS770xCB-050U-PFF +Sensor_Current:ACS770xCB-100B-PFF +Sensor_Current:ACS770xCB-100U-PFF +Sensor_Current:ACS770xCB-100U-PSF +Sensor_Current:ACS770xCB-150B-PFF +Sensor_Current:ACS770xCB-150B-PSF +Sensor_Current:ACS770xCB-150U-PFF +Sensor_Current:ACS770xCB-150U-PSF +Sensor_Current:ACS770xCB-200B-PFF +Sensor_Current:ACS770xCB-200B-PSF +Sensor_Current:ACS770xCB-200U-PFF +Sensor_Current:ACS770xCB-200U-PSF +Sensor_Current:ACS780xLRTR-050B +Sensor_Current:ACS780xLRTR-050U +Sensor_Current:ACS780xLRTR-100B +Sensor_Current:ACS780xLRTR-100U +Sensor_Current:ACS780xLRTR-150B +Sensor_Current:ACS780xLRTR-150U +Sensor_Current:ACS781xLRTR-050B +Sensor_Current:ACS781xLRTR-050U +Sensor_Current:ACS781xLRTR-100B +Sensor_Current:ACS781xLRTR-100U +Sensor_Current:ACS781xLRTR-150B +Sensor_Current:ACS781xLRTR-150U +Sensor_Current:CKSR_15-NP +Sensor_Current:CKSR_25-NP +Sensor_Current:CKSR_50-NP +Sensor_Current:CKSR_50-NP-SP1 +Sensor_Current:CKSR_6-NP +Sensor_Current:CKSR_75-NP +Sensor_Current:CQ-2063 +Sensor_Current:CQ-2064 +Sensor_Current:CQ-2065 +Sensor_Current:CQ-206A +Sensor_Current:CQ-206B +Sensor_Current:CQ-2092 +Sensor_Current:CQ-2093 +Sensor_Current:CQ-209A +Sensor_Current:CQ-209B +Sensor_Current:CQ-209D +Sensor_Current:CQ-2232 +Sensor_Current:CQ-2233 +Sensor_Current:CQ-2234 +Sensor_Current:CQ-2235 +Sensor_Current:CQ-2332 +Sensor_Current:CQ-2333 +Sensor_Current:CQ-2334 +Sensor_Current:CQ-2335 +Sensor_Current:CQ-2336 +Sensor_Current:CQ-236B +Sensor_Current:CQ-3200 +Sensor_Current:CQ-3201 +Sensor_Current:CQ-3202 +Sensor_Current:CQ-3203 +Sensor_Current:CQ-3204 +Sensor_Current:CQ-320A +Sensor_Current:CQ-320B +Sensor_Current:CQ-3300 +Sensor_Current:CQ-3301 +Sensor_Current:CQ-3302 +Sensor_Current:CQ-3303 +Sensor_Current:CQ-330A +Sensor_Current:CQ-330B +Sensor_Current:CQ-330E +Sensor_Current:CQ-330F +Sensor_Current:CQ-330G +Sensor_Current:CQ-330H +Sensor_Current:CQ-330J +Sensor_Current:CSLW6B1 +Sensor_Current:CSLW6B200M +Sensor_Current:CSLW6B40M +Sensor_Current:CSLW6B5 +Sensor_Current:CZ-3813 +Sensor_Current:CZ-3814 +Sensor_Current:CZ-3815 +Sensor_Current:HO120-NP +Sensor_Current:HO128-NP +Sensor_Current:HO15-NP +Sensor_Current:HO15-NPxSP33 +Sensor_Current:HO15-NSM +Sensor_Current:HO150-NP +Sensor_Current:HO25-NP +Sensor_Current:HO25-NPxSP33 +Sensor_Current:HO25-NSM +Sensor_Current:HO40-NP +Sensor_Current:HO60-NP +Sensor_Current:HO8-NP +Sensor_Current:HO8-NPxSP33 +Sensor_Current:HO8-NSM +Sensor_Current:HTFS200-P +Sensor_Current:HTFS400-P +Sensor_Current:HTFS600-P +Sensor_Current:HTFS800-P +Sensor_Current:HX02-P +Sensor_Current:HX03-P-SP2 +Sensor_Current:HX04-P +Sensor_Current:HX05-NP +Sensor_Current:HX05-P-SP2 +Sensor_Current:HX06-P +Sensor_Current:HX10-NP +Sensor_Current:HX10-P-SP2 +Sensor_Current:HX15-NP +Sensor_Current:HX15-P-SP2 +Sensor_Current:HX20-P-SP2 +Sensor_Current:HX25-P-SP2 +Sensor_Current:HX50-P-SP2 +Sensor_Current:IR2175 +Sensor_Current:IR21771S +Sensor_Current:IR2177S +Sensor_Current:IR22771S +Sensor_Current:IR2277S +Sensor_Current:IR25750L +Sensor_Current:LA100-P +Sensor_Current:LA25-NP +Sensor_Current:LA25-P +Sensor_Current:LA55-P +Sensor_Current:LTSR15-NP +Sensor_Current:LTSR25-NP +Sensor_Current:LTSR6-NP +Sensor_Current:MCA1101-20-3 +Sensor_Current:MCA1101-20-5 +Sensor_Current:MCA1101-5-3 +Sensor_Current:MCA1101-5-5 +Sensor_Current:MCA1101-50-3 +Sensor_Current:MCA1101-50-5 +Sensor_Current:MCA1101-65-5 +Sensor_Distance:TMF8820 +Sensor_Distance:TMF8821 +Sensor_Distance:TMF8828 +Sensor_Distance:VL53L0CXV0DH1 +Sensor_Distance:VL53L1CXV0FY1 +Sensor_Energy:ATM90E26-YU +Sensor_Energy:INA219AxD +Sensor_Energy:INA219AxDCN +Sensor_Energy:INA219BxD +Sensor_Energy:INA219BxDCN +Sensor_Energy:INA226 +Sensor_Energy:INA228 +Sensor_Energy:INA233 +Sensor_Energy:INA237 +Sensor_Energy:INA238 +Sensor_Energy:LTC4151xMS +Sensor_Energy:MCP39F521 +Sensor_Energy:PAC1931x-xJ6CX +Sensor_Energy:PAC1932x-xJ6CX +Sensor_Energy:PAC1932x-xJQ +Sensor_Energy:PAC1933x-xJ6CX +Sensor_Energy:PAC1933x-xJQ +Sensor_Energy:PAC1934x-xJ6CX +Sensor_Energy:PAC1934x-xJQ +Sensor_Energy:PAC1941x-1x-4MX +Sensor_Energy:PAC1941x-1x-J6CX +Sensor_Energy:PAC1941x-2x-4MX +Sensor_Energy:PAC1941x-2x-J6CX +Sensor_Energy:PAC1942x-1x-4MX +Sensor_Energy:PAC1942x-1x-J6CX +Sensor_Energy:PAC1942x-2x-4MX +Sensor_Energy:PAC1942x-2x-J6CX +Sensor_Energy:PAC1943x-x4MX +Sensor_Energy:PAC1943x-xJ6CX +Sensor_Energy:PAC1944x-x4MX +Sensor_Energy:PAC1944x-xJ6CX +Sensor_Energy:PAC1951x-1x-4MX +Sensor_Energy:PAC1951x-1x-J6CX +Sensor_Energy:PAC1951x-2x-4MX +Sensor_Energy:PAC1951x-2x-J6CX +Sensor_Energy:PAC1952x-1x-4MX +Sensor_Energy:PAC1952x-1x-J6CX +Sensor_Energy:PAC1952x-2x-4MX +Sensor_Energy:PAC1952x-2x-J6CX +Sensor_Energy:PAC1953x-x4MX +Sensor_Energy:PAC1953x-xJ6CX +Sensor_Energy:PAC1954x-x4MX +Sensor_Energy:PAC1954x-xJ6CX +Sensor_Gas:004-0-0010 +Sensor_Gas:004-0-0013 +Sensor_Gas:004-0-0050 +Sensor_Gas:004-0-0053 +Sensor_Gas:004-0-0071 +Sensor_Gas:004-0-0075 +Sensor_Gas:3SP-H2S-50_110-304 +Sensor_Gas:CCS811 +Sensor_Gas:GM-402B +Sensor_Gas:LuminOX_LOX-O2 +Sensor_Gas:MQ-6 +Sensor_Gas:MiCS-5524 +Sensor_Gas:SCD40-D-R2 +Sensor_Gas:SCD41-D-R2 +Sensor_Gas:TGS-5141 +Sensor_Humidity:ENS210 +Sensor_Humidity:HDC1080 +Sensor_Humidity:HDC2080 +Sensor_Humidity:SHT30-DIS +Sensor_Humidity:SHT30A-DIS +Sensor_Humidity:SHT31-DIS +Sensor_Humidity:SHT31A-DIS +Sensor_Humidity:SHT35-DIS +Sensor_Humidity:SHT35A-DIS +Sensor_Humidity:SHT4x +Sensor_Humidity:SHTC1 +Sensor_Humidity:SHTC3 +Sensor_Humidity:Si7020-A20 +Sensor_Humidity:Si7021-A20 +Sensor_Magnetic:A1101ELHL +Sensor_Magnetic:A1101LLHL +Sensor_Magnetic:A1102ELHL +Sensor_Magnetic:A1102LLHL +Sensor_Magnetic:A1103ELHL +Sensor_Magnetic:A1103LLHL +Sensor_Magnetic:A1104LLHL +Sensor_Magnetic:A1106LLHL +Sensor_Magnetic:A1301EUA-T +Sensor_Magnetic:A1301KLHLT-T +Sensor_Magnetic:A1301KUA-T +Sensor_Magnetic:A1302ELHLT-T +Sensor_Magnetic:A1302KLHLT-T +Sensor_Magnetic:A1302KUA-T +Sensor_Magnetic:A3214ELHLT-T +Sensor_Magnetic:AH1806-P +Sensor_Magnetic:AH1806-W +Sensor_Magnetic:AH1806-Z +Sensor_Magnetic:AK7452 +Sensor_Magnetic:AS5045B +Sensor_Magnetic:AS5047D +Sensor_Magnetic:AS5048A +Sensor_Magnetic:AS5048B +Sensor_Magnetic:AS5050A +Sensor_Magnetic:AS5055A +Sensor_Magnetic:BM1422AGMV +Sensor_Magnetic:BMM150 +Sensor_Magnetic:DRV5033AJxDBZ +Sensor_Magnetic:DRV5033AJxLPG +Sensor_Magnetic:DRV5033FAxDBZ +Sensor_Magnetic:DRV5033FAxLPG +Sensor_Magnetic:DRV5055A1xDBZxQ1 +Sensor_Magnetic:DRV5055A1xLPGxQ1 +Sensor_Magnetic:DRV5055A2xDBZxQ1 +Sensor_Magnetic:DRV5055A2xLPGxQ1 +Sensor_Magnetic:DRV5055A3xDBZxQ1 +Sensor_Magnetic:DRV5055A3xLPGxQ1 +Sensor_Magnetic:DRV5055A4xDBZxQ1 +Sensor_Magnetic:DRV5055A4xLPGxQ1 +Sensor_Magnetic:IST8308 +Sensor_Magnetic:IST8310 +Sensor_Magnetic:LIS2MDL +Sensor_Magnetic:LIS3MDL +Sensor_Magnetic:MA730 +Sensor_Magnetic:MMC5633NJL +Sensor_Magnetic:MMC5883MA +Sensor_Magnetic:MT6701CT +Sensor_Magnetic:MT6701QT +Sensor_Magnetic:MT6816CT +Sensor_Magnetic:SM351LT +Sensor_Magnetic:SM353LT +Sensor_Magnetic:Si7210-B-xx-IM2 +Sensor_Magnetic:Si7210-B-xx-IV +Sensor_Magnetic:TLE5012B +Sensor_Magnetic:TLV493D +Sensor_Magnetic:TMAG5110A2xxDBV +Sensor_Magnetic:TMAG5110A4xxDBV +Sensor_Magnetic:TMAG5110B2xxDBV +Sensor_Magnetic:TMAG5110B4xxDBV +Sensor_Magnetic:TMAG5110C2xxDBV +Sensor_Magnetic:TMAG5110C4xxDBV +Sensor_Magnetic:TMAG5111A2xxDBV +Sensor_Magnetic:TMAG5111A4xxDBV +Sensor_Magnetic:TMAG5111B2xxDBV +Sensor_Magnetic:TMAG5111B4xxDBV +Sensor_Magnetic:TMAG5111C2xxDBV +Sensor_Magnetic:TMAG5111C4xxDBV +Sensor_Magnetic:TMAG5170-Q1 +Sensor_Motion:ADXL343 +Sensor_Motion:ADXL363 +Sensor_Motion:BMF055 +Sensor_Motion:BMI160 +Sensor_Motion:BNO055 +Sensor_Motion:ICM-20602 +Sensor_Motion:ICM-20948 +Sensor_Motion:IIM-42652 +Sensor_Motion:IIS3DWB +Sensor_Motion:IPS2200 +Sensor_Motion:ISM330DHCX +Sensor_Motion:KX022-1020 +Sensor_Motion:KX122-1042 +Sensor_Motion:KX222-1054 +Sensor_Motion:KXTJ3-1057 +Sensor_Motion:L3GD20 +Sensor_Motion:LIS2DE12 +Sensor_Motion:LIS2DH +Sensor_Motion:LIS2HH12 +Sensor_Motion:LIS331HH +Sensor_Motion:LIS3DH +Sensor_Motion:LSM303C +Sensor_Motion:LSM303D +Sensor_Motion:LSM303DLHC +Sensor_Motion:LSM6DS3 +Sensor_Motion:LSM6DSL +Sensor_Motion:LSM6DSM +Sensor_Motion:LSM9DS1 +Sensor_Motion:MMA8653FCR1 +Sensor_Motion:MPU-6000 +Sensor_Motion:MPU-6050 +Sensor_Motion:MPU-9150 +Sensor_Motion:MPU-9250 +Sensor_Motion:SC7A20 +Sensor_Optical:A1050 +Sensor_Optical:A1060 +Sensor_Optical:A9013 +Sensor_Optical:A9050 +Sensor_Optical:A9060 +Sensor_Optical:APDS-9251-001 +Sensor_Optical:APDS-9301 +Sensor_Optical:APDS-9306 +Sensor_Optical:APDS-9306-065 +Sensor_Optical:AS7261 +Sensor_Optical:AS7262 +Sensor_Optical:AS7263 +Sensor_Optical:AS72651 +Sensor_Optical:AS7341DLG +Sensor_Optical:AS7343xDLG +Sensor_Optical:BP103 +Sensor_Optical:BP103B +Sensor_Optical:BP103BF +Sensor_Optical:BP104 +Sensor_Optical:BP104-SMD +Sensor_Optical:BPW21 +Sensor_Optical:BPW34 +Sensor_Optical:BPW34-SMD +Sensor_Optical:BPW40 +Sensor_Optical:BPW42 +Sensor_Optical:BPW82 +Sensor_Optical:BPW85 +Sensor_Optical:BPW85A +Sensor_Optical:BPW85B +Sensor_Optical:BPW85C +Sensor_Optical:BPX61 +Sensor_Optical:BPX65 +Sensor_Optical:BPY62 +Sensor_Optical:C12880MA +Sensor_Optical:Flir_LEPTON +Sensor_Optical:ISL29035 +Sensor_Optical:KPS-3227 +Sensor_Optical:KPS-5130 +Sensor_Optical:LDR03 +Sensor_Optical:LDR07 +Sensor_Optical:LPT80A +Sensor_Optical:LTR-303ALS-01 +Sensor_Optical:M9960 +Sensor_Optical:NOA1305 +Sensor_Optical:PMTx08Dyn +Sensor_Optical:PMTx08Dyn_Shld +Sensor_Optical:S13360-3025CS +Sensor_Optical:S13360-3050CS +Sensor_Optical:S13360-3075CS +Sensor_Optical:S5971 +Sensor_Optical:S5972 +Sensor_Optical:S5973 +Sensor_Optical:SFH203 +Sensor_Optical:SFH203FA +Sensor_Optical:SFH205F +Sensor_Optical:SFH205FA +Sensor_Optical:SFH206K +Sensor_Optical:SFH216 +Sensor_Optical:SFH225FA +Sensor_Optical:SFH235FA +Sensor_Optical:SFH2400 +Sensor_Optical:SFH2430 +Sensor_Optical:SFH2440 +Sensor_Optical:SFH2701 +Sensor_Optical:SFH300 +Sensor_Optical:SFH309 +Sensor_Optical:SFH320 +Sensor_Optical:SFH3201 +Sensor_Optical:TEPT4400 +Sensor_Optical:TSL2550D +Sensor_Optical:TSL2550T +Sensor_Optical:TSL25911FN +Sensor_Optical:VT93xx +Sensor_Pressure:40PC015G +Sensor_Pressure:40PC100G +Sensor_Pressure:40PC150G +Sensor_Pressure:40PC250G +Sensor_Pressure:BMP280 +Sensor_Pressure:LPS22DF +Sensor_Pressure:LPS22HB +Sensor_Pressure:LPS22HH +Sensor_Pressure:LPS25HB +Sensor_Pressure:MPL115A1 +Sensor_Pressure:MPL3115A2 +Sensor_Pressure:MPXA6115A +Sensor_Pressure:MPXAZ6115A +Sensor_Pressure:MPXH6115A +Sensor_Pressure:MPXHZ6115A +Sensor_Pressure:MS5525DSO +Sensor_Pressure:MS5607-02BA +Sensor_Pressure:MS5611-01BA +Sensor_Pressure:MS5837-xxBA +Sensor_Pressure:WSEN-PADS_2511020213301 +Sensor_Pressure:XGZP6897D +Sensor_Pressure:XGZP6899D +Sensor_Proximity:AD7150BRMZ +Sensor_Proximity:AD7151BRMZ +Sensor_Proximity:APDS-9160-003 +Sensor_Proximity:BPR-105 +Sensor_Proximity:BPR-105F +Sensor_Proximity:BPR-205 +Sensor_Proximity:CNY70 +Sensor_Proximity:GP2S700HCP +Sensor_Proximity:ITR1201SR10AR +Sensor_Proximity:ITR8307 +Sensor_Proximity:ITR8307-F43 +Sensor_Proximity:ITR8307-L24-TR8 +Sensor_Proximity:ITR8307-S17-TR8 +Sensor_Proximity:ITR9608-F +Sensor_Proximity:KRC011 +Sensor_Proximity:LDC1312 +Sensor_Proximity:LDC1314 +Sensor_Proximity:LDC1612 +Sensor_Proximity:LDC1614 +Sensor_Proximity:LG206D +Sensor_Proximity:LG206L +Sensor_Proximity:QRE1113 +Sensor_Proximity:QRE1113GR +Sensor_Proximity:RPR-0720 +Sensor_Proximity:SFH900 +Sensor_Proximity:SFH9201 +Sensor_Proximity:SFH9202 +Sensor_Proximity:SFH9206 +Sensor_Proximity:SG-105 +Sensor_Proximity:SG-105F +Sensor_Proximity:SG-107 +Sensor_Proximity:SG-107F +Sensor_Proximity:TSSP58038 +Sensor_Proximity:TSSP58038SS1XB +Sensor_Proximity:TSSP58P38 +Sensor_Temperature:AD8494 +Sensor_Temperature:AD8495 +Sensor_Temperature:AD8496 +Sensor_Temperature:AD8497 +Sensor_Temperature:BD1020HFV +Sensor_Temperature:DS1621 +Sensor_Temperature:DS1621S +Sensor_Temperature:DS1621V +Sensor_Temperature:DS1804 +Sensor_Temperature:DS1821C +Sensor_Temperature:DS1822 +Sensor_Temperature:DS1822-PAR +Sensor_Temperature:DS1822Z +Sensor_Temperature:DS1825 +Sensor_Temperature:DS18B20 +Sensor_Temperature:DS18B20-PAR +Sensor_Temperature:DS18B20U +Sensor_Temperature:DS18B20Z +Sensor_Temperature:DS18S20 +Sensor_Temperature:DS18S20-PAR +Sensor_Temperature:DS18S20Z +Sensor_Temperature:DS28EA00 +Sensor_Temperature:KT100 +Sensor_Temperature:KTY10 +Sensor_Temperature:KTY81 +Sensor_Temperature:KTY82 +Sensor_Temperature:KTY83 +Sensor_Temperature:KTY84 +Sensor_Temperature:KTY85 +Sensor_Temperature:LM20BIM7 +Sensor_Temperature:LM20CIM7 +Sensor_Temperature:LM35-D +Sensor_Temperature:LM35-LP +Sensor_Temperature:LM35-NEB +Sensor_Temperature:LM73 +Sensor_Temperature:LM73-1 +Sensor_Temperature:LM74CIM +Sensor_Temperature:LM74CITP +Sensor_Temperature:LM75B +Sensor_Temperature:LM75C +Sensor_Temperature:LM92CIM +Sensor_Temperature:LM94021 +Sensor_Temperature:LMT01DQX +Sensor_Temperature:LMT01LPG +Sensor_Temperature:LMT84DCK +Sensor_Temperature:LMT85DCK +Sensor_Temperature:LMT86DCK +Sensor_Temperature:LMT87DCK +Sensor_Temperature:LTC2983 +Sensor_Temperature:MAX31820 +Sensor_Temperature:MAX31820PAR +Sensor_Temperature:MAX31826 +Sensor_Temperature:MAX31855EASA +Sensor_Temperature:MAX31855JASA +Sensor_Temperature:MAX31855KASA +Sensor_Temperature:MAX31855NASA +Sensor_Temperature:MAX31855RASA +Sensor_Temperature:MAX31855SASA +Sensor_Temperature:MAX31855TASA +Sensor_Temperature:MAX31856 +Sensor_Temperature:MAX31865xAP +Sensor_Temperature:MAX31865xTP +Sensor_Temperature:MAX6654 +Sensor_Temperature:MCP9501 +Sensor_Temperature:MCP9502 +Sensor_Temperature:MCP9503 +Sensor_Temperature:MCP9504 +Sensor_Temperature:MCP9700Ax-ELT +Sensor_Temperature:MCP9700Ax-ETT +Sensor_Temperature:MCP9700Ax-HLT +Sensor_Temperature:MCP9700Ax-HTT +Sensor_Temperature:MCP9700x-ELT +Sensor_Temperature:MCP9700x-ETT +Sensor_Temperature:MCP9700x-HLT +Sensor_Temperature:MCP9700x-HTT +Sensor_Temperature:MCP9800Ax-xOT +Sensor_Temperature:MCP9802Ax-xOT +Sensor_Temperature:MCP9804_DFN +Sensor_Temperature:MCP9804_MSOP +Sensor_Temperature:MCP9808_DFN +Sensor_Temperature:MCP9808_MSOP +Sensor_Temperature:MCP9844x-xMN +Sensor_Temperature:PCT2075D +Sensor_Temperature:PCT2075DP +Sensor_Temperature:PT100 +Sensor_Temperature:PT1000 +Sensor_Temperature:PT500 +Sensor_Temperature:Si7050-A20 +Sensor_Temperature:Si7051-A20 +Sensor_Temperature:Si7053-A20 +Sensor_Temperature:Si7054-A20 +Sensor_Temperature:Si7055-A20 +Sensor_Temperature:TC1047AxNB +Sensor_Temperature:TC1047xNB +Sensor_Temperature:TMP100 +Sensor_Temperature:TMP101 +Sensor_Temperature:TMP102xxDRL +Sensor_Temperature:TMP1075D +Sensor_Temperature:TMP1075DGK +Sensor_Temperature:TMP1075DSG +Sensor_Temperature:TMP110D +Sensor_Temperature:TMP112xxDRL +Sensor_Temperature:TMP114 +Sensor_Temperature:TMP116xxDRV +Sensor_Temperature:TMP117xxDRV +Sensor_Temperature:TMP117xxYBG +Sensor_Temperature:TMP119AIYBGR +Sensor_Temperature:TMP20AIDCK +Sensor_Temperature:TMP20AIDRL +Sensor_Temperature:TMP36xS +Sensor_Temperature:TMP411 +Sensor_Temperature:TMP461xxRUN +Sensor_Temperature:TMP464xxRGT +Sensor_Temperature:TMP468xxRGT +Sensor_Temperature:TSIC206-SO8 +Sensor_Temperature:TSIC206-TO92 +Sensor_Temperature:TSIC306-SO8 +Sensor_Temperature:TSIC306-TO92 +Sensor_Touch:AT42QT1010-M +Sensor_Touch:AT42QT1010-TSHR +Sensor_Touch:AT42QT1011-M +Sensor_Touch:AT42QT1011-TSHR +Sensor_Touch:AT42QT1012-M +Sensor_Touch:AT42QT1012-T +Sensor_Touch:AT42QT1040-M +Sensor_Touch:AT42QT1050-M +Sensor_Touch:AT42QT1050-U +Sensor_Touch:AT42QT1060-M +Sensor_Touch:AT42QT1070-M +Sensor_Touch:AT42QT1070-S +Sensor_Touch:AT42QT1110-M +Sensor_Touch:CAP1206-x-AIA +Sensor_Touch:CAP1206-x-SL +Sensor_Touch:CY8CMBR3002 +Sensor_Touch:CY8CMBR3102 +Sensor_Touch:CY8CMBR3106S +Sensor_Touch:CY8CMBR3108 +Sensor_Touch:CY8CMBR3110 +Sensor_Touch:CY8CMBR3116 +Sensor_Touch:MPR121QR2 +Sensor_Touch:PCA8886 +Sensor_Touch:PCF8883 +Sensor_Voltage:LV25-P +Simulation_SPICE:0 +Simulation_SPICE:BSOURCE +Simulation_SPICE:D +Simulation_SPICE:ESOURCE +Simulation_SPICE:GSOURCE +Simulation_SPICE:IAM +Simulation_SPICE:IBIS_DEVICE +Simulation_SPICE:IBIS_DEVICE_DIFF +Simulation_SPICE:IBIS_DRIVER +Simulation_SPICE:IBIS_DRIVER_DIFF +Simulation_SPICE:IDC +Simulation_SPICE:IEXP +Simulation_SPICE:IPULSE +Simulation_SPICE:IPWL +Simulation_SPICE:ISFFM +Simulation_SPICE:ISIN +Simulation_SPICE:ITRNOISE +Simulation_SPICE:ITRRANDOM +Simulation_SPICE:NJFET +Simulation_SPICE:NMOS +Simulation_SPICE:NMOS_Substrate +Simulation_SPICE:NPN +Simulation_SPICE:NPN_Substrate +Simulation_SPICE:OPAMP +Simulation_SPICE:PJFET +Simulation_SPICE:PMOS +Simulation_SPICE:PMOS_Substrate +Simulation_SPICE:PNP +Simulation_SPICE:PNP_Substrate +Simulation_SPICE:SWITCH +Simulation_SPICE:TLINE +Simulation_SPICE:VAM +Simulation_SPICE:VDC +Simulation_SPICE:VEXP +Simulation_SPICE:VOLTMETER_DIFF +Simulation_SPICE:VPULSE +Simulation_SPICE:VPWL +Simulation_SPICE:VSFFM +Simulation_SPICE:VSIN +Simulation_SPICE:VTRNOISE +Simulation_SPICE:VTRRANDOM +Switch:CK_KMS2xxG +Switch:CK_KMS2xxGP +Switch:SW_Coded +Switch:SW_Coded_SH-7010 +Switch:SW_Coded_SH-7030 +Switch:SW_Coded_SH-7040 +Switch:SW_Coded_SH-7050 +Switch:SW_Coded_SH-7070 +Switch:SW_Coded_SH-7080 +Switch:SW_DIP_x01 +Switch:SW_DIP_x02 +Switch:SW_DIP_x03 +Switch:SW_DIP_x04 +Switch:SW_DIP_x05 +Switch:SW_DIP_x06 +Switch:SW_DIP_x07 +Switch:SW_DIP_x08 +Switch:SW_DIP_x09 +Switch:SW_DIP_x10 +Switch:SW_DIP_x11 +Switch:SW_DIP_x12 +Switch:SW_DP3T +Switch:SW_DPDT_x2 +Switch:SW_DPST +Switch:SW_DPST_Temperature +Switch:SW_DPST_x2 +Switch:SW_E3_SA3216 +Switch:SW_E3_SA3624 +Switch:SW_E3_SA6432 +Switch:SW_MEC_5E +Switch:SW_MEC_5G +Switch:SW_MEC_5G_2LED +Switch:SW_MEC_5G_LED +Switch:SW_MMI_Q5-100 +Switch:SW_NKK_GW12LJPCF +Switch:SW_Nidec_CAS-120A1 +Switch:SW_Omron_B3FS +Switch:SW_Push +Switch:SW_Push_45deg +Switch:SW_Push_DPDT +Switch:SW_Push_Dual +Switch:SW_Push_Dual_x2 +Switch:SW_Push_LED +Switch:SW_Push_Lamp +Switch:SW_Push_Open +Switch:SW_Push_Open_Dual +Switch:SW_Push_Open_Dual_x2 +Switch:SW_Push_SPDT +Switch:SW_Push_Shielded +Switch:SW_Reed +Switch:SW_Reed_Opener +Switch:SW_Reed_SPDT +Switch:SW_Rotary_1x12 +Switch:SW_Rotary_1x3_MP +Switch:SW_Rotary_1x4_MP +Switch:SW_Rotary_1x5_MP +Switch:SW_Rotary_1x6_MP +Switch:SW_Rotary_1x7_MP +Switch:SW_Rotary_1x8_MP +Switch:SW_Rotary_1x9_MP +Switch:SW_Rotary_2x6 +Switch:SW_Rotary_3x4 +Switch:SW_Rotary_4x3 +Switch:SW_SP3T +Switch:SW_SP3T_NR01103 +Switch:SW_SP4T_NR01104 +Switch:SW_SP5T_NR01105 +Switch:SW_SPDT +Switch:SW_SPDT_312 +Switch:SW_SPDT_321 +Switch:SW_SPDT_MSM +Switch:SW_SPDT_XKB_DMx-xxxx-1 +Switch:SW_SPST +Switch:SW_SPST_LED +Switch:SW_SPST_Lamp +Switch:SW_SPST_Temperature +Switch:SW_Slide_DPDT +Switch:SW_Wuerth_450301014042 +Timer:8253 +Timer:8254 +Timer:8284 +Timer:82C54 +Timer:82C54_PLCC +Timer:AD9513 +Timer:AD9514 +Timer:AD9515 +Timer:CD4541BE +Timer:CD4541BM +Timer:CD4541BPW +Timer:DS1023S +Timer:ICM7209 +Timer:ICM7555xB +Timer:ICM7555xP +Timer:ICM7556 +Timer:LM555xM +Timer:LM555xMM +Timer:LM555xN +Timer:LM556 +Timer:LMC555xM +Timer:LMC555xMM +Timer:LMC555xN +Timer:LMC555xTP +Timer:LTC6902 +Timer:LTC6909 +Timer:LTC6993xS6-1 +Timer:LTC6993xS6-2 +Timer:LTC6993xS6-3 +Timer:LTC6993xS6-4 +Timer:LTC6994xDCB-1 +Timer:LTC6994xDCB-2 +Timer:LTC6994xS6-1 +Timer:LTC6994xS6-2 +Timer:MC14541BD +Timer:MC14541BDT +Timer:MC1455B +Timer:MC1455P +Timer:MN3101 +Timer:MN3102 +Timer:NA555D +Timer:NA555P +Timer:NA556 +Timer:NE555D +Timer:NE555P +Timer:NE556 +Timer:NE567 +Timer:NLV14541BD +Timer:NLV14541BDT +Timer:PL611-01-xxxT +Timer:SA555D +Timer:SA555P +Timer:SA556 +Timer:SE555D +Timer:SE555P +Timer:SE556 +Timer:SE567 +Timer:SY58031U +Timer:SY58032U +Timer:SY58033U +Timer:TLC555xD +Timer:TLC555xP +Timer:TLC555xPS +Timer:TLC555xPW +Timer:TPL5010 +Timer:TPL5110 +Timer:TPL5111 +Timer_PLL:ADF4002BCPZ +Timer_PLL:ADF4002BRUZ +Timer_PLL:ADF4158 +Timer_PLL:ADF4350 +Timer_PLL:ADF4351 +Timer_PLL:CDCVF2505 +Timer_PLL:CS2000-CP +Timer_PLL:ICS525-01R +Timer_PLL:ICS525R-02 +Timer_PLL:Si5342A-D +Timer_PLL:Si5342B-D +Timer_PLL:Si5342C-D +Timer_PLL:Si5342D-D +Timer_PLL:Si5344A-D +Timer_PLL:Si5344B-D +Timer_PLL:Si5344C-D +Timer_PLL:Si5344D-D +Timer_PLL:Si5345A-D +Timer_PLL:Si5345B-D +Timer_PLL:Si5345C-D +Timer_PLL:Si5345D-D +Timer_RTC:AB0805 +Timer_RTC:AB0815 +Timer_RTC:AB1805 +Timer_RTC:AB1815 +Timer_RTC:BQ32000 +Timer_RTC:BQ32002 +Timer_RTC:DS1302+ +Timer_RTC:DS1302N+ +Timer_RTC:DS1302S+ +Timer_RTC:DS1302SN+ +Timer_RTC:DS1302Z+ +Timer_RTC:DS1302ZN+ +Timer_RTC:DS1307+ +Timer_RTC:DS1307N+ +Timer_RTC:DS1307Z+ +Timer_RTC:DS1307ZN+ +Timer_RTC:DS1602 +Timer_RTC:DS3231M +Timer_RTC:DS3231MZ +Timer_RTC:DS3232M +Timer_RTC:M41T62Q +Timer_RTC:MCP7940N-xMNY +Timer_RTC:MCP7940N-xMS +Timer_RTC:MCP7940N-xP +Timer_RTC:MCP7940N-xSN +Timer_RTC:MCP7940N-xST +Timer_RTC:PCF85063ATL +Timer_RTC:PCF8523T +Timer_RTC:PCF8523TK +Timer_RTC:PCF8523TS +Timer_RTC:PCF85263AT +Timer_RTC:PCF85263ATL +Timer_RTC:PCF85263ATT +Timer_RTC:PCF85263ATT1 +Timer_RTC:PCF85363ATT +Timer_RTC:PCF85363ATT1 +Timer_RTC:PCF8563T +Timer_RTC:PCF8563TS +Timer_RTC:RV-1805-C3 +Timer_RTC:RV-3028-C7 +Timer_RTC:RV-8523-C3 +Timer_RTC:RX8901CE +Transformer:0433BM15A0001 +Transformer:0868BM15C0001 +Transformer:0896BM15A0001 +Transformer:0915BM15A0001 +Transformer:30F-51NL +Transformer:5400BL15B050 +Transformer:ADT1-1 +Transformer:ADT1-1WT +Transformer:ADT1-1WT-1 +Transformer:ADT1-6T +Transformer:ADT1.5-1 +Transformer:ADT1.5-122 +Transformer:ADT1.5-17 +Transformer:ADT1.5-2 +Transformer:ADT16-1T +Transformer:ADT16-6 +Transformer:ADT16-6T +Transformer:ADT2-1T +Transformer:ADT2-1T-1P +Transformer:ADT2-71T +Transformer:ADT3-1T +Transformer:ADT3-1T-75 +Transformer:ADT3-6T +Transformer:ADT4-1T +Transformer:ADT4-1WT +Transformer:ADT4-5WT +Transformer:ADT4-6 +Transformer:ADT4-6T +Transformer:ADT4-6WT +Transformer:ADT8-1T +Transformer:ADT9-1T +Transformer:ADTL1-12 +Transformer:ADTL1-15-75 +Transformer:ADTL1-18-75 +Transformer:ADTL1-4-75 +Transformer:ADTL2-18 +Transformer:ADTT1-1 +Transformer:ADTT1-6 +Transformer:ADTT1.5-1 +Transformer:ADTT3-2 +Transformer:ADTT4-1 +Transformer:B0322J5050AHF +Transformer:CST1 +Transformer:CST1_Split +Transformer:CST2 +Transformer:CST2010 +Transformer:CST2010_Split +Transformer:CST2_Split +Transformer:ED8_4 +Transformer:ETC1-1-13 +Transformer:LL1587 +Transformer:P0544NL +Transformer:P0926NL +Transformer:PA0173NL +Transformer:PA0184NL +Transformer:PA0184NL1 +Transformer:PA0185NL +Transformer:PA0185NL1 +Transformer:PA0264NL +Transformer:PA0297NL +Transformer:PA0510NL +Transformer:PA1323NL +Transformer:PA2001NL +Transformer:PA2002NL +Transformer:PA2004NL +Transformer:PA2005NL +Transformer:PA2006NL +Transformer:PA2007NL +Transformer:PA2008NL +Transformer:PA2009NL +Transformer:PA2777NL +Transformer:PA3493NL +Transformer:PE-68386NL +Transformer:PT61017PEL +Transformer:PT61020EL +Transformer:TC1-1-13M+ +Transformer:TEZ0.5-D-1 +Transformer:TEZ0.5-D-2 +Transformer:TEZ1.5-D-1 +Transformer:TEZ1.5-D-2 +Transformer:TEZ10.0-D-1 +Transformer:TEZ10.0-D-2 +Transformer:TEZ16.0-D-1 +Transformer:TEZ16.0-D-2 +Transformer:TEZ2.0-D-1 +Transformer:TEZ2.0-D-2 +Transformer:TEZ2.5-D-1 +Transformer:TEZ2.5-D-2 +Transformer:TEZ2.6-D-1 +Transformer:TEZ2.6-D-2 +Transformer:TEZ4.0-D-1 +Transformer:TEZ4.0-D-2 +Transformer:TEZ6.0-D-1 +Transformer:TEZ6.0-D-2 +Transformer:TG110-E050N5xx +Transformer:TG110-S050N2xx +Transformer:TG111-MSC13LF +Transformer:TR1-SO8 +Transformer:TR60_FC +Transformer:TR60_IC +Transformer:TR60_IC2 +Transformer:TRANSF1 +Transformer:TRANSF2 +Transformer:TRANSF3 +Transformer:TRANSF4 +Transformer:TRANSF5 +Transformer:TRANSF6 +Transformer:TRANSF7 +Transformer:TRANSF8 +Transformer:Triad_VPP16-310 +Transformer:Wuerth_749013011A +Transformer:Wuerth_750315371 +Transformer:Wuerth_750343373 +Transformer:Wuerth_760871131 +Transformer:Wurth_750319177 +Transformer:ZMCT103C +Transformer:ZMPT101K +Transistor_Array:A2982 +Transistor_Array:MC1413BD +Transistor_Array:MC1413BP +Transistor_Array:MC1413D +Transistor_Array:MC1413P +Transistor_Array:NCV1413B +Transistor_Array:SN75468 +Transistor_Array:SN75469 +Transistor_Array:TBD62783A +Transistor_Array:TBD62785AFWG +Transistor_Array:TBD62785APG +Transistor_Array:ULN2002 +Transistor_Array:ULN2002A +Transistor_Array:ULN2003 +Transistor_Array:ULN2003A +Transistor_Array:ULN2004 +Transistor_Array:ULN2004A +Transistor_Array:ULN2801A +Transistor_Array:ULN2802A +Transistor_Array:ULN2803A +Transistor_Array:ULN2804A +Transistor_Array:ULN2805A +Transistor_Array:ULQ2003A +Transistor_Array:ULQ2004A +Transistor_BJT:2N2219 +Transistor_BJT:2N2646 +Transistor_BJT:2N2647 +Transistor_BJT:2N3055 +Transistor_BJT:2N3904 +Transistor_BJT:2N3905 +Transistor_BJT:2N3906 +Transistor_BJT:2SA1015 +Transistor_BJT:2SB631 +Transistor_BJT:2SB817 +Transistor_BJT:2SC1815 +Transistor_BJT:2SC1941 +Transistor_BJT:2SC1945 +Transistor_BJT:2SC4213 +Transistor_BJT:2SD1047 +Transistor_BJT:2SD600 +Transistor_BJT:320S14-U +Transistor_BJT:BC107 +Transistor_BJT:BC108 +Transistor_BJT:BC109 +Transistor_BJT:BC140 +Transistor_BJT:BC141 +Transistor_BJT:BC160 +Transistor_BJT:BC161 +Transistor_BJT:BC212 +Transistor_BJT:BC237 +Transistor_BJT:BC240 +Transistor_BJT:BC307 +Transistor_BJT:BC327 +Transistor_BJT:BC328 +Transistor_BJT:BC337 +Transistor_BJT:BC338 +Transistor_BJT:BC413 +Transistor_BJT:BC413B +Transistor_BJT:BC413C +Transistor_BJT:BC414 +Transistor_BJT:BC414B +Transistor_BJT:BC414C +Transistor_BJT:BC516 +Transistor_BJT:BC517 +Transistor_BJT:BC546 +Transistor_BJT:BC547 +Transistor_BJT:BC548 +Transistor_BJT:BC549 +Transistor_BJT:BC550 +Transistor_BJT:BC556 +Transistor_BJT:BC557 +Transistor_BJT:BC558 +Transistor_BJT:BC559 +Transistor_BJT:BC560 +Transistor_BJT:BC636 +Transistor_BJT:BC807 +Transistor_BJT:BC807W +Transistor_BJT:BC808 +Transistor_BJT:BC808W +Transistor_BJT:BC817 +Transistor_BJT:BC817W +Transistor_BJT:BC818 +Transistor_BJT:BC818W +Transistor_BJT:BC846 +Transistor_BJT:BC846BDW1 +Transistor_BJT:BC846BPDW1 +Transistor_BJT:BC846BPN +Transistor_BJT:BC846BS +Transistor_BJT:BC847 +Transistor_BJT:BC847BDW1 +Transistor_BJT:BC847BPDW1 +Transistor_BJT:BC847BPN +Transistor_BJT:BC847BS +Transistor_BJT:BC847W +Transistor_BJT:BC848 +Transistor_BJT:BC848W +Transistor_BJT:BC849 +Transistor_BJT:BC849W +Transistor_BJT:BC850 +Transistor_BJT:BC850W +Transistor_BJT:BC856 +Transistor_BJT:BC856BDW1 +Transistor_BJT:BC856BS +Transistor_BJT:BC856W +Transistor_BJT:BC857 +Transistor_BJT:BC857BDW1 +Transistor_BJT:BC857BS +Transistor_BJT:BC857W +Transistor_BJT:BC858 +Transistor_BJT:BC858W +Transistor_BJT:BC859 +Transistor_BJT:BC859W +Transistor_BJT:BC860 +Transistor_BJT:BC860W +Transistor_BJT:BCP51 +Transistor_BJT:BCP53 +Transistor_BJT:BCP56 +Transistor_BJT:BCV29 +Transistor_BJT:BCV49 +Transistor_BJT:BCV61 +Transistor_BJT:BCV62 +Transistor_BJT:BCX51 +Transistor_BJT:BCX52 +Transistor_BJT:BCX53 +Transistor_BJT:BCX56 +Transistor_BJT:BD135 +Transistor_BJT:BD136 +Transistor_BJT:BD137 +Transistor_BJT:BD138 +Transistor_BJT:BD139 +Transistor_BJT:BD140 +Transistor_BJT:BD233 +Transistor_BJT:BD234 +Transistor_BJT:BD235 +Transistor_BJT:BD236 +Transistor_BJT:BD237 +Transistor_BJT:BD238 +Transistor_BJT:BD249 +Transistor_BJT:BD249A +Transistor_BJT:BD249B +Transistor_BJT:BD249C +Transistor_BJT:BD250 +Transistor_BJT:BD250A +Transistor_BJT:BD250B +Transistor_BJT:BD250C +Transistor_BJT:BD433 +Transistor_BJT:BD434 +Transistor_BJT:BD435 +Transistor_BJT:BD436 +Transistor_BJT:BD437 +Transistor_BJT:BD438 +Transistor_BJT:BD439 +Transistor_BJT:BD440 +Transistor_BJT:BD441 +Transistor_BJT:BD442 +Transistor_BJT:BD909 +Transistor_BJT:BD910 +Transistor_BJT:BD911 +Transistor_BJT:BD912 +Transistor_BJT:BDW93 +Transistor_BJT:BDW93A +Transistor_BJT:BDW93B +Transistor_BJT:BDW93C +Transistor_BJT:BDW94 +Transistor_BJT:BDW94A +Transistor_BJT:BDW94B +Transistor_BJT:BDW94C +Transistor_BJT:BF199 +Transistor_BJT:BF457 +Transistor_BJT:BF458 +Transistor_BJT:BF459 +Transistor_BJT:BFR92 +Transistor_BJT:BFT92 +Transistor_BJT:BUT11 +Transistor_BJT:BUT11A +Transistor_BJT:DMMT5401 +Transistor_BJT:DTA113T +Transistor_BJT:DTA113Z +Transistor_BJT:DTA114E +Transistor_BJT:DTA114G +Transistor_BJT:DTA114T +Transistor_BJT:DTA114W +Transistor_BJT:DTA114Y +Transistor_BJT:DTA115E +Transistor_BJT:DTA115G +Transistor_BJT:DTA115T +Transistor_BJT:DTA115U +Transistor_BJT:DTA123E +Transistor_BJT:DTA123J +Transistor_BJT:DTA123Y +Transistor_BJT:DTA124E +Transistor_BJT:DTA124G +Transistor_BJT:DTA124T +Transistor_BJT:DTA124X +Transistor_BJT:DTA125T +Transistor_BJT:DTA143E +Transistor_BJT:DTA143T +Transistor_BJT:DTA143X +Transistor_BJT:DTA143Y +Transistor_BJT:DTA143Z +Transistor_BJT:DTA144E +Transistor_BJT:DTA144G +Transistor_BJT:DTA144T +Transistor_BJT:DTA144V +Transistor_BJT:DTA144W +Transistor_BJT:DTA1D3R +Transistor_BJT:DTA214Y +Transistor_BJT:DTB113E +Transistor_BJT:DTB113Z +Transistor_BJT:DTB114E +Transistor_BJT:DTB114G +Transistor_BJT:DTB114T +Transistor_BJT:DTB122J +Transistor_BJT:DTB123E +Transistor_BJT:DTB123T +Transistor_BJT:DTB123Y +Transistor_BJT:DTB133H +Transistor_BJT:DTB143T +Transistor_BJT:DTB163T +Transistor_BJT:DTC113T +Transistor_BJT:DTC113Z +Transistor_BJT:DTC114E +Transistor_BJT:DTC114G +Transistor_BJT:DTC114T +Transistor_BJT:DTC114W +Transistor_BJT:DTC114Y +Transistor_BJT:DTC115E +Transistor_BJT:DTC115G +Transistor_BJT:DTC115T +Transistor_BJT:DTC115U +Transistor_BJT:DTC123E +Transistor_BJT:DTC123J +Transistor_BJT:DTC123Y +Transistor_BJT:DTC124E +Transistor_BJT:DTC124G +Transistor_BJT:DTC124T +Transistor_BJT:DTC124X +Transistor_BJT:DTC125T +Transistor_BJT:DTC143E +Transistor_BJT:DTC143T +Transistor_BJT:DTC143X +Transistor_BJT:DTC143Y +Transistor_BJT:DTC143Z +Transistor_BJT:DTC144E +Transistor_BJT:DTC144G +Transistor_BJT:DTC144T +Transistor_BJT:DTC144V +Transistor_BJT:DTC144W +Transistor_BJT:DTC1D3R +Transistor_BJT:DTC214Y +Transistor_BJT:DTD113E +Transistor_BJT:DTD113Z +Transistor_BJT:DTD114E +Transistor_BJT:DTD114G +Transistor_BJT:DTD114T +Transistor_BJT:DTD122J +Transistor_BJT:DTD123E +Transistor_BJT:DTD123T +Transistor_BJT:DTD123Y +Transistor_BJT:DTD133H +Transistor_BJT:DTD143T +Transistor_BJT:DTD163T +Transistor_BJT:EMH3 +Transistor_BJT:FFB2222A +Transistor_BJT:FFB2227A +Transistor_BJT:FFB3904 +Transistor_BJT:FFB3906 +Transistor_BJT:FFB3946 +Transistor_BJT:FFB5551 +Transistor_BJT:FMB2227A +Transistor_BJT:FMB3946 +Transistor_BJT:IMH3A +Transistor_BJT:KTD1624 +Transistor_BJT:MAT02 +Transistor_BJT:MBT2222ADW1T1 +Transistor_BJT:MBT3904DW1 +Transistor_BJT:MBT3906DW1 +Transistor_BJT:MBT3946DW1T1 +Transistor_BJT:MJ2955 +Transistor_BJT:MJE13003 +Transistor_BJT:MJE13005G +Transistor_BJT:MJE13007G +Transistor_BJT:MJE13009G +Transistor_BJT:MMBT2222A +Transistor_BJT:MMBT3904 +Transistor_BJT:MMBT3906 +Transistor_BJT:MMBT5550L +Transistor_BJT:MMBT5551L +Transistor_BJT:MMBTA06 +Transistor_BJT:MMBTA42 +Transistor_BJT:MMBTA44 +Transistor_BJT:MMBTA56 +Transistor_BJT:MMBTA92 +Transistor_BJT:MMBTA94 +Transistor_BJT:MMDT2222A +Transistor_BJT:MMDT3904 +Transistor_BJT:MMDT3906 +Transistor_BJT:MMDT3946 +Transistor_BJT:MMDT5401 +Transistor_BJT:MMDT5551 +Transistor_BJT:MMDTA06 +Transistor_BJT:MPSA42 +Transistor_BJT:MPSA92 +Transistor_BJT:MUN5111DW1 +Transistor_BJT:MUN5112DW1 +Transistor_BJT:MUN5113DW1 +Transistor_BJT:MUN5114DW1 +Transistor_BJT:MUN5211DW1 +Transistor_BJT:MUN5212DW1 +Transistor_BJT:MUN5213DW1 +Transistor_BJT:MUN5214DW1 +Transistor_BJT:MUN5311DW1 +Transistor_BJT:MUN5312DW1 +Transistor_BJT:MUN5313DW1 +Transistor_BJT:MUN5314DW1 +Transistor_BJT:MUN5330DW1 +Transistor_BJT:MUN5331DW1 +Transistor_BJT:MUN5332DW1 +Transistor_BJT:MUN5333DW1 +Transistor_BJT:MUN5334DW1 +Transistor_BJT:MUN5335DW1 +Transistor_BJT:MUN5336DW1 +Transistor_BJT:PBSS301PZ +Transistor_BJT:PMBT2222A +Transistor_BJT:PMBT2222AYS +Transistor_BJT:PMBT3904YS +Transistor_BJT:PMBT3906YS +Transistor_BJT:PMBT3946YPN +Transistor_BJT:PN2222A +Transistor_BJT:PUMT1 +Transistor_BJT:PUMX1 +Transistor_BJT:PZT2222A +Transistor_BJT:PZT3904 +Transistor_BJT:PZT3906 +Transistor_BJT:PZTA42 +Transistor_BJT:PZTA92 +Transistor_BJT:Q_Dual_NPN_C2C1E1E2 +Transistor_BJT:Q_Dual_NPN_NPN_B1E2B2C2E1C1 +Transistor_BJT:Q_Dual_NPN_NPN_BRT_E1B1C2E2B2C1 +Transistor_BJT:Q_Dual_NPN_NPN_BRT_No_R2_C1B2E2C2B1E1 +Transistor_BJT:Q_Dual_NPN_NPN_BRT_No_R2_E1B1C2E2B2C1 +Transistor_BJT:Q_Dual_NPN_NPN_C1E1C2E2B2B1 +Transistor_BJT:Q_Dual_NPN_NPN_E1B1C2E2B2C1 +Transistor_BJT:Q_Dual_NPN_PNP_B1E2B2C2E1C1 +Transistor_BJT:Q_Dual_NPN_PNP_BRT_E1B1C2E2B2C1 +Transistor_BJT:Q_Dual_NPN_PNP_E1B1C2E2B2C1 +Transistor_BJT:Q_Dual_PNP_C2C1E1E2 +Transistor_BJT:Q_Dual_PNP_NPN_BRT_E1B1C2E2B2C1 +Transistor_BJT:Q_Dual_PNP_PNP_BRT_E1B1C2E2B2C1 +Transistor_BJT:Q_Dual_PNP_PNP_C1B1B2C2E2E1 +Transistor_BJT:Q_Dual_PNP_PNP_C1E1C2E2B2B1 +Transistor_BJT:Q_Dual_PNP_PNP_E1B1C2E2B2C1 +Transistor_BJT:Q_NPN_BCE +Transistor_BJT:Q_NPN_BCEC +Transistor_BJT:Q_NPN_BEC +Transistor_BJT:Q_NPN_BRT_BEC +Transistor_BJT:Q_NPN_BRT_ECB +Transistor_BJT:Q_NPN_CBE +Transistor_BJT:Q_NPN_CEB +Transistor_BJT:Q_NPN_Darlington_BCE +Transistor_BJT:Q_NPN_Darlington_BCEC +Transistor_BJT:Q_NPN_Darlington_BEC +Transistor_BJT:Q_NPN_Darlington_CBE +Transistor_BJT:Q_NPN_Darlington_CEB +Transistor_BJT:Q_NPN_Darlington_EBC +Transistor_BJT:Q_NPN_Darlington_ECB +Transistor_BJT:Q_NPN_Darlington_ECBC +Transistor_BJT:Q_NPN_EBC +Transistor_BJT:Q_NPN_ECB +Transistor_BJT:Q_NPN_ECBC +Transistor_BJT:Q_PNP_BCE +Transistor_BJT:Q_PNP_BCEC +Transistor_BJT:Q_PNP_BEC +Transistor_BJT:Q_PNP_BRT_BEC +Transistor_BJT:Q_PNP_BRT_ECB +Transistor_BJT:Q_PNP_CBE +Transistor_BJT:Q_PNP_CEB +Transistor_BJT:Q_PNP_Darlington_BCE +Transistor_BJT:Q_PNP_Darlington_BCEC +Transistor_BJT:Q_PNP_Darlington_BEC +Transistor_BJT:Q_PNP_Darlington_CBE +Transistor_BJT:Q_PNP_Darlington_CEB +Transistor_BJT:Q_PNP_Darlington_EBC +Transistor_BJT:Q_PNP_Darlington_ECB +Transistor_BJT:Q_PNP_Darlington_ECBC +Transistor_BJT:Q_PNP_EBC +Transistor_BJT:Q_PNP_ECB +Transistor_BJT:Q_PNP_ECBC +Transistor_BJT:S8050 +Transistor_BJT:S8550 +Transistor_BJT:SS8050 +Transistor_BJT:SS8550 +Transistor_BJT:SSM2210 +Transistor_BJT:SSM2220 +Transistor_BJT:TIP120 +Transistor_BJT:TIP121 +Transistor_BJT:TIP122 +Transistor_BJT:TIP125 +Transistor_BJT:TIP126 +Transistor_BJT:TIP127 +Transistor_BJT:TIP2955 +Transistor_BJT:TIP2955G +Transistor_BJT:TIP3055 +Transistor_BJT:TIP3055G +Transistor_BJT:TIP41 +Transistor_BJT:TIP41A +Transistor_BJT:TIP41B +Transistor_BJT:TIP41C +Transistor_BJT:TIP42 +Transistor_BJT:TIP42A +Transistor_BJT:TIP42B +Transistor_BJT:TIP42C +Transistor_BJT:UMH3N +Transistor_FET:2N3819 +Transistor_FET:2N7000 +Transistor_FET:2N7002 +Transistor_FET:2N7002E +Transistor_FET:2N7002H +Transistor_FET:2N7002K +Transistor_FET:3SK263 +Transistor_FET:AO3400A +Transistor_FET:AO3401A +Transistor_FET:AO4842 +Transistor_FET:AO4892 +Transistor_FET:AON6411 +Transistor_FET:BF244A +Transistor_FET:BF244B +Transistor_FET:BF244C +Transistor_FET:BF245A +Transistor_FET:BF245B +Transistor_FET:BF245C +Transistor_FET:BF545A +Transistor_FET:BF545B +Transistor_FET:BF545C +Transistor_FET:BF994S +Transistor_FET:BS107 +Transistor_FET:BS108 +Transistor_FET:BS170 +Transistor_FET:BS170F +Transistor_FET:BS250 +Transistor_FET:BS870 +Transistor_FET:BSB008NE2LX +Transistor_FET:BSB012NE2LXI +Transistor_FET:BSB013NE2LXI +Transistor_FET:BSB014N04LX3 +Transistor_FET:BSB015N04NX3 +Transistor_FET:BSB028N06NN3 +Transistor_FET:BSB044N08NN3 +Transistor_FET:BSB056N10NN3 +Transistor_FET:BSB104N08NP3 +Transistor_FET:BSB165N15NZ3 +Transistor_FET:BSB280N15NZ3 +Transistor_FET:BSC026N08NS5 +Transistor_FET:BSC028N06LS3 +Transistor_FET:BSC030N08NS5 +Transistor_FET:BSC035N10NS5 +Transistor_FET:BSC037N08NS5 +Transistor_FET:BSC040N08NS5 +Transistor_FET:BSC040N10NS5 +Transistor_FET:BSC046N10NS3G +Transistor_FET:BSC047N08NS3G +Transistor_FET:BSC052N08NS5 +Transistor_FET:BSC057N08NS3G +Transistor_FET:BSC060N10NS3G +Transistor_FET:BSC061N08NS5 +Transistor_FET:BSC070N10NS3G +Transistor_FET:BSC070N10NS5 +Transistor_FET:BSC072N08NS5 +Transistor_FET:BSC079N10NSG +Transistor_FET:BSC082N10LSG +Transistor_FET:BSC098N10NS5 +Transistor_FET:BSC100N10NSFG +Transistor_FET:BSC105N10LSFG +Transistor_FET:BSC109N10NS3G +Transistor_FET:BSC117N08NS5 +Transistor_FET:BSC118N10NSG +Transistor_FET:BSC123N08NS3G +Transistor_FET:BSC123N10LSG +Transistor_FET:BSC13DN30NSFD +Transistor_FET:BSC159N10LSFG +Transistor_FET:BSC160N10NS3G +Transistor_FET:BSC196N10NSG +Transistor_FET:BSC252N10NSFG +Transistor_FET:BSC265N10LSFG +Transistor_FET:BSC340N08NS3G +Transistor_FET:BSC440N10NS3G +Transistor_FET:BSD235C +Transistor_FET:BSD840N +Transistor_FET:BSF030NE2LQ +Transistor_FET:BSF035NE2LQ +Transistor_FET:BSF450NE7NH3 +Transistor_FET:BSN20 +Transistor_FET:BSP129 +Transistor_FET:BSP89 +Transistor_FET:BSR56 +Transistor_FET:BSR57 +Transistor_FET:BSR58 +Transistor_FET:BSS123 +Transistor_FET:BSS127S +Transistor_FET:BSS138 +Transistor_FET:BSS214NW +Transistor_FET:BSS83P +Transistor_FET:BSS84 +Transistor_FET:BUK7880-55A +Transistor_FET:BUK7M10-40EX +Transistor_FET:BUK7M12-40EX +Transistor_FET:BUK7M12-60EX +Transistor_FET:BUK7M15-60EX +Transistor_FET:BUK7M17-80EX +Transistor_FET:BUK7M19-60EX +Transistor_FET:BUK7M21-40EX +Transistor_FET:BUK7M22-80EX +Transistor_FET:BUK7M27-80EX +Transistor_FET:BUK7M33-60EX +Transistor_FET:BUK7M42-60EX +Transistor_FET:BUK7M45-40EX +Transistor_FET:BUK7M67-60EX +Transistor_FET:BUK7M6R3-40EX +Transistor_FET:BUK7M8R0-40EX +Transistor_FET:BUK7M9R9-60EX +Transistor_FET:BUK9832-55A +Transistor_FET:BUK9M10-30EX +Transistor_FET:BUK9M11-40EX +Transistor_FET:BUK9M12-60EX +Transistor_FET:BUK9M120-100EX +Transistor_FET:BUK9M14-40EX +Transistor_FET:BUK9M15-60EX +Transistor_FET:BUK9M156-100EX +Transistor_FET:BUK9M17-30EX +Transistor_FET:BUK9M19-60EX +Transistor_FET:BUK9M23-80EX +Transistor_FET:BUK9M24-40EX +Transistor_FET:BUK9M24-60EX +Transistor_FET:BUK9M28-80EX +Transistor_FET:BUK9M34-100EX +Transistor_FET:BUK9M35-80EX +Transistor_FET:BUK9M42-60EX +Transistor_FET:BUK9M43-100EX +Transistor_FET:BUK9M52-40EX +Transistor_FET:BUK9M53-60EX +Transistor_FET:BUK9M5R2-30EX +Transistor_FET:BUK9M6R6-30EX +Transistor_FET:BUK9M7R2-40EX +Transistor_FET:BUK9M85-60EX +Transistor_FET:BUK9M9R1-40EX +Transistor_FET:BUZ11 +Transistor_FET:C2M0025120D +Transistor_FET:C2M0040120D +Transistor_FET:C2M0045170D +Transistor_FET:C2M0080120D +Transistor_FET:C2M0160120D +Transistor_FET:C2M0280120D +Transistor_FET:C2M1000170D +Transistor_FET:C2M1000170J +Transistor_FET:C3M0030090K +Transistor_FET:C3M0065090D +Transistor_FET:C3M0065090J +Transistor_FET:C3M0065100J +Transistor_FET:C3M0065100K +Transistor_FET:C3M0075120J +Transistor_FET:C3M0075120K +Transistor_FET:C3M0120090D +Transistor_FET:C3M0120090J +Transistor_FET:C3M0120100J +Transistor_FET:C3M0120100K +Transistor_FET:C3M0280090D +Transistor_FET:C3M0280090J +Transistor_FET:CSD13380F3 +Transistor_FET:CSD16301Q2 +Transistor_FET:CSD16321Q5 +Transistor_FET:CSD16322Q5 +Transistor_FET:CSD16325Q5 +Transistor_FET:CSD16327Q3 +Transistor_FET:CSD16342Q5A +Transistor_FET:CSD16401Q5 +Transistor_FET:CSD16403Q5A +Transistor_FET:CSD16404Q5A +Transistor_FET:CSD16407Q5 +Transistor_FET:CSD16408Q5 +Transistor_FET:CSD16410Q5A +Transistor_FET:CSD16412Q5A +Transistor_FET:CSD16413Q5A +Transistor_FET:CSD16414Q5 +Transistor_FET:CSD16415Q5 +Transistor_FET:CSD16570Q5B +Transistor_FET:CSD17301Q5A +Transistor_FET:CSD17302Q5A +Transistor_FET:CSD17303Q5 +Transistor_FET:CSD17305Q5A +Transistor_FET:CSD17306Q5A +Transistor_FET:CSD17307Q5A +Transistor_FET:CSD17310Q5A +Transistor_FET:CSD17311Q5 +Transistor_FET:CSD17312Q5 +Transistor_FET:CSD17313Q2 +Transistor_FET:CSD17322Q5A +Transistor_FET:CSD17327Q5A +Transistor_FET:CSD17501Q5A +Transistor_FET:CSD17505Q5A +Transistor_FET:CSD17506Q5A +Transistor_FET:CSD17507Q5A +Transistor_FET:CSD17510Q5A +Transistor_FET:CSD17522Q5A +Transistor_FET:CSD17527Q5A +Transistor_FET:CSD17551Q5A +Transistor_FET:CSD17552Q5A +Transistor_FET:CSD17553Q5A +Transistor_FET:CSD17555Q5A +Transistor_FET:CSD17556Q5B +Transistor_FET:CSD17559Q5 +Transistor_FET:CSD17570Q5B +Transistor_FET:CSD17573Q5B +Transistor_FET:CSD17576Q5B +Transistor_FET:CSD17577Q3A +Transistor_FET:CSD17577Q5A +Transistor_FET:CSD17578Q5A +Transistor_FET:CSD17579Q5A +Transistor_FET:CSD17581Q3A +Transistor_FET:CSD18501Q5A +Transistor_FET:CSD18502Q5B +Transistor_FET:CSD18503Q5A +Transistor_FET:CSD18504Q5A +Transistor_FET:CSD18509Q5B +Transistor_FET:CSD18531Q5A +Transistor_FET:CSD18532NQ5B +Transistor_FET:CSD18532Q5B +Transistor_FET:CSD18533Q5A +Transistor_FET:CSD18534Q5A +Transistor_FET:CSD18537NQ5A +Transistor_FET:CSD18540Q5B +Transistor_FET:CSD18543Q3A +Transistor_FET:CSD18563Q5A +Transistor_FET:CSD19502Q5B +Transistor_FET:CSD19531Q5A +Transistor_FET:CSD19532Q5B +Transistor_FET:CSD19533Q5A +Transistor_FET:CSD19534Q5A +Transistor_FET:CSD19537Q3 +Transistor_FET:CSD25302Q2 +Transistor_FET:CSD25402Q3A +Transistor_FET:CSD25480F3 +Transistor_FET:DMC2053UVT +Transistor_FET:DMC3071LVT +Transistor_FET:DMG1012T +Transistor_FET:DMG2301L +Transistor_FET:DMG2302U +Transistor_FET:DMG3402L +Transistor_FET:DMG3404L +Transistor_FET:DMG3406L +Transistor_FET:DMG3414U +Transistor_FET:DMG3418L +Transistor_FET:DMG9926UDM +Transistor_FET:DMN10H220L +Transistor_FET:DMN10H700S +Transistor_FET:DMN13H750S +Transistor_FET:DMN2040U +Transistor_FET:DMN2041L +Transistor_FET:DMN2050L +Transistor_FET:DMN2056U +Transistor_FET:DMN2058U +Transistor_FET:DMN2075U +Transistor_FET:DMN2230U +Transistor_FET:DMN24H11DS +Transistor_FET:DMN24H3D5L +Transistor_FET:DMN3008SFG +Transistor_FET:DMN3033LDM +Transistor_FET:DMN3042L +Transistor_FET:DMN3051L +Transistor_FET:DMN30H4D0L +Transistor_FET:DMN3110S +Transistor_FET:DMN3150L +Transistor_FET:DMN32D2LDF +Transistor_FET:DMN3300U +Transistor_FET:DMN3404L +Transistor_FET:DMN6075S +Transistor_FET:DMN60H080DS +Transistor_FET:DMN6140L +Transistor_FET:DMN61D8LQ +Transistor_FET:DMN67D7L +Transistor_FET:DMN67D8L +Transistor_FET:DMP3013SFV +Transistor_FET:DMP6050SSD +Transistor_FET:DMT6008LFG +Transistor_FET:EPC2035 +Transistor_FET:EPC2036 +Transistor_FET:EPC2037 +Transistor_FET:EPC2038 +Transistor_FET:EPC2203 +Transistor_FET:EPC2219 +Transistor_FET:FDC2512 +Transistor_FET:FDC6330L +Transistor_FET:FDC86244 +Transistor_FET:FDG1024NZ +Transistor_FET:FDG6335N +Transistor_FET:FDMC8032L +Transistor_FET:FDMS8050 +Transistor_FET:FDMS8050ET30 +Transistor_FET:FDMS8350L +Transistor_FET:FDMS8350LET40 +Transistor_FET:FDMS86150 +Transistor_FET:FDMS86150ET100 +Transistor_FET:FDMS86152 +Transistor_FET:FDMS86202 +Transistor_FET:FDMS86202ET120 +Transistor_FET:FDMS86255 +Transistor_FET:FDMS86255ET150 +Transistor_FET:FDMS86350 +Transistor_FET:FDMS86350ET80 +Transistor_FET:FDMS86550 +Transistor_FET:FDMS86550ET60 +Transistor_FET:FDMT800100DC +Transistor_FET:FDMT800120DC +Transistor_FET:FDMT800150DC +Transistor_FET:FDMT800152DC +Transistor_FET:FDMT80060DC +Transistor_FET:FDMT80080DC +Transistor_FET:FDN340P +Transistor_FET:FDS2734 +Transistor_FET:FDS4559 +Transistor_FET:FDS4897AC +Transistor_FET:FDS4897C +Transistor_FET:FDS6630A +Transistor_FET:FDS6890A +Transistor_FET:FDS6892A +Transistor_FET:FDS6898A +Transistor_FET:FDS6930A +Transistor_FET:FDS6930B +Transistor_FET:FDS8960C +Transistor_FET:FDS9435A +Transistor_FET:FDS9926A +Transistor_FET:FDS9934C +Transistor_FET:FQP27P06 +Transistor_FET:GS66502B +Transistor_FET:GS66504B +Transistor_FET:GS66508B +Transistor_FET:IF3602 +Transistor_FET:IGLD60R070D1 +Transistor_FET:IGLD60R190D1 +Transistor_FET:IGO60R070D1 +Transistor_FET:IGOT60R070D1 +Transistor_FET:IGT40R070D1_E8220 +Transistor_FET:IGT60R070D1 +Transistor_FET:IGT60R190D1S +Transistor_FET:IPB180N10S4-02 +Transistor_FET:IPD50R380CE +Transistor_FET:IPD50R3K0CE +Transistor_FET:IPDD60R050G7 +Transistor_FET:IPDD60R080G7 +Transistor_FET:IPDD60R102G7 +Transistor_FET:IPDD60R125G7 +Transistor_FET:IPDD60R150G7 +Transistor_FET:IPDD60R190G7 +Transistor_FET:IPP060N06N +Transistor_FET:IPT012N08N5 +Transistor_FET:IPT015N10N5 +Transistor_FET:IPT020N10N3 +Transistor_FET:IRF3205 +Transistor_FET:IRF40DM229 +Transistor_FET:IRF4905 +Transistor_FET:IRF540N +Transistor_FET:IRF60DM206 +Transistor_FET:IRF6613 +Transistor_FET:IRF6614 +Transistor_FET:IRF6616 +Transistor_FET:IRF6617 +Transistor_FET:IRF6618 +Transistor_FET:IRF6620 +Transistor_FET:IRF6621 +Transistor_FET:IRF6622 +Transistor_FET:IRF6623 +Transistor_FET:IRF6628 +Transistor_FET:IRF6631 +Transistor_FET:IRF6635 +Transistor_FET:IRF6636 +Transistor_FET:IRF6637 +Transistor_FET:IRF6641 +Transistor_FET:IRF6643 +Transistor_FET:IRF6644 +Transistor_FET:IRF6646 +Transistor_FET:IRF6648 +Transistor_FET:IRF6655 +Transistor_FET:IRF6662 +Transistor_FET:IRF6665 +Transistor_FET:IRF6668 +Transistor_FET:IRF6674 +Transistor_FET:IRF6710S2 +Transistor_FET:IRF6711S +Transistor_FET:IRF6712S +Transistor_FET:IRF6713S +Transistor_FET:IRF6714M +Transistor_FET:IRF6715M +Transistor_FET:IRF6716M +Transistor_FET:IRF6717M +Transistor_FET:IRF6718L2 +Transistor_FET:IRF6721S +Transistor_FET:IRF6722M +Transistor_FET:IRF6724M +Transistor_FET:IRF6725M +Transistor_FET:IRF6726M +Transistor_FET:IRF6727M +Transistor_FET:IRF6728M +Transistor_FET:IRF6775M +Transistor_FET:IRF6785 +Transistor_FET:IRF6795M +Transistor_FET:IRF6797M +Transistor_FET:IRF6798M +Transistor_FET:IRF6802SD +Transistor_FET:IRF6810S +Transistor_FET:IRF6811S +Transistor_FET:IRF6892S +Transistor_FET:IRF6893M +Transistor_FET:IRF6894M +Transistor_FET:IRF6898M +Transistor_FET:IRF7171M +Transistor_FET:IRF7309IPBF +Transistor_FET:IRF7324 +Transistor_FET:IRF7343PBF +Transistor_FET:IRF740 +Transistor_FET:IRF7403 +Transistor_FET:IRF7404 +Transistor_FET:IRF7480M +Transistor_FET:IRF7483M +Transistor_FET:IRF7486M +Transistor_FET:IRF7580M +Transistor_FET:IRF7606PBF +Transistor_FET:IRF7607PBF +Transistor_FET:IRF7665S2 +Transistor_FET:IRF7739L1 +Transistor_FET:IRF7748L1 +Transistor_FET:IRF7759L2 +Transistor_FET:IRF7769L1 +Transistor_FET:IRF7779L2 +Transistor_FET:IRF7780M +Transistor_FET:IRF7799L2 +Transistor_FET:IRF7946 +Transistor_FET:IRF8301M +Transistor_FET:IRF8302M +Transistor_FET:IRF8304M +Transistor_FET:IRF8306M +Transistor_FET:IRF8308M +Transistor_FET:IRF8327S +Transistor_FET:IRF8721PBF-1 +Transistor_FET:IRF9383M +Transistor_FET:IRF9540N +Transistor_FET:IRFI4019H +Transistor_FET:IRFI4020H +Transistor_FET:IRFI4212H +Transistor_FET:IRFP4468PbF +Transistor_FET:IRFP4668PbF +Transistor_FET:IRFS4115 +Transistor_FET:IRFS4127 +Transistor_FET:IRFS4227 +Transistor_FET:IRFS4229 +Transistor_FET:IRFS4310Z +Transistor_FET:IRFS4321 +Transistor_FET:IRFTS9342PBF +Transistor_FET:IRL6283M +Transistor_FET:IRL6297SD +Transistor_FET:IRL7472L1 +Transistor_FET:IRLB8721PBF +Transistor_FET:IRLIZ44N +Transistor_FET:IRLML0030 +Transistor_FET:IRLML2060 +Transistor_FET:IRLML5203 +Transistor_FET:IRLML6244 +Transistor_FET:IRLML6401 +Transistor_FET:IRLML6402 +Transistor_FET:IRLML9301 +Transistor_FET:IRLZ24 +Transistor_FET:IRLZ34N +Transistor_FET:IRLZ44N +Transistor_FET:JFE150DBV +Transistor_FET:JFE150DCK +Transistor_FET:JFE2140D +Transistor_FET:MMBF170 +Transistor_FET:MMBF4391 +Transistor_FET:MMBF4392 +Transistor_FET:MMBF4393 +Transistor_FET:MMBFJ111 +Transistor_FET:MMBFJ112 +Transistor_FET:MMBFJ113 +Transistor_FET:NDT3055L +Transistor_FET:NTR2101P +Transistor_FET:PGA26E07BA +Transistor_FET:PGA26E19BA +Transistor_FET:PMDT290UCE +Transistor_FET:PMN48XP +Transistor_FET:PSMN5R2-60YL +Transistor_FET:QM6006D +Transistor_FET:QM6015D +Transistor_FET:Q_Dual_NMOS_G1S2G2D2S1D1 +Transistor_FET:Q_Dual_NMOS_S1G1D2S2G2D1 +Transistor_FET:Q_Dual_NMOS_S1G1S2G2D2D1 +Transistor_FET:Q_Dual_NMOS_S1G1S2G2D2D2D1D1 +Transistor_FET:Q_Dual_PMOS_G1S2G2D2S1D1 +Transistor_FET:Q_Dual_PMOS_S1G1D2S2G2D1 +Transistor_FET:Q_Dual_PMOS_S1G1S2G2D2D2D1D1 +Transistor_FET:Q_NMOS_DGS +Transistor_FET:Q_NMOS_DSG +Transistor_FET:Q_NMOS_GDS +Transistor_FET:Q_NMOS_GDSD +Transistor_FET:Q_NMOS_GSD +Transistor_FET:Q_NMOS_SDGD +Transistor_FET:Q_NMOS_SGD +Transistor_FET:Q_PMOS_DGS +Transistor_FET:Q_PMOS_DSG +Transistor_FET:Q_PMOS_GDS +Transistor_FET:Q_PMOS_GDSD +Transistor_FET:Q_PMOS_GSD +Transistor_FET:Q_PMOS_SDG +Transistor_FET:Q_PMOS_SDGD +Transistor_FET:Q_PMOS_SGD +Transistor_FET:RQ6E080AJ +Transistor_FET:RS9N50D +Transistor_FET:RSQ030N08HZG +Transistor_FET:SCTL35N65G2V +Transistor_FET:SGT65R65AL +Transistor_FET:SQJQ100E +Transistor_FET:SQJQ100EL +Transistor_FET:SQJQ112E +Transistor_FET:SQJQ114EL +Transistor_FET:SQJQ116EL +Transistor_FET:SQJQ130EL +Transistor_FET:SQJQ140E +Transistor_FET:SQJQ142E +Transistor_FET:SQJQ144AE +Transistor_FET:SQJQ146E +Transistor_FET:SQJQ148E +Transistor_FET:SQJQ150E +Transistor_FET:SQJQ160E +Transistor_FET:SQJQ160EL +Transistor_FET:SQJQ184E +Transistor_FET:SQJQ186E +Transistor_FET:SQJQ402E +Transistor_FET:SQJQ404E +Transistor_FET:SQJQ410EL +Transistor_FET:SQJQ466E +Transistor_FET:SQJQ480E +Transistor_FET:STB15N80K5 +Transistor_FET:STB33N65M2 +Transistor_FET:STB40N60M2 +Transistor_FET:STD7NK40Z +Transistor_FET:STS2DNE60 +Transistor_FET:SUD08P06-155L +Transistor_FET:SUD09P10-195 +Transistor_FET:SUD19P06-60 +Transistor_FET:SUD45P03-09 +Transistor_FET:SUD50P04-08 +Transistor_FET:SUD50P06-15 +Transistor_FET:SUD50P08-25L +Transistor_FET:SUD50P10-43L +Transistor_FET:Si1308EDL +Transistor_FET:Si1442DH +Transistor_FET:Si2319CDS +Transistor_FET:Si2371EDS +Transistor_FET:Si3456DDV +Transistor_FET:Si4162DY +Transistor_FET:Si4532DY +Transistor_FET:Si4542DY +Transistor_FET:Si7141DP +Transistor_FET:Si7336ADP +Transistor_FET:Si7450DP +Transistor_FET:Si7617DN +Transistor_FET:SiA449DJ +Transistor_FET:SiA453EDJ +Transistor_FET:SiA462DJ +Transistor_FET:SiR696DP +Transistor_FET:SiS415DNT +Transistor_FET:SiS443DN +Transistor_FET:SiS454DN +Transistor_FET:SiSS27DN +Transistor_FET:T2N7002AK +Transistor_FET:TP0610L +Transistor_FET:TP0610T +Transistor_FET:TSM2301ACX +Transistor_FET:TSM2302CX +Transistor_FET:VN10LF +Transistor_FET:VNP10N07 +Transistor_FET:VP0610L +Transistor_FET:VP0610T +Transistor_FET:ZVN3306F +Transistor_FET:ZVN3310F +Transistor_FET:ZVN3320F +Transistor_FET:ZVN4106F +Transistor_FET:ZXM61N02F +Transistor_FET:ZXM61N03F +Transistor_FET:ZXMN10A07F +Transistor_FET:ZXMN2A01F +Transistor_FET:ZXMN2A14F +Transistor_FET:ZXMN2B01F +Transistor_FET:ZXMN2B14FH +Transistor_FET:ZXMN2F30FH +Transistor_FET:ZXMN2F34FH +Transistor_FET:ZXMN3A01F +Transistor_FET:ZXMN3A14F +Transistor_FET:ZXMN3B01F +Transistor_FET:ZXMN3B14F +Transistor_FET:ZXMN3F30FH +Transistor_FET:ZXMN6A07F +Transistor_FET:ZXMP4A16G +Transistor_FET_Other:DN2540N3-G +Transistor_FET_Other:DN2540N5-G +Transistor_FET_Other:DN2540N8-G +Transistor_FET_Other:Q_NMOS_Depletion_DGS +Transistor_FET_Other:Q_NMOS_Depletion_DSG +Transistor_FET_Other:Q_NMOS_Depletion_GDS +Transistor_FET_Other:Q_NMOS_Depletion_GSD +Transistor_FET_Other:Q_NMOS_Depletion_SDG +Transistor_FET_Other:Q_NMOS_Depletion_SGD +Transistor_IGBT:IRG4PF50W +Transistor_IGBT:STGP7NC60HD +Transistor_Power_Module:A2C25S12M3 +Transistor_Power_Module:A2C25S12M3-F +Transistor_Power_Module:A2C35S12M3 +Transistor_Power_Module:A2C35S12M3-F +Transistor_Power_Module:A2C50S65M2 +Transistor_Power_Module:A2C50S65M2-F +Transistor_Power_Module:FP10R06W1E3 +Transistor_Power_Module:FP15R06W1E3 +Transistor_Power_Module:FP15R12W2T4 +Transistor_Power_Module:FP25R12W2T4 +Transistor_Power_Module:FP25R12W2T4P +Transistor_Power_Module:FP35R12W2T4 +Transistor_Power_Module:FP35R12W2T4P +Transistor_Power_Module:FP50R06W2E3 +Transistor_Power_Module:FS75R07N2E4 +Transistor_Power_Module:MG12100W-XN2MM +Transistor_Power_Module:MG1215H-XBN2MM +Transistor_Power_Module:MG1225H-XBN2MM +Transistor_Power_Module:MG1225H-XN2MM +Transistor_Power_Module:MG1240H-XBN2MM +Transistor_Power_Module:MG1250H-XN2MM +Transistor_Power_Module:MG1250W-XBN2MM +Transistor_Power_Module:MG1275W-XBN2MM +Transistor_Power_Module:MG1275W-XN2MM +Transistor_Power_Module:STGIPS10C60-H +Transistor_Power_Module:STGIPS10K60A +Transistor_Power_Module:STGIPS10K60A2 +Transistor_Power_Module:STGIPS10K60T +Transistor_Power_Module:STGIPS14K60 +Transistor_Power_Module:STGIPS14K60T +Transistor_Power_Module:STGIPS20K60 +Triac_Thyristor:BT136-500 +Triac_Thyristor:BT136-600 +Triac_Thyristor:BT136-800 +Triac_Thyristor:BT138-600 +Triac_Thyristor:BT138-800 +Triac_Thyristor:BT139-600 +Triac_Thyristor:BT169B +Triac_Thyristor:BT169D +Triac_Thyristor:BT169G +Triac_Thyristor:BTA16-600B +Triac_Thyristor:BTA16-600BW +Triac_Thyristor:BTA16-600C +Triac_Thyristor:BTA16-600CW +Triac_Thyristor:BTA16-600SW +Triac_Thyristor:BTA16-800B +Triac_Thyristor:BTA16-800BW +Triac_Thyristor:BTA16-800C +Triac_Thyristor:BTA16-800CW +Triac_Thyristor:BTA16-800SW +Triac_Thyristor:BTB16-600B +Triac_Thyristor:BTB16-600BW +Triac_Thyristor:BTB16-600C +Triac_Thyristor:BTB16-600CW +Triac_Thyristor:BTB16-600SW +Triac_Thyristor:BTB16-800B +Triac_Thyristor:BTB16-800BW +Triac_Thyristor:BTB16-800C +Triac_Thyristor:BTB16-800CW +Triac_Thyristor:BTB16-800SW +Triac_Thyristor:CT401T +Triac_Thyristor:Generic_Triac_A1A2G +Triac_Thyristor:Generic_Triac_A1GA2 +Triac_Thyristor:Generic_Triac_A2A1G +Triac_Thyristor:Generic_Triac_A2GA1 +Triac_Thyristor:Generic_Triac_GA1A2 +Triac_Thyristor:Generic_Triac_GA2A1 +Triac_Thyristor:TIC106 +Triac_Thyristor:TIC116 +Triac_Thyristor:TIC126 +Triac_Thyristor:TIC206 +Triac_Thyristor:TIC216 +Triac_Thyristor:TIC226 +Triac_Thyristor:X0202MN +Triac_Thyristor:X0202NN +Triac_Thyristor:Z0103MN +Triac_Thyristor:Z0103NN +Triac_Thyristor:Z0107MN +Triac_Thyristor:Z0107NN +Triac_Thyristor:Z0109MN +Triac_Thyristor:Z0109NN +Triac_Thyristor:Z0110MN +Triac_Thyristor:Z0110NN +Valve:6AK8 +Valve:9AK8 +Valve:CK548DX +Valve:CK6418 +Valve:EABC80 +Valve:EC92 +Valve:ECC81 +Valve:ECC83 +Valve:ECC88 +Valve:ECH81 +Valve:ECL82 +Valve:ECL86 +Valve:EF80 +Valve:EF83 +Valve:EF85 +Valve:EF86 +Valve:EL34 +Valve:EL84 +Valve:EM84 +Valve:JAN6418 +Valve:NOS-6418 +Valve:PABC80 +Valve:STABI +Valve:UABC80 +Video:AD725 +Video:AD9708AR +Video:AD9891 +Video:AD9895 +Video:AD9984AKST +Video:ADA4430-1WYRTZ +Video:ADA4430-1YKSZ +Video:ADV7280xCP +Video:ADV7390BCPZ +Video:ADV7391BCPZ +Video:AV9173 +Video:CX7930 +Video:CXD3400N +Video:HD63484 +Video:HD63484_PLCC +Video:ICX415AQ +Video:ISL59885 +Video:LM1881 +Video:MAX310 +Video:MAX311 +Video:MB88303P +Video:S178 +Video:SAA7182 +Video:SI582 +Video:TDA1950 +Video:TDA1950F +Video:TDA2593 +Video:TDA7260 +Video:TDA8501 +Video:TDA8702 +Video:TDA8702T +Video:TDA8772 +Video:TDA9500 +Video:TDA9503 +Video:TDA9513 +Video:TEA2014 +Video:TEA5115 +Video:TFP410PAP diff --git a/rector.php b/rector.php index 94ade3df..40eee9f7 100644 --- a/rector.php +++ b/rector.php @@ -2,15 +2,17 @@ declare(strict_types=1); +use Rector\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiveTypeRector; use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; use Rector\Config\RectorConfig; use Rector\Doctrine\Set\DoctrineSetList; -use Rector\PHPUnit\Rector\ClassMethod\AddDoesNotPerformAssertionToNonAssertingTestRector; -use Rector\PHPUnit\Set\PHPUnitLevelSetList; +use Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; -use Rector\Symfony\Set\SymfonyLevelSetList; +use Rector\Symfony\CodeQuality\Rector\Class_\EventListenerToEventSubscriberRector; +use Rector\Symfony\CodeQuality\Rector\ClassMethod\ActionSuffixRemoverRector; +use Rector\Symfony\CodeQuality\Rector\MethodCall\LiteralGetToRequestClassConstantRector; use Rector\Symfony\Set\SymfonySetList; use Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector; @@ -44,20 +46,36 @@ return static function (RectorConfig $rectorConfig): void { LevelSetList::UP_TO_PHP_81, //Symfony rules - SymfonyLevelSetList::UP_TO_SYMFONY_62, SymfonySetList::SYMFONY_CODE_QUALITY, + SymfonySetList::SYMFONY_64, //Doctrine rules DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES, DoctrineSetList::DOCTRINE_CODE_QUALITY, //PHPUnit rules - PHPUnitLevelSetList::UP_TO_PHPUNIT_90, PHPUnitSetList::PHPUNIT_CODE_QUALITY, + PHPUnitSetList::PHPUNIT_90, ]); $rectorConfig->skip([ - AddDoesNotPerformAssertionToNonAssertingTestRector::class, CountArrayToEmptyArrayComparisonRector::class, + //Leave our !== null checks alone + FlipTypeControlToUseExclusiveTypeRector::class, + //Leave our PartList TableAction alone + ActionSuffixRemoverRector::class, + //We declare event listeners via attributes, therefore no need to migrate them to subscribers + EventListenerToEventSubscriberRector::class, + PreferPHPUnitThisCallRector::class, + //Do not replace 'GET' with class constant, + LiteralGetToRequestClassConstantRector::class, + ]); + + //Do not apply rules to Symfony own files + $rectorConfig->skip([ + __DIR__ . '/public/index.php', + __DIR__ . '/src/Kernel.php', + __DIR__ . '/config/preload.php', + __DIR__ . '/config/bundles.php', ]); }; diff --git a/src/ApiPlatform/DocumentedAPIProperties/DocumentedAPIProperty.php b/src/ApiPlatform/DocumentedAPIProperties/DocumentedAPIProperty.php new file mode 100644 index 00000000..57d275be --- /dev/null +++ b/src/ApiPlatform/DocumentedAPIProperties/DocumentedAPIProperty.php @@ -0,0 +1,120 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform\DocumentedAPIProperties; + +use ApiPlatform\Metadata\ApiProperty; + +/** + * When this attribute is applied to a class, an property will be added to the API documentation using the given parameters. + * This is useful for adding properties to the API documentation, that are not existing in the entity class itself, + * but get added by a normalizer. + */ +#[\Attribute(\Attribute::TARGET_CLASS| \Attribute::IS_REPEATABLE)] +final class DocumentedAPIProperty +{ + public function __construct( + /** + * @param string $schemaName The name of the schema to add the property to (e.g. "Part-Read") + */ + public readonly string $schemaName, + /** + * @var string $property The name of the property to add to the schema + */ + public readonly string $property, + public readonly string $type = 'string', + public readonly bool $nullable = true, + /** + * @var string $description The description of the property + */ + public readonly ?string $description = null, + /** + * @var bool True if the property is readable, false otherwise + */ + public readonly bool $readable = true, + /** + * @var bool True if the property is writable, false otherwise + */ + public readonly bool $writeable = false, + /** + * @var string|null The deprecation reason of the property + */ + public readonly ?string $deprecationReason = null, + /** @var mixed The default value of this property */ + public readonly mixed $default = null, + public readonly mixed $example = null, + ) + { + } + + public function toAPIProperty(bool $use_swagger = false): ApiProperty + { + $openApiContext = []; + + if (false === $this->writeable) { + $openApiContext['readOnly'] = true; + } + if (!$use_swagger && false === $this->readable) { + $openApiContext['writeOnly'] = true; + } + if (null !== $description = $this->description) { + $openApiContext['description'] = $description; + } + + $deprecationReason = $this->deprecationReason; + + // see https://github.com/json-schema-org/json-schema-spec/pull/737 + if (!$use_swagger && null !== $deprecationReason) { + $openApiContext['deprecated'] = true; + } + + if (!empty($default = $this->default)) { + if ($default instanceof \BackedEnum) { + $default = $default->value; + } + $openApiContext['default'] = $default; + } + + if (!empty($example = $this->example)) { + $openApiContext['example'] = $example; + } + + if (!isset($openApiContext['example']) && isset($openApiContext['default'])) { + $openApiContext['example'] = $openApiContext['default']; + } + + $openApiContext['type'] = $this->type; + $openApiContext['nullable'] = $this->nullable; + + + + return new ApiProperty( + description: $this->description, + readable: $this->readable, + writable: $this->writeable, + openapiContext: $openApiContext, + types: $this->type, + property: $this->property + ); + } +} \ No newline at end of file diff --git a/src/ApiPlatform/DocumentedAPIProperties/PropertyMetadataFactory.php b/src/ApiPlatform/DocumentedAPIProperties/PropertyMetadataFactory.php new file mode 100644 index 00000000..49e9a031 --- /dev/null +++ b/src/ApiPlatform/DocumentedAPIProperties/PropertyMetadataFactory.php @@ -0,0 +1,73 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform\DocumentedAPIProperties; + +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface; +use ReflectionClass; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; + +/** + * This decorator adds the virtual properties defined by the DocumentedAPIProperty attribute to the property metadata + * which then get picked up by the openapi schema generator + */ +#[AsDecorator('api_platform.metadata.property.metadata_factory')] +class PropertyMetadataFactory implements PropertyMetadataFactoryInterface +{ + public function __construct(private PropertyMetadataFactoryInterface $decorated) + { + } + + public function create(string $resourceClass, string $property, array $options = []): ApiProperty + { + $metadata = $this->decorated->create($resourceClass, $property, $options); + + //Only become active in the context of the openapi schema generation + if (!isset($options['schema_type'])) { + return $metadata; + } + + if (!class_exists($resourceClass)) { + return $metadata; + } + + $refClass = new ReflectionClass($resourceClass); + $attributes = $refClass->getAttributes(DocumentedAPIProperty::class); + + //Look for the DocumentedAPIProperty attribute with the given property name + foreach ($attributes as $attribute) { + /** @var DocumentedAPIProperty $api_property */ + $api_property = $attribute->newInstance(); + //If attribute not matches the property name, skip it + if ($api_property->property !== $property) { + continue; + } + + //Return the virtual property + return $api_property->toAPIProperty(); + } + + return $metadata; + } +} \ No newline at end of file diff --git a/src/ApiPlatform/DocumentedAPIProperties/PropertyNameCollectionFactory.php b/src/ApiPlatform/DocumentedAPIProperties/PropertyNameCollectionFactory.php new file mode 100644 index 00000000..3157cbf3 --- /dev/null +++ b/src/ApiPlatform/DocumentedAPIProperties/PropertyNameCollectionFactory.php @@ -0,0 +1,68 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform\DocumentedAPIProperties; + +use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; +use ApiPlatform\Metadata\Property\PropertyNameCollection; +use ReflectionClass; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; + +/** + * This decorator adds the virtual property names defined by the DocumentedAPIProperty attribute to the property name collection + * which then get picked up by the openapi schema generator + */ +#[AsDecorator('api_platform.metadata.property.name_collection_factory')] +class PropertyNameCollectionFactory implements PropertyNameCollectionFactoryInterface +{ + public function __construct(private readonly PropertyNameCollectionFactoryInterface $decorated) + { + } + + public function create(string $resourceClass, array $options = []): PropertyNameCollection + { + // Get the default properties from the decorated service + $propertyNames = $this->decorated->create($resourceClass, $options); + + //Only become active in the context of the openapi schema generation + if (!isset($options['schema_type'])) { + return $propertyNames; + } + + if (!class_exists($resourceClass)) { + return $propertyNames; + } + + $properties = iterator_to_array($propertyNames); + + $refClass = new ReflectionClass($resourceClass); + + foreach ($refClass->getAttributes(DocumentedAPIProperty::class) as $attribute) { + /** @var DocumentedAPIProperty $instance */ + $instance = $attribute->newInstance(); + $properties[] = $instance->property; + } + + return new PropertyNameCollection($properties); + } +} \ No newline at end of file diff --git a/src/ApiPlatform/ErrorHandler.php b/src/ApiPlatform/ErrorHandler.php new file mode 100644 index 00000000..7704347d --- /dev/null +++ b/src/ApiPlatform/ErrorHandler.php @@ -0,0 +1,75 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform; + +use ApiPlatform\Metadata\Operation; +use ApiPlatform\State\ProviderInterface; +use Doctrine\ORM\ORMInvalidArgumentException; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use ApiPlatform\State\ApiResource\Error; +use Symfony\Component\DependencyInjection\Attribute\Autowire; + +/** + * This class adds a custom error if the user tries to create a new entity through a relation, and suggests to do reference it through an IRI instead. + * This class decorates the default error handler of API Platform. + */ +#[AsDecorator('api_platform.state.error_provider')] +final class ErrorHandler implements ProviderInterface +{ + public function __construct(private readonly ProviderInterface $decorated, #[Autowire('%kernel.debug%')] private readonly bool $debug) + { + + } + + public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + $request = $context['request']; + $format = $request->getRequestFormat(); + $exception = $request->attributes->get('exception'); + + //Check if the exception is a ORM InvalidArgument exception and complains about a not-persisted entity through relation + if ($exception instanceof ORMInvalidArgumentException && str_contains($exception->getMessage(), 'A new entity was found through the relationship')) { + //Extract the entity class and property name from the exception message + $matches = []; + preg_match('/A new entity was found through the relationship \'(?.*)\'/i', $exception->getMessage(), $matches); + + $property = $matches['property'] ?? "unknown"; + + //Create a new error response + $error = Error::createFromException($exception, 400); + + //Return the error response + $detail = "You tried to create a new entity through the relation '$property', but this is not allowed. Please create the entity first and then reference it through an IRI!"; + //If we are in debug mode, add the exception message to the error response + if ($this->debug) { + $detail .= " Original exception message: " . $exception->getMessage(); + } + $error->setDetail($detail); + return $error; + } + + + return $this->decorated->provide($operation, $uriVariables, $context); + } +} \ No newline at end of file diff --git a/src/ApiPlatform/Filter/EntityFilter.php b/src/ApiPlatform/Filter/EntityFilter.php new file mode 100644 index 00000000..85bc3833 --- /dev/null +++ b/src/ApiPlatform/Filter/EntityFilter.php @@ -0,0 +1,84 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform\Filter; + +use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; +use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; +use ApiPlatform\Metadata\Operation; +use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ManagerRegistry; +use Psr\Log\LoggerInterface; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; + +class EntityFilter extends AbstractFilter +{ + + public function __construct( + ManagerRegistry $managerRegistry, + private readonly EntityFilterHelper $filter_helper, + ?LoggerInterface $logger = null, + ?array $properties = null, + ?NameConverterInterface $nameConverter = null + ) { + parent::__construct($managerRegistry, $logger, $properties, $nameConverter); + } + + protected function filterProperty( + string $property, + $value, + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + ?Operation $operation = null, + array $context = [] + ): void { + if ( + !$this->isPropertyEnabled($property, $resourceClass) || + !$this->isPropertyMapped($property, $resourceClass, true) + ) { + return; + } + + $metadata = $this->getClassMetadata($resourceClass); + $target_class = $metadata->getAssociationTargetClass($property); + //If it is not an association we can not filter the property + if (!$target_class) { + return; + } + + $elements = $this->filter_helper->valueToEntityArray($value, $target_class); + + $parameterName = $queryNameGenerator->generateParameterName($property); // Generate a unique parameter name to avoid collisions with other filters + $queryBuilder + ->andWhere(sprintf('o.%s IN (:%s)', $property, $parameterName)) + ->setParameter($parameterName, $elements); + } + + + + public function getDescription(string $resourceClass): array + { + return $this->filter_helper->getDescription($this->properties); + } +} \ No newline at end of file diff --git a/src/ApiPlatform/Filter/EntityFilterHelper.php b/src/ApiPlatform/Filter/EntityFilterHelper.php new file mode 100644 index 00000000..45e04fde --- /dev/null +++ b/src/ApiPlatform/Filter/EntityFilterHelper.php @@ -0,0 +1,99 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform\Filter; + +use App\Entity\Base\AbstractStructuralDBElement; +use App\Services\Trees\NodesListBuilder; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\PropertyInfo\Type; + +class EntityFilterHelper +{ + public function __construct( + private readonly NodesListBuilder $nodesListBuilder, + private readonly EntityManagerInterface $entityManager) + { + + } + + public function valueToEntityArray(string $value, string $target_class): array + { + //Convert value to IDs: + $elements = []; + + //Split the given value by comm + foreach (explode(',', $value) as $id) { + if (trim($id) === '') { + continue; + } + + //Check if the given value ends with a plus, then we want to include all direct children + $include_children = false; + $include_recursive = false; + if (str_ends_with($id, '++')) { //Plus Plus means include all children recursively + $id = substr($id, 0, -2); + $include_recursive = true; + } elseif (str_ends_with($id, '+')) { + $id = substr($id, 0, -1); + $include_children = true; + } + + //Get a (shallow) reference to the entitity + $element = $this->entityManager->getReference($target_class, (int) $id); + $elements[] = $element; + + //If $element is not structural we are done + if (!is_a($element, AbstractStructuralDBElement::class)) { + continue; + } + + //Get the recursive list of children + if ($include_recursive) { + $elements = array_merge($elements, $this->nodesListBuilder->getChildrenFlatList($element)); + } elseif ($include_children) { + $elements = array_merge($elements, $element->getChildren()->toArray()); + } + } + + return $elements; + } + + public function getDescription(array $properties): array + { + if ($properties === []) { + return []; + } + + $description = []; + foreach (array_keys($properties) as $property) { + $description[(string)$property] = [ + 'property' => $property, + 'type' => Type::BUILTIN_TYPE_STRING, + 'required' => false, + 'description' => 'Filter using a comma seperated list of element IDs. Use + to include all direct children and ++ to include all children recursively.', + ]; + } + return $description; + } +} \ No newline at end of file diff --git a/src/ApiPlatform/Filter/LikeFilter.php b/src/ApiPlatform/Filter/LikeFilter.php new file mode 100644 index 00000000..a8e96eb9 --- /dev/null +++ b/src/ApiPlatform/Filter/LikeFilter.php @@ -0,0 +1,74 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform\Filter; + +use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; +use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; +use ApiPlatform\Metadata\Operation; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\PropertyInfo\Type; + +final class LikeFilter extends AbstractFilter +{ + + protected function filterProperty( + string $property, + $value, + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + ?Operation $operation = null, + array $context = [] + ): void { + // Otherwise filter is applied to order and page as well + if ( + !$this->isPropertyEnabled($property, $resourceClass) || + !$this->isPropertyMapped($property, $resourceClass) + ) { + return; + } + $parameterName = $queryNameGenerator->generateParameterName($property); // Generate a unique parameter name to avoid collisions with other filters + $queryBuilder + ->andWhere(sprintf('ILIKE(o.%s, :%s) = TRUE', $property, $parameterName)) + ->setParameter($parameterName, $value); + } + + public function getDescription(string $resourceClass): array + { + if (!$this->properties) { + return []; + } + + $description = []; + foreach (array_keys($this->properties) as $property) { + $description[(string)$property] = [ + 'property' => $property, + 'type' => Type::BUILTIN_TYPE_STRING, + 'required' => false, + 'description' => 'Filter using a LIKE SQL expression. Use % as wildcard for multiple characters and _ for single characters. For example, to search for all items containing foo, use foo. To search for all items starting with foo, use foo%. To search for all items ending with foo, use %foo', + ]; + } + return $description; + } +} \ No newline at end of file diff --git a/src/ApiPlatform/Filter/PartStoragelocationFilter.php b/src/ApiPlatform/Filter/PartStoragelocationFilter.php new file mode 100644 index 00000000..4d0ad2df --- /dev/null +++ b/src/ApiPlatform/Filter/PartStoragelocationFilter.php @@ -0,0 +1,79 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform\Filter; + +use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; +use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; +use ApiPlatform\Metadata\Operation; +use App\Entity\Parts\StorageLocation; +use Doctrine\ORM\QueryBuilder; +use Doctrine\Persistence\ManagerRegistry; +use Psr\Log\LoggerInterface; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; + +class PartStoragelocationFilter extends AbstractFilter +{ + + public function __construct( + ManagerRegistry $managerRegistry, + private readonly EntityFilterHelper $filter_helper, + ?LoggerInterface $logger = null, + ?array $properties = null, + ?NameConverterInterface $nameConverter = null + ) { + parent::__construct($managerRegistry, $logger, $properties, $nameConverter); + } + + protected function filterProperty( + string $property, + $value, + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + ?Operation $operation = null, + array $context = [] + ): void { + //Do not check for mapping here, as we are using a virtual property + if ( + !$this->isPropertyEnabled($property, $resourceClass) + ) { + return; + } + + $elements = $this->filter_helper->valueToEntityArray($value, StorageLocation::class); + + $parameterName = $queryNameGenerator->generateParameterName($property); // Generate a unique parameter name to avoid collisions with other filters + $queryBuilder + ->leftJoin('o.partLots', 'partLots') + ->andWhere(sprintf('partLots.storage_location IN (:%s)', $parameterName)) + ->setParameter($parameterName, $elements); + } + + + + public function getDescription(string $resourceClass): array + { + return $this->filter_helper->getDescription($this->properties); + } +} \ No newline at end of file diff --git a/src/ApiPlatform/Filter/TagFilter.php b/src/ApiPlatform/Filter/TagFilter.php new file mode 100644 index 00000000..98648ee9 --- /dev/null +++ b/src/ApiPlatform/Filter/TagFilter.php @@ -0,0 +1,96 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform\Filter; + +use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; +use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; +use ApiPlatform\Metadata\Operation; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\PropertyInfo\Type; + +/** + * Due to their nature, tags are stored in a single string, separated by commas, which requires some more complex search logic. + * This filter allows to easily search for tags in a part entity. + */ +final class TagFilter extends AbstractFilter +{ + + protected function filterProperty( + string $property, + $value, + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + ?Operation $operation = null, + array $context = [] + ): void { + // Ignore filter if property is not enabled or mapped + if ( + !$this->isPropertyEnabled($property, $resourceClass) || + !$this->isPropertyMapped($property, $resourceClass) + ) { + return; + } + + //Escape any %, _ or \ in the tag + $value = addcslashes($value, '%_\\'); + + $tag_identifier_prefix = $queryNameGenerator->generateParameterName($property); + + $expr = $queryBuilder->expr(); + + $tmp = $expr->orX( + 'ILIKE(o.'.$property.', :' . $tag_identifier_prefix . '_1) = TRUE', + 'ILIKE(o.'.$property.', :' . $tag_identifier_prefix . '_2) = TRUE', + 'ILIKE(o.'.$property.', :' . $tag_identifier_prefix . '_3) = TRUE', + 'ILIKE(o.'.$property.', :' . $tag_identifier_prefix . '_4) = TRUE', + ); + + $queryBuilder->andWhere($tmp); + + //Set the parameters for the LIKE expression, in each variation of the tag (so with a comma, at the end, at the beginning, and on both ends, and equaling the tag) + $queryBuilder->setParameter($tag_identifier_prefix . '_1', '%,' . $value . ',%'); + $queryBuilder->setParameter($tag_identifier_prefix . '_2', '%,' . $value); + $queryBuilder->setParameter($tag_identifier_prefix . '_3', $value . ',%'); + $queryBuilder->setParameter($tag_identifier_prefix . '_4', $value); + } + + public function getDescription(string $resourceClass): array + { + if (!$this->properties) { + return []; + } + + $description = []; + foreach (array_keys($this->properties) as $property) { + $description[(string)$property] = [ + 'property' => $property, + 'type' => Type::BUILTIN_TYPE_STRING, + 'required' => false, + 'description' => 'Filter for tags of a part', + ]; + } + return $description; + } +} \ No newline at end of file diff --git a/src/ApiPlatform/FixInheritanceMappingMetadataFacory.php b/src/ApiPlatform/FixInheritanceMappingMetadataFacory.php new file mode 100644 index 00000000..c65e57a0 --- /dev/null +++ b/src/ApiPlatform/FixInheritanceMappingMetadataFacory.php @@ -0,0 +1,72 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform; + +use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; +use ApiPlatform\Metadata\Resource\ResourceMetadataCollection; +use App\Entity\Attachments\Attachment; +use App\Entity\Parameters\AbstractParameter; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; + +/** + * API Platform has problems with single table inheritance, as it assumes that they all have different endpoints. + * This decorator fixes this problem by using the parent class for the metadata collection. + */ +#[AsDecorator('api_platform.metadata.resource.metadata_collection_factory')] +class FixInheritanceMappingMetadataFacory implements ResourceMetadataCollectionFactoryInterface +{ + private const SINGLE_INHERITANCE_ENTITY_CLASSES = [ + Attachment::class, + AbstractParameter::class, + ]; + + private array $cache = []; + + public function __construct(private readonly ResourceMetadataCollectionFactoryInterface $decorated) + { + } + + public function create(string $resourceClass): ResourceMetadataCollection + { + //If we already have a cached value, we can return it + if (isset($this->cache[$resourceClass])) { + return $this->decorated->create($this->cache[$resourceClass]); + } + + //Check if the resourceClass is a single inheritance class, then we can use the parent class to access it + foreach (self::SINGLE_INHERITANCE_ENTITY_CLASSES as $class) { + if (is_a($resourceClass, $class, true)) { + $this->cache[$resourceClass] = $class; + break; + } + } + + //If it was not found in the list of single inheritance classes, we can use the original class + if (!isset($this->cache[$resourceClass])) { + $this->cache[$resourceClass] = $resourceClass; + } + + return $this->decorated->create($this->cache[$resourceClass] ?? $resourceClass); + } +} \ No newline at end of file diff --git a/src/ApiPlatform/HandleAttachmentsUploadsProcessor.php b/src/ApiPlatform/HandleAttachmentsUploadsProcessor.php new file mode 100644 index 00000000..b5149442 --- /dev/null +++ b/src/ApiPlatform/HandleAttachmentsUploadsProcessor.php @@ -0,0 +1,67 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform; + +use ApiPlatform\Metadata\DeleteOperationInterface; +use ApiPlatform\Metadata\Operation; +use ApiPlatform\State\ProcessorInterface; +use App\Entity\Attachments\Attachment; +use App\Services\Attachments\AttachmentSubmitHandler; +use Symfony\Component\DependencyInjection\Attribute\Autowire; + +/** + * This state processor handles the upload property set on the deserialized attachment entity and + * calls the upload handler service to handle the upload. + */ +final class HandleAttachmentsUploadsProcessor implements ProcessorInterface +{ + public function __construct( + #[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')] + private readonly ProcessorInterface $persistProcessor, + #[Autowire(service: 'api_platform.doctrine.orm.state.remove_processor')] + private readonly ProcessorInterface $removeProcessor, + private readonly AttachmentSubmitHandler $attachmentSubmitHandler + ) { + + } + + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed + { + if ($operation instanceof DeleteOperationInterface) { + return $this->removeProcessor->process($data, $operation, $uriVariables, $context); + } + + //Check if the attachment has any upload data we need to handle + //This have to happen before the persist processor is called, because the changes on the entity must be saved! + if ($data instanceof Attachment && $data->getUpload()) { + $upload = $data->getUpload(); + //Reset the upload data + $data->setUpload(null); + + $this->attachmentSubmitHandler->handleUpload($data, $upload); + } + + return $this->persistProcessor->process($data, $operation, $uriVariables, $context); + } +} \ No newline at end of file diff --git a/src/ApiPlatform/NormalizePropertyNameCollectionFactory.php b/src/ApiPlatform/NormalizePropertyNameCollectionFactory.php new file mode 100644 index 00000000..c6a8220e --- /dev/null +++ b/src/ApiPlatform/NormalizePropertyNameCollectionFactory.php @@ -0,0 +1,77 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform; + +use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface; +use ApiPlatform\Metadata\Property\PropertyNameCollection; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use function Symfony\Component\String\u; + +/** + * This decorator removes all camelCase property names from the property name collection, if a snake_case version exists. + * This is a fix for https://github.com/Part-DB/Part-DB-server/issues/862, as the openapi schema generator wrongly collects + * both camelCase and snake_case property names, which leads to duplicate properties in the schema. + * This seems to come from the fact that the openapi schema generator uses no serializerContext, which seems then to collect + * the getters too... + */ +#[AsDecorator('api_platform.metadata.property.name_collection_factory')] +class NormalizePropertyNameCollectionFactory implements PropertyNameCollectionFactoryInterface +{ + public function __construct(private readonly PropertyNameCollectionFactoryInterface $decorated) + { + } + + public function create(string $resourceClass, array $options = []): PropertyNameCollection + { + // Get the default properties from the decorated service + $propertyNames = $this->decorated->create($resourceClass, $options); + + //Only become active in the context of the openapi schema generation + if (!isset($options['schema_type'])) { + return $propertyNames; + } + + //If we are not in the jsonapi generator (which sets no serializer groups), return the property names as is + if (isset($options['serializer_groups'])) { + return $propertyNames; + } + + //Remove all camelCase property names from the collection, if a snake_case version exists + $properties = iterator_to_array($propertyNames); + + foreach ($properties as $property) { + if (str_contains($property, '_')) { + $camelized = u($property)->camel()->toString(); + + //If the camelized version exists, remove it from the collection + $index = array_search($camelized, $properties, true); + if ($index !== false) { + unset($properties[$index]); + } + } + } + + return new PropertyNameCollection($properties); + } +} \ No newline at end of file diff --git a/src/ApiPlatform/OpenApiFactoryDecorator.php b/src/ApiPlatform/OpenApiFactoryDecorator.php new file mode 100644 index 00000000..af213e14 --- /dev/null +++ b/src/ApiPlatform/OpenApiFactoryDecorator.php @@ -0,0 +1,50 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiPlatform; + +use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface; +use ApiPlatform\OpenApi\Model\SecurityScheme; +use ApiPlatform\OpenApi\OpenApi; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; + +#[AsDecorator('api_platform.openapi.factory')] +class OpenApiFactoryDecorator implements OpenApiFactoryInterface +{ + public function __construct(private readonly OpenApiFactoryInterface $decorated) + { + } + + public function __invoke(array $context = []): OpenApi + { + $openApi = $this->decorated->__invoke($context); + $securitySchemes = $openApi->getComponents()->getSecuritySchemes() ?: new \ArrayObject(); + $securitySchemes['access_token'] = new SecurityScheme( + type: 'http', + description: 'Use an API token to authenticate', + name: 'Authorization', + scheme: 'bearer', + ); + return $openApi; + } +} \ No newline at end of file diff --git a/src/ApiResource/PartDBInfo.php b/src/ApiResource/PartDBInfo.php new file mode 100644 index 00000000..25aed05e --- /dev/null +++ b/src/ApiResource/PartDBInfo.php @@ -0,0 +1,67 @@ +. + */ + +declare(strict_types=1); + + +namespace App\ApiResource; + +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Get; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\State\PartDBInfoProvider; + +/** + * This class is used to provide various information about the system. + */ +#[ApiResource( + uriTemplate: '/info.{_format}', + description: 'Basic information about Part-DB like version, title, etc.', + operations: [new Get(openapi: new Operation(summary: 'Get basic information about the installed Part-DB instance.'))], + provider: PartDBInfoProvider::class +)] +#[ApiFilter(PropertyFilter::class)] +class PartDBInfo +{ + public function __construct( + /** The installed Part-DB version */ + public readonly string $version, + /** The Git branch name of the Part-DB version (or null, if not installed via git) */ + public readonly string|null $git_branch, + /** The Git branch commit of the Part-DB version (or null, if not installed via git) */ + public readonly string|null $git_commit, + /** The name of this Part-DB instance */ + public readonly string $title, + /** The banner, shown on homepage (markdown encoded) */ + public readonly string $banner, + /** The configured default URI for Part-DB */ + public readonly string $default_uri, + /** The global timezone of this Part-DB */ + public readonly string $global_timezone, + /** The base currency of Part-DB, used as internal representation of monetary values */ + public readonly string $base_currency, + /** The configured default language of Part-DB */ + public readonly string $global_locale, + ) { + + } +} \ No newline at end of file diff --git a/src/Command/Attachments/CleanAttachmentsCommand.php b/src/Command/Attachments/CleanAttachmentsCommand.php index e9ffd286..59bc99ee 100644 --- a/src/Command/Attachments/CleanAttachmentsCommand.php +++ b/src/Command/Attachments/CleanAttachmentsCommand.php @@ -73,6 +73,9 @@ class CleanAttachmentsCommand extends Command //Ignore image cache folder $finder->exclude('cache'); + //Ignore automigration folder + $finder->exclude('.automigration-backup'); + $fs = new Filesystem(); $file_list = []; diff --git a/src/Command/Attachments/DownloadAttachmentsCommand.php b/src/Command/Attachments/DownloadAttachmentsCommand.php new file mode 100644 index 00000000..34deef0e --- /dev/null +++ b/src/Command/Attachments/DownloadAttachmentsCommand.php @@ -0,0 +1,136 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Command\Attachments; + +use App\Entity\Attachments\Attachment; +use App\Entity\Attachments\AttachmentUpload; +use App\Exceptions\AttachmentDownloadException; +use App\Services\Attachments\AttachmentManager; +use App\Services\Attachments\AttachmentSubmitHandler; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +#[AsCommand('partdb:attachments:download', "Downloads all attachments which have only an external URL to the local filesystem.")] +class DownloadAttachmentsCommand extends Command +{ + public function __construct(private readonly AttachmentSubmitHandler $attachmentSubmitHandler, + private EntityManagerInterface $entityManager) + { + parent::__construct(); + } + + public function configure(): void + { + $this->setHelp('This command downloads all attachments, which only have an external URL, to the local filesystem, so that you have an offline copy of the attachments.'); + $this->addOption('--private', null, null, 'If set, the attachments will be downloaded to the private storage.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $qb = $this->entityManager->createQueryBuilder(); + $qb->select('attachment') + ->from(Attachment::class, 'attachment') + ->where('attachment.external_path IS NOT NULL') + ->andWhere('attachment.external_path != \'\'') + ->andWhere('attachment.internal_path IS NULL'); + + $query = $qb->getQuery(); + $attachments = $query->getResult(); + + if (count($attachments) === 0) { + $io->success('No attachments with external URL found.'); + return Command::SUCCESS; + } + + $io->note('Found ' . count($attachments) . ' attachments with external URL, that will be downloaded.'); + + //If the option --private is set, the attachments will be downloaded to the private storage. + $private = $input->getOption('private'); + if ($private) { + if (!$io->confirm('Attachments will be downloaded to the private storage. Continue?')) { + return Command::SUCCESS; + } + } else { + if (!$io->confirm('Attachments will be downloaded to the public storage, where everybody knowing the correct URL can access it. Continue?')){ + return Command::SUCCESS; + } + } + + $progressBar = $io->createProgressBar(count($attachments)); + $progressBar->setFormat("%current%/%max% [%bar%] %percent:3s%% %elapsed:16s%/%estimated:-16s% \n%message%"); + + $progressBar->setMessage('Starting download...'); + $progressBar->start(); + + + $errors = []; + + foreach ($attachments as $attachment) { + /** @var Attachment $attachment */ + $progressBar->setMessage(sprintf('%s (ID: %s) from %s', $attachment->getName(), $attachment->getID(), $attachment->getHost())); + $progressBar->advance(); + + try { + $attachmentUpload = new AttachmentUpload(file: null, downloadUrl: true, private: $private); + $this->attachmentSubmitHandler->handleUpload($attachment, $attachmentUpload); + + //Write changes to the database + $this->entityManager->flush(); + } catch (AttachmentDownloadException $e) { + $errors[] = [ + 'attachment' => $attachment, + 'error' => $e->getMessage() + ]; + } + } + + $progressBar->finish(); + + //Fix the line break after the progress bar + $io->newLine(); + $io->newLine(); + + if (count($errors) > 0) { + $io->warning('Some attachments could not be downloaded:'); + foreach ($errors as $error) { + $io->warning(sprintf("Attachment %s (ID %s) could not be downloaded from %s:\n%s", + $error['attachment']->getName(), + $error['attachment']->getID(), + $error['attachment']->getExternalPath(), + $error['error']) + ); + } + } else { + $io->success('All attachments downloaded successfully.'); + } + + return Command::SUCCESS; + } +} \ No newline at end of file diff --git a/src/Command/Attachments/SanitizeSVGAttachmentsCommand.php b/src/Command/Attachments/SanitizeSVGAttachmentsCommand.php new file mode 100644 index 00000000..7f6550f0 --- /dev/null +++ b/src/Command/Attachments/SanitizeSVGAttachmentsCommand.php @@ -0,0 +1,90 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Command\Attachments; + +use App\Entity\Attachments\Attachment; +use App\Services\Attachments\AttachmentSubmitHandler; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +#[AsCommand('partdb:attachments:sanitize-svg', "Sanitize uploaded SVG files.")] +class SanitizeSVGAttachmentsCommand extends Command +{ + public function __construct(private readonly EntityManagerInterface $entityManager, private readonly AttachmentSubmitHandler $attachmentSubmitHandler, ?string $name = null) + { + parent::__construct($name); + } + + public function configure(): void + { + $this->setHelp('This command allows to sanitize SVG files uploaded via attachments. This happens automatically since version 1.17.1, this command is intended to be used for older files.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $io->info('This command will sanitize all uploaded SVG files. This is only required if you have uploaded (untrusted) SVG files before version 1.17.1. If you are running a newer version, you don\'t need to run this command (again).'); + if (!$io->confirm('Do you want to continue?', false)) { + $io->success('Command aborted.'); + return Command::FAILURE; + } + + $io->info('Sanitizing SVG files...'); + + //Finding all attachments with svg files + $qb = $this->entityManager->createQueryBuilder(); + $qb->select('a') + ->from(Attachment::class, 'a') + ->where('a.internal_path LIKE :pattern ESCAPE \'#\'') + ->orWhere('a.original_filename LIKE :pattern ESCAPE \'#\'') + ->setParameter('pattern', '%.svg'); + + $attachments = $qb->getQuery()->getResult(); + $io->note('Found '.count($attachments).' attachments with SVG files.'); + + if (count($attachments) === 0) { + $io->success('No SVG files found.'); + return Command::FAILURE; + } + + $io->info('Sanitizing SVG files...'); + $io->progressStart(count($attachments)); + foreach ($attachments as $attachment) { + /** @var Attachment $attachment */ + $io->note('Sanitizing attachment '.$attachment->getId().' ('.($attachment->getFilename() ?? '???').')'); + $this->attachmentSubmitHandler->sanitizeSVGAttachment($attachment); + $io->progressAdvance(); + + } + $io->progressFinish(); + + $io->success('Sanitization finished. All SVG files have been sanitized.'); + return Command::SUCCESS; + } +} \ No newline at end of file diff --git a/src/Command/BackupCommand.php b/src/Command/BackupCommand.php index ef7d038f..085c552a 100644 --- a/src/Command/BackupCommand.php +++ b/src/Command/BackupCommand.php @@ -4,8 +4,10 @@ declare(strict_types=1); namespace App\Command; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Spatie\DbDumper\Databases\PostgreSql; use Symfony\Component\Console\Attribute\AsCommand; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\ORM\EntityManagerInterface; use PhpZip\Constants\ZipCompressionMethod; @@ -50,6 +52,7 @@ class BackupCommand extends Command $backup_attachments = $input->getOption('attachments'); $backup_config = $input->getOption('config'); $backup_full = $input->getOption('full'); + $overwrite = $input->getOption('overwrite'); if ($backup_full) { $backup_database = true; @@ -68,7 +71,9 @@ class BackupCommand extends Command //Check if the file already exists //Then ask the user, if he wants to overwrite the file - if (file_exists($output_filepath) && !$io->confirm('The file '.realpath($output_filepath).' already exists. Do you want to overwrite it?', false)) { + if (!$overwrite + && file_exists($output_filepath) + && !$io->confirm('The file '.realpath($output_filepath).' already exists. Do you want to overwrite it?', false)) { $io->error('Backup aborted!'); return Command::FAILURE; } @@ -136,30 +141,42 @@ class BackupCommand extends Command } } + private function runSQLDumper(DbDumper $dumper, ZipFile $zip, array $connectionParams): void + { + $this->configureDumper($connectionParams, $dumper); + + $tmp_file = tempnam(sys_get_temp_dir(), 'partdb_sql_dump'); + + $dumper->dumpToFile($tmp_file); + $zip->addFile($tmp_file, 'database.sql'); + } + protected function backupDatabase(ZipFile $zip, SymfonyStyle $io): void { $io->note('Backup database...'); //Determine if we use MySQL or SQLite $connection = $this->entityManager->getConnection(); - if ($connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) { + $params = $connection->getParams(); + $platform = $connection->getDatabasePlatform(); + if ($platform instanceof AbstractMySQLPlatform) { try { $io->note('MySQL database detected. Dump DB to SQL using mysqldump...'); - $params = $connection->getParams(); - $dumper = MySql::create(); - $this->configureDumper($params, $dumper); - - $tmp_file = tempnam(sys_get_temp_dir(), 'partdb_sql_dump'); - - $dumper->dumpToFile($tmp_file); - $zip->addFile($tmp_file, 'mysql_dump.sql'); + $this->runSQLDumper(MySql::create(), $zip, $params); } catch (\Exception $e) { $io->error('Could not dump database: '.$e->getMessage()); $io->error('This can maybe be fixed by installing the mysqldump binary and adding it to the PATH variable!'); } - } elseif ($connection->getDatabasePlatform() instanceof SqlitePlatform) { + } elseif ($platform instanceof PostgreSQLPlatform) { + try { + $io->note('PostgreSQL database detected. Dump DB to SQL using pg_dump...'); + $this->runSQLDumper(PostgreSql::create(), $zip, $params); + } catch (\Exception $e) { + $io->error('Could not dump database: '.$e->getMessage()); + $io->error('This can maybe be fixed by installing the pg_dump binary and adding it to the PATH variable!'); + } + } elseif ($platform instanceof SQLitePlatform) { $io->note('SQLite database detected. Copy DB file to ZIP...'); - $params = $connection->getParams(); $zip->addFile($params['path'], 'var/app.db'); } else { $io->error('Unknown database platform. Could not backup database!'); diff --git a/src/Command/CheckRequirementsCommand.php b/src/Command/CheckRequirementsCommand.php index 068147e2..5e15e8e2 100644 --- a/src/Command/CheckRequirementsCommand.php +++ b/src/Command/CheckRequirementsCommand.php @@ -76,6 +76,17 @@ class CheckRequirementsCommand extends Command $io->success('PHP version is sufficient.'); } + //Checking 32-bit system + if (PHP_INT_SIZE === 4) { + $io->warning('You are using a 32-bit system. You will have problems with working with dates after the year 2038, therefore a 64-bit system is recommended.'); + } elseif (PHP_INT_SIZE === 8) { //@phpstan-ignore-line //PHP_INT_SIZE is always 4 or 8 + if (!$only_issues) { + $io->success('You are using a 64-bit system.'); + } + } else { + $io->warning('You are using a system with an unknown bit size. That is interesting xD'); + } + //Check if opcache is enabled if ($io->isVerbose()) { $io->comment('Checking Opcache...'); diff --git a/src/Command/LoadFixturesCommand.php b/src/Command/LoadFixturesCommand.php new file mode 100644 index 00000000..d01d19c3 --- /dev/null +++ b/src/Command/LoadFixturesCommand.php @@ -0,0 +1,73 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Command; + +use App\Doctrine\Purger\ResetAutoIncrementPurgerFactory; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * This command does basically the same as doctrine:fixtures:load, but it purges the database before loading the fixtures. + * It does so in another transaction, so we can modify the purger to reset the autoincrement, which would not be possible + * because the implicit commit otherwise. + */ +#[AsCommand(name: 'partdb:fixtures:load', description: 'Load test fixtures into the database and allows to reset the autoincrement before loading the fixtures.', hidden: true)] +class LoadFixturesCommand extends Command +{ + public function __construct(private readonly EntityManagerInterface $entityManager) + { + parent::__construct(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $ui = new SymfonyStyle($input, $output); + + $ui->warning('This command is for development and testing purposes only. It will purge the database and load fixtures afterwards. Do not use in production!'); + + if (! $ui->confirm(sprintf('Careful, database "%s" will be purged. Do you want to continue?', $this->entityManager->getConnection()->getDatabase()), ! $input->isInteractive())) { + return 0; + } + + $factory = new ResetAutoIncrementPurgerFactory(); + $purger = $factory->createForEntityManager(null, $this->entityManager); + + $purger->purge(); + + //Afterwards run the load fixtures command as normal, but with the --append option + $new_input = new ArrayInput([ + 'command' => 'doctrine:fixtures:load', + '--append' => true, + ]); + + $returnCode = $this->getApplication()?->doRun($new_input, $output); + + return $returnCode ?? Command::FAILURE; + } +} \ No newline at end of file diff --git a/src/Command/Logs/ShowEventLogCommand.php b/src/Command/Logs/ShowEventLogCommand.php index 2d11b359..505b1275 100644 --- a/src/Command/Logs/ShowEventLogCommand.php +++ b/src/Command/Logs/ShowEventLogCommand.php @@ -65,12 +65,12 @@ class ShowEventLogCommand extends Command $max_page = (int) ceil($total_count / $limit); if ($page > $max_page && $max_page > 0) { - $io->error("There is no page ${page}! The maximum page is ${max_page}."); + $io->error("There is no page $page! The maximum page is $max_page."); return Command::FAILURE; } - $io->note("There are a total of ${total_count} log entries in the DB."); + $io->note("There are a total of $total_count log entries in the DB."); $continue = true; while ($continue && $page <= $max_page) { @@ -105,7 +105,7 @@ class ShowEventLogCommand extends Command $entries = $this->repo->getLogsOrderedByTimestamp($sorting, $limit, $offset); $table = new Table($output); - $table->setHeaderTitle("Page ${page} / ${max_page}"); + $table->setHeaderTitle("Page $page / $max_page"); $headers = ['ID', 'Timestamp', 'Type', 'User', 'Target Type', 'Target']; if ($showExtra) { $headers[] = 'Extra data'; diff --git a/src/Command/Migrations/ConvertBBCodeCommand.php b/src/Command/Migrations/ConvertBBCodeCommand.php index 2297cbdd..201263ff 100644 --- a/src/Command/Migrations/ConvertBBCodeCommand.php +++ b/src/Command/Migrations/ConvertBBCodeCommand.php @@ -30,7 +30,7 @@ use App\Entity\Parts\Category; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; use App\Entity\UserSystem\Group; @@ -79,13 +79,14 @@ class ConvertBBCodeCommand extends Command /** * Returns a list which entities and which properties need to be checked. + * @return array, string[]> */ protected function getTargetsLists(): array { return [ Part::class => ['description', 'comment'], AttachmentType::class => ['comment'], - Storelocation::class => ['comment'], + StorageLocation::class => ['comment'], Project::class => ['comment'], Category::class => ['comment'], Manufacturer::class => ['comment'], @@ -109,7 +110,6 @@ class ConvertBBCodeCommand extends Command $class )); //Determine which entities of this type we need to modify - /** @var EntityRepository $repo */ $repo = $this->em->getRepository($class); $qb = $repo->createQueryBuilder('e') ->select('e'); diff --git a/src/Command/User/SetPasswordCommand.php b/src/Command/User/SetPasswordCommand.php index 822277f1..30ef867b 100644 --- a/src/Command/User/SetPasswordCommand.php +++ b/src/Command/User/SetPasswordCommand.php @@ -83,6 +83,19 @@ class SetPasswordCommand extends Command while (!$success) { $pw1 = $io->askHidden('Please enter new password:'); + + if ($pw1 === null) { + $io->error('No password entered! Please try again.'); + + //If we are in non-interactive mode, we can not ask again + if (!$input->isInteractive()) { + $io->warning('Non-interactive mode detected. No password can be entered that way! If you are using docker exec, please use -it flag.'); + return Command::FAILURE; + } + + continue; + } + $pw2 = $io->askHidden('Please confirm:'); if ($pw1 !== $pw2) { $io->error('The entered password did not match! Please try again.'); diff --git a/src/Command/User/UserEnableCommand.php b/src/Command/User/UserEnableCommand.php index 00753e94..51ff2280 100644 --- a/src/Command/User/UserEnableCommand.php +++ b/src/Command/User/UserEnableCommand.php @@ -35,7 +35,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; #[AsCommand('partdb:users:enable|partdb:user:enable', 'Enables/Disable the login of one or more users')] class UserEnableCommand extends Command { - public function __construct(protected EntityManagerInterface $entityManager, string $name = null) + public function __construct(protected EntityManagerInterface $entityManager, ?string $name = null) { parent::__construct($name); } diff --git a/src/Command/User/UsersPermissionsCommand.php b/src/Command/User/UsersPermissionsCommand.php index 021853bb..6408e9c9 100644 --- a/src/Command/User/UsersPermissionsCommand.php +++ b/src/Command/User/UsersPermissionsCommand.php @@ -206,12 +206,15 @@ class UsersPermissionsCommand extends Command return 'Allow'; } elseif ($permission_value === false) { return 'Disallow'; - } elseif ($permission_value === null && !$inherit) { + } + // Permission value is null by this point + elseif (!$inherit) { return 'Inherit'; - } elseif ($permission_value === null && $inherit) { + } elseif ($inherit) { return 'Disallow (Inherited)'; } + //@phpstan-ignore-next-line This line is never reached, but PHPstorm complains otherwise return '???'; } } diff --git a/src/Configuration/PermissionsConfiguration.php b/src/Configuration/PermissionsConfiguration.php index 307e3794..c069ab24 100644 --- a/src/Configuration/PermissionsConfiguration.php +++ b/src/Configuration/PermissionsConfiguration.php @@ -55,6 +55,7 @@ final class PermissionsConfiguration implements ConfigurationInterface ->scalarNode('name')->end() ->scalarNode('label')->end() ->scalarNode('bit')->end() + ->scalarNode('apiTokenRole')->defaultNull()->end() ->arrayNode('alsoSet') ->beforeNormalization()->castToArray()->end()->scalarPrototype()->end(); diff --git a/src/Controller/AdminPages/AttachmentTypeController.php b/src/Controller/AdminPages/AttachmentTypeController.php index 426e773c..08c10da1 100644 --- a/src/Controller/AdminPages/AttachmentTypeController.php +++ b/src/Controller/AdminPages/AttachmentTypeController.php @@ -34,7 +34,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; /** * @see \App\Tests\Controller\AdminPages\AttachmentTypeControllerTest @@ -55,7 +55,7 @@ class AttachmentTypeController extends BaseAdminController return $this->_delete($request, $entity, $recursionHelper); } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'attachment_type_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'attachment_type_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}', requirements: ['id' => '\d+'])] public function edit(AttachmentType $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { diff --git a/src/Controller/AdminPages/BaseAdminController.php b/src/Controller/AdminPages/BaseAdminController.php index 9f43d07d..edc5917a 100644 --- a/src/Controller/AdminPages/BaseAdminController.php +++ b/src/Controller/AdminPages/BaseAdminController.php @@ -24,6 +24,8 @@ namespace App\Controller\AdminPages; use App\DataTables\LogDataTable; use App\Entity\Attachments\Attachment; +use App\Entity\Attachments\AttachmentContainingDBElement; +use App\Entity\Attachments\AttachmentUpload; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Base\AbstractPartsContainingDBElement; @@ -32,8 +34,8 @@ use App\Entity\Base\PartsContainingRepositoryInterface; use App\Entity\LabelSystem\LabelProcessMode; use App\Entity\LabelSystem\LabelProfile; use App\Entity\Parameters\AbstractParameter; -use App\Entity\UserSystem\User; use App\Exceptions\AttachmentDownloadException; +use App\Exceptions\TwigModeException; use App\Form\AdminPages\ImportType; use App\Form\AdminPages\MassCreationForm; use App\Repository\AbstractPartsContainingRepository; @@ -51,8 +53,8 @@ use Doctrine\ORM\EntityManagerInterface; use InvalidArgumentException; use Omines\DataTablesBundle\DataTableFactory; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\RedirectResponse; @@ -60,7 +62,8 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Component\Serializer\Exception\UnexpectedValueException; -use Symfony\Component\Validator\ConstraintViolationList; +use Symfony\Component\Validator\ConstraintViolationInterface; +use Symfony\Component\Validator\ConstraintViolationListInterface; use Symfony\Contracts\Translation\TranslatorInterface; use function Symfony\Component\Translation\t; @@ -73,15 +76,11 @@ abstract class BaseAdminController extends AbstractController protected string $route_base = ''; protected string $attachment_class = ''; protected ?string $parameter_class = ''; - /** - * @var EventDispatcher|EventDispatcherInterface - */ - protected $eventDispatcher; public function __construct(protected TranslatorInterface $translator, protected UserPasswordHasherInterface $passwordEncoder, protected AttachmentSubmitHandler $attachmentSubmitHandler, protected EventCommentHelper $commentHelper, protected HistoryHelper $historyHelper, protected TimeTravel $timeTravel, - protected DataTableFactory $dataTableFactory, EventDispatcherInterface $eventDispatcher, protected LabelExampleElementsGenerator $barcodeExampleGenerator, + protected DataTableFactory $dataTableFactory, protected EventDispatcherInterface $eventDispatcher, protected LabelExampleElementsGenerator $barcodeExampleGenerator, protected LabelGenerator $labelGenerator, protected EntityManagerInterface $entityManager) { if ('' === $this->entity_class || '' === $this->form_class || '' === $this->twig_template || '' === $this->route_base) { @@ -95,7 +94,6 @@ abstract class BaseAdminController extends AbstractController if ('' === $this->parameter_class || ($this->parameter_class && !is_a($this->parameter_class, AbstractParameter::class, true))) { throw new InvalidArgumentException('You have to override the $parameter_class value with a valid Parameter class in your subclass!'); } - $this->eventDispatcher = $eventDispatcher; } protected function revertElementIfNeeded(AbstractDBElement $entity, ?string $timestamp): ?DateTime @@ -175,16 +173,10 @@ abstract class BaseAdminController extends AbstractController $attachments = $form['attachments']; foreach ($attachments as $attachment) { /** @var FormInterface $attachment */ - $options = [ - 'secure_attachment' => $attachment['secureFile']->getData(), - 'download_url' => $attachment['downloadURL']->getData(), - ]; - try { - $this->attachmentSubmitHandler->handleFormSubmit( + $this->attachmentSubmitHandler->handleUpload( $attachment->getData(), - $attachment['file']->getData(), - $options + AttachmentUpload::fromAttachmentForm($attachment) ); } catch (AttachmentDownloadException $attachmentDownloadException) { $this->addFlash( @@ -196,6 +188,11 @@ abstract class BaseAdminController extends AbstractController } } + //Ensure that the master picture is still part of the attachments + if ($entity instanceof AttachmentContainingDBElement && ($entity->getMasterPictureAttachment() !== null && !$entity->getAttachments()->contains($entity->getMasterPictureAttachment()))) { + $entity->setMasterPictureAttachment(null); + } + $this->commentHelper->setMessage($form['log_comment']->getData()); $em->persist($entity); @@ -216,10 +213,14 @@ abstract class BaseAdminController extends AbstractController //Show preview for LabelProfile if needed. if ($entity instanceof LabelProfile) { $example = $this->barcodeExampleGenerator->getElement($entity->getOptions()->getSupportedElement()); - $pdf_data = $this->labelGenerator->generateLabel($entity->getOptions(), $example); + $pdf_data = null; + try { + $pdf_data = $this->labelGenerator->generateLabel($entity->getOptions(), $example); + } catch (TwigModeException $exception) { + $form->get('options')->get('lines')->addError(new FormError($exception->getSafeMessage())); + } } - /** @var AbstractPartsContainingRepository $repo */ $repo = $this->entityManager->getRepository($this->entity_class); return $this->render($this->twig_template, [ @@ -264,16 +265,11 @@ abstract class BaseAdminController extends AbstractController $attachments = $form['attachments']; foreach ($attachments as $attachment) { /** @var FormInterface $attachment */ - $options = [ - 'secure_attachment' => $attachment['secureFile']->getData(), - 'download_url' => $attachment['downloadURL']->getData(), - ]; try { - $this->attachmentSubmitHandler->handleFormSubmit( + $this->attachmentSubmitHandler->handleUpload( $attachment->getData(), - $attachment['file']->getData(), - $options + AttachmentUpload::fromAttachmentForm($attachment) ); } catch (AttachmentDownloadException $attachmentDownloadException) { $this->addFlash( @@ -284,6 +280,12 @@ abstract class BaseAdminController extends AbstractController ); } } + + //Ensure that the master picture is still part of the attachments + if ($new_entity instanceof AttachmentContainingDBElement && ($new_entity->getMasterPictureAttachment() !== null && !$new_entity->getAttachments()->contains($new_entity->getMasterPictureAttachment()))) { + $new_entity->setMasterPictureAttachment(null); + } + $this->commentHelper->setMessage($form['log_comment']->getData()); $em->persist($new_entity); $em->flush(); @@ -328,8 +330,8 @@ abstract class BaseAdminController extends AbstractController try { $errors = $importer->importFileAndPersistToDB($file, $options); - foreach ($errors as $name => $error) { - foreach ($error as $violation) { + foreach ($errors as $name => ['violations' => $violations]) { + foreach ($violations as $violation) { $this->addFlash('error', $name.': '.$violation->getMessage()); } } @@ -339,6 +341,7 @@ abstract class BaseAdminController extends AbstractController } } + ret: //Mass creation form $mass_creation_form = $this->createForm(MassCreationForm::class, ['entity_class' => $this->entity_class]); $mass_creation_form->handleRequest($request); @@ -351,11 +354,14 @@ abstract class BaseAdminController extends AbstractController $results = $importer->massCreation($data['lines'], $this->entity_class, $data['parent'] ?? null, $errors); //Show errors to user: - foreach ($errors as $error) { - if ($error['entity'] instanceof AbstractStructuralDBElement) { - $this->addFlash('error', $error['entity']->getFullPath().':'.$error['violations']); - } else { //When we don't have a structural element, we can only show the name - $this->addFlash('error', $error['entity']->getName().':'.$error['violations']); + foreach ($errors as ['entity' => $new_entity, 'violations' => $violations]) { + /** @var ConstraintViolationInterface $violation */ + foreach ($violations as $violation) { + if ($new_entity instanceof AbstractStructuralDBElement) { + $this->addFlash('error', $new_entity->getFullPath().':'.$violation->getMessage()); + } else { //When we don't have a structural element, we can only show the name + $this->addFlash('error', $new_entity->getName().':'.$violation->getMessage()); + } } } @@ -364,9 +370,12 @@ abstract class BaseAdminController extends AbstractController $em->persist($result); } $em->flush(); + + if (count($results) > 0) { + $this->addFlash('success', t('entity.mass_creation_flash', ['%COUNT%' => count($results)])); + } } - ret: return $this->render($this->twig_template, [ 'entity' => $new_entity, 'form' => $form, @@ -387,7 +396,7 @@ abstract class BaseAdminController extends AbstractController { if ($entity instanceof AbstractPartsContainingDBElement) { /** @var AbstractPartsContainingRepository $repo */ - $repo = $this->entityManager->getRepository($this->entity_class); + $repo = $this->entityManager->getRepository($this->entity_class); //@phpstan-ignore-line if ($repo->getPartsCount($entity) > 0) { $this->addFlash('error', t('entity.delete.must_not_contain_parts', ['%PATH%' => $entity->getFullPath()])); @@ -458,6 +467,11 @@ abstract class BaseAdminController extends AbstractController $this->denyAccessUnlessGranted('read', $entity); $entities = $em->getRepository($this->entity_class)->findAll(); + if (count($entities) === 0) { + $this->addFlash('error', 'entity.export.flash.error.no_entities'); + return $this->redirectToRoute($this->route_base.'_new'); + } + return $exporter->exportEntityFromRequest($entities, $request); } diff --git a/src/Controller/AdminPages/CategoryController.php b/src/Controller/AdminPages/CategoryController.php index 153d46f3..361df625 100644 --- a/src/Controller/AdminPages/CategoryController.php +++ b/src/Controller/AdminPages/CategoryController.php @@ -33,7 +33,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; /** * @see \App\Tests\Controller\AdminPages\CategoryControllerTest @@ -54,7 +54,7 @@ class CategoryController extends BaseAdminController return $this->_delete($request, $entity, $recursionHelper); } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'category_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'category_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}', requirements: ['id' => '\d+'])] public function edit(Category $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { diff --git a/src/Controller/AdminPages/CurrencyController.php b/src/Controller/AdminPages/CurrencyController.php index 18d449fd..4450e157 100644 --- a/src/Controller/AdminPages/CurrencyController.php +++ b/src/Controller/AdminPages/CurrencyController.php @@ -38,7 +38,6 @@ use App\Services\LogSystem\HistoryHelper; use App\Services\LogSystem\TimeTravel; use App\Services\Trees\StructuralElementRecursionHelper; use Doctrine\ORM\EntityManagerInterface; -use Exchanger\Exception\ChainException; use Exchanger\Exception\Exception; use Exchanger\Exception\UnsupportedCurrencyPairException; use Omines\DataTablesBundle\DataTableFactory; @@ -48,7 +47,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Contracts\Translation\TranslatorInterface; /** @@ -124,7 +123,7 @@ class CurrencyController extends BaseAdminController return true; } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'currency_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'currency_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}', requirements: ['id' => '\d+'])] public function edit(Currency $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { diff --git a/src/Controller/AdminPages/FootprintController.php b/src/Controller/AdminPages/FootprintController.php index d1414d2a..3932e939 100644 --- a/src/Controller/AdminPages/FootprintController.php +++ b/src/Controller/AdminPages/FootprintController.php @@ -34,7 +34,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; /** * @see \App\Tests\Controller\AdminPages\FootprintControllerTest @@ -55,7 +55,7 @@ class FootprintController extends BaseAdminController return $this->_delete($request, $entity, $recursionHelper); } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'footprint_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'footprint_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}', requirements: ['id' => '\d+'])] public function edit(Footprint $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { diff --git a/src/Controller/AdminPages/LabelProfileController.php b/src/Controller/AdminPages/LabelProfileController.php index ee754436..7e7dfa1c 100644 --- a/src/Controller/AdminPages/LabelProfileController.php +++ b/src/Controller/AdminPages/LabelProfileController.php @@ -22,10 +22,8 @@ declare(strict_types=1); namespace App\Controller\AdminPages; -use App\Entity\Attachments\AttachmentType; use App\Entity\Attachments\LabelAttachment; use App\Entity\LabelSystem\LabelProfile; -use App\Entity\Parameters\AbstractParameter; use App\Form\AdminPages\LabelProfileAdminForm; use App\Services\ImportExportSystem\EntityExporter; use App\Services\ImportExportSystem\EntityImporter; @@ -34,7 +32,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; /** * @see \App\Tests\Controller\AdminPages\LabelProfileControllerTest */ @@ -55,7 +53,7 @@ class LabelProfileController extends BaseAdminController return $this->_delete($request, $entity, $recursionHelper); } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'label_profile_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'label_profile_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}', requirements: ['id' => '\d+'])] public function edit(LabelProfile $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { diff --git a/src/Controller/AdminPages/ManufacturerController.php b/src/Controller/AdminPages/ManufacturerController.php index 2a97d3f3..5fc4d4ac 100644 --- a/src/Controller/AdminPages/ManufacturerController.php +++ b/src/Controller/AdminPages/ManufacturerController.php @@ -33,7 +33,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; /** * @see \App\Tests\Controller\AdminPages\ManufacturerControllerTest @@ -54,7 +54,7 @@ class ManufacturerController extends BaseAdminController return $this->_delete($request, $entity, $recursionHelper); } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'manufacturer_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'manufacturer_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}', requirements: ['id' => '\d+'])] public function edit(Manufacturer $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { diff --git a/src/Controller/AdminPages/MeasurementUnitController.php b/src/Controller/AdminPages/MeasurementUnitController.php index 993c5dad..59c38ba4 100644 --- a/src/Controller/AdminPages/MeasurementUnitController.php +++ b/src/Controller/AdminPages/MeasurementUnitController.php @@ -34,7 +34,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; /** * @see \App\Tests\Controller\AdminPages\MeasurementUnitControllerTest @@ -55,7 +55,7 @@ class MeasurementUnitController extends BaseAdminController return $this->_delete($request, $entity, $recursionHelper); } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'measurement_unit_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'measurement_unit_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}', requirements: ['id' => '\d+'])] public function edit(MeasurementUnit $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { diff --git a/src/Controller/AdminPages/ProjectAdminController.php b/src/Controller/AdminPages/ProjectAdminController.php index 16bf6df1..41287b69 100644 --- a/src/Controller/AdminPages/ProjectAdminController.php +++ b/src/Controller/AdminPages/ProjectAdminController.php @@ -33,7 +33,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; #[Route(path: '/project')] class ProjectAdminController extends BaseAdminController @@ -51,7 +51,7 @@ class ProjectAdminController extends BaseAdminController return $this->_delete($request, $entity, $recursionHelper); } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'project_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'project_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}/edit', requirements: ['id' => '\d+'])] public function edit(Project $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { diff --git a/src/Controller/AdminPages/StorelocationController.php b/src/Controller/AdminPages/StorageLocationController.php similarity index 71% rename from src/Controller/AdminPages/StorelocationController.php rename to src/Controller/AdminPages/StorageLocationController.php index 7a9850ab..def6d3c6 100644 --- a/src/Controller/AdminPages/StorelocationController.php +++ b/src/Controller/AdminPages/StorageLocationController.php @@ -22,9 +22,9 @@ declare(strict_types=1); namespace App\Controller\AdminPages; -use App\Entity\Attachments\StorelocationAttachment; -use App\Entity\Parameters\StorelocationParameter; -use App\Entity\Parts\Storelocation; +use App\Entity\Attachments\StorageLocationAttachment; +use App\Entity\Parameters\StorageLocationParameter; +use App\Entity\Parts\StorageLocation; use App\Form\AdminPages\StorelocationAdminForm; use App\Services\ImportExportSystem\EntityExporter; use App\Services\ImportExportSystem\EntityImporter; @@ -33,30 +33,30 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; /** * @see \App\Tests\Controller\AdminPages\StorelocationControllerTest */ #[Route(path: '/store_location')] -class StorelocationController extends BaseAdminController +class StorageLocationController extends BaseAdminController { - protected string $entity_class = Storelocation::class; + protected string $entity_class = StorageLocation::class; protected string $twig_template = 'admin/storelocation_admin.html.twig'; protected string $form_class = StorelocationAdminForm::class; protected string $route_base = 'store_location'; - protected string $attachment_class = StorelocationAttachment::class; - protected ?string $parameter_class = StorelocationParameter::class; + protected string $attachment_class = StorageLocationAttachment::class; + protected ?string $parameter_class = StorageLocationParameter::class; #[Route(path: '/{id}', name: 'store_location_delete', methods: ['DELETE'])] - public function delete(Request $request, Storelocation $entity, StructuralElementRecursionHelper $recursionHelper): RedirectResponse + public function delete(Request $request, StorageLocation $entity, StructuralElementRecursionHelper $recursionHelper): RedirectResponse { return $this->_delete($request, $entity, $recursionHelper); } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'store_location_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'store_location_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}', requirements: ['id' => '\d+'])] - public function edit(Storelocation $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response + public function edit(StorageLocation $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { return $this->_edit($entity, $request, $em, $timestamp); } @@ -64,7 +64,7 @@ class StorelocationController extends BaseAdminController #[Route(path: '/new', name: 'store_location_new')] #[Route(path: '/{id}/clone', name: 'store_location_clone')] #[Route(path: '/')] - public function new(Request $request, EntityManagerInterface $em, EntityImporter $importer, ?Storelocation $entity = null): Response + public function new(Request $request, EntityManagerInterface $em, EntityImporter $importer, ?StorageLocation $entity = null): Response { return $this->_new($request, $em, $importer, $entity); } @@ -76,7 +76,7 @@ class StorelocationController extends BaseAdminController } #[Route(path: '/{id}/export', name: 'store_location_export')] - public function exportEntity(Storelocation $entity, EntityExporter $exporter, Request $request): Response + public function exportEntity(StorageLocation $entity, EntityExporter $exporter, Request $request): Response { return $this->_exportEntity($entity, $exporter, $request); } diff --git a/src/Controller/AdminPages/SupplierController.php b/src/Controller/AdminPages/SupplierController.php index 4cd5e46b..195b9e18 100644 --- a/src/Controller/AdminPages/SupplierController.php +++ b/src/Controller/AdminPages/SupplierController.php @@ -33,7 +33,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; /** * @see \App\Tests\Controller\AdminPages\SupplierControllerTest @@ -54,7 +54,7 @@ class SupplierController extends BaseAdminController return $this->_delete($request, $entity, $recursionHelper); } - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'supplier_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'supplier_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}', requirements: ['id' => '\d+'])] public function edit(Supplier $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response { diff --git a/src/Controller/AttachmentFileController.php b/src/Controller/AttachmentFileController.php index 16b07ab9..d8bd8d87 100644 --- a/src/Controller/AttachmentFileController.php +++ b/src/Controller/AttachmentFileController.php @@ -32,11 +32,10 @@ use Omines\DataTablesBundle\DataTableFactory; use RuntimeException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\BinaryFileResponse; -use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; class AttachmentFileController extends AbstractController { @@ -52,15 +51,15 @@ class AttachmentFileController extends AbstractController $this->denyAccessUnlessGranted('show_private', $attachment); } - if ($attachment->isExternal()) { - throw new RuntimeException('You can not download external attachments!'); + if (!$attachment->hasInternal()) { + throw $this->createNotFoundException('The file for this attachment is external and not stored locally!'); } - if (!$helper->isFileExisting($attachment)) { - throw new RuntimeException('The file associated with the attachment is not existing!'); + if (!$helper->isInternalFileExisting($attachment)) { + throw $this->createNotFoundException('The file associated with the attachment is not existing!'); } - $file_path = $helper->toAbsoluteFilePath($attachment); + $file_path = $helper->toAbsoluteInternalFilePath($attachment); $response = new BinaryFileResponse($file_path); //Set header content disposition, so that the file will be downloaded @@ -81,15 +80,15 @@ class AttachmentFileController extends AbstractController $this->denyAccessUnlessGranted('show_private', $attachment); } - if ($attachment->isExternal()) { - throw new RuntimeException('You can not download external attachments!'); + if (!$attachment->hasInternal()) { + throw $this->createNotFoundException('The file for this attachment is external and not stored locally!'); } - if (!$helper->isFileExisting($attachment)) { - throw new RuntimeException('The file associated with the attachment is not existing!'); + if (!$helper->isInternalFileExisting($attachment)) { + throw $this->createNotFoundException('The file associated with the attachment is not existing!'); } - $file_path = $helper->toAbsoluteFilePath($attachment); + $file_path = $helper->toAbsoluteInternalFilePath($attachment); $response = new BinaryFileResponse($file_path); //Set header content disposition, so that the file will be downloaded diff --git a/src/Controller/ErrorHandling/FixedErrorController.php b/src/Controller/ErrorHandling/FixedErrorController.php new file mode 100644 index 00000000..610a07b1 --- /dev/null +++ b/src/Controller/ErrorHandling/FixedErrorController.php @@ -0,0 +1,64 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Controller\ErrorHandling; + +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Controller\ErrorController; + +/** + * This class decorates the default error decorator and changes the content type of responses, if it went through a + * Turbo request. + * The problem is, that the default error controller returns in the format of the preferred content type of the request. + * This is turbo-stream. This causes Turbo to try to integrate it into the content frame and not trigger the ajax failed + * events to show the error in a popup like intended. + */ +#[AsDecorator("error_controller")] +class FixedErrorController +{ + public function __construct(private readonly ErrorController $decorated) + {} + + public function __invoke(\Throwable $exception): Response + { + $response = ($this->decorated)($exception); + + //Check the content type of the response + $contentType = $response->headers->get('Content-Type'); + + //If the content type is turbo stream, change the content type to html + //This prevents Turbo to render the response as a turbo stream, and forces to render it in the popup + if ($contentType === 'text/vnd.turbo-stream.html') { + $response->headers->set('Content-Type', 'text/html'); + } + + return $response; + } + + public function preview(Request $request, int $code): Response + { + return ($this->decorated)->preview($request, $code); + } +} \ No newline at end of file diff --git a/src/Controller/GroupController.php b/src/Controller/GroupController.php index 718f0eba..cf7f0ab8 100644 --- a/src/Controller/GroupController.php +++ b/src/Controller/GroupController.php @@ -37,7 +37,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; #[Route(path: '/group')] class GroupController extends BaseAdminController @@ -49,7 +49,7 @@ class GroupController extends BaseAdminController protected string $attachment_class = GroupAttachment::class; protected ?string $parameter_class = GroupParameter::class; - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'group_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'group_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}/', requirements: ['id' => '\d+'])] public function edit(Group $entity, Request $request, EntityManagerInterface $em, PermissionPresetsHelper $permissionPresetsHelper, PermissionSchemaUpdater $permissionSchemaUpdater, ?string $timestamp = null): Response { diff --git a/src/Controller/HomepageController.php b/src/Controller/HomepageController.php index 212363ff..076e790b 100644 --- a/src/Controller/HomepageController.php +++ b/src/Controller/HomepageController.php @@ -25,45 +25,29 @@ namespace App\Controller; use App\DataTables\LogDataTable; use App\Entity\Parts\Part; use App\Services\Misc\GitVersionInfo; +use App\Services\System\BannerHelper; +use App\Services\System\UpdateAvailableManager; use Doctrine\ORM\EntityManagerInterface; -use const DIRECTORY_SEPARATOR; use Omines\DataTablesBundle\DataTableFactory; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\KernelInterface; -use Symfony\Component\Routing\Annotation\Route; -use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Component\Routing\Attribute\Route; class HomepageController extends AbstractController { - public function __construct(protected CacheInterface $cache, protected KernelInterface $kernel, protected DataTableFactory $dataTable) + public function __construct(private readonly DataTableFactory $dataTable, private readonly BannerHelper $bannerHelper) { } - public function getBanner(): string - { - $banner = $this->getParameter('partdb.banner'); - if (!is_string($banner)) { - throw new \RuntimeException('The parameter "partdb.banner" must be a string.'); - } - if (empty($banner)) { - $banner_path = $this->kernel->getProjectDir() - .DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'banner.md'; - $tmp = file_get_contents($banner_path); - if (false === $tmp) { - throw new \RuntimeException('The banner file could not be read.'); - } - $banner = $tmp; - } - - return $banner; - } #[Route(path: '/', name: 'homepage')] - public function homepage(Request $request, GitVersionInfo $versionInfo, EntityManagerInterface $entityManager): Response + public function homepage(Request $request, GitVersionInfo $versionInfo, EntityManagerInterface $entityManager, + UpdateAvailableManager $updateAvailableManager): Response { + $this->denyAccessUnlessGranted('HAS_ACCESS_PERMISSIONS'); + if ($this->isGranted('@tools.lastActivity')) { $table = $this->dataTable->createFromType( LogDataTable::class, @@ -92,11 +76,14 @@ class HomepageController extends AbstractController } return $this->render('homepage.html.twig', [ - 'banner' => $this->getBanner(), + 'banner' => $this->bannerHelper->getBanner(), 'git_branch' => $versionInfo->getGitBranchName(), 'git_commit' => $versionInfo->getGitCommitHash(), 'show_first_steps' => $show_first_steps, 'datatable' => $table, + 'new_version_available' => $updateAvailableManager->isUpdateAvailable(), + 'new_version' => $updateAvailableManager->getLatestVersionString(), + 'new_version_url' => $updateAvailableManager->getLatestVersionUrl(), ]); } } diff --git a/src/Controller/InfoProviderController.php b/src/Controller/InfoProviderController.php index cb95377b..a6ce3f1b 100644 --- a/src/Controller/InfoProviderController.php +++ b/src/Controller/InfoProviderController.php @@ -23,28 +23,31 @@ declare(strict_types=1); namespace App\Controller; -use App\Exceptions\AttachmentDownloadException; +use App\Entity\Parts\Manufacturer; +use App\Entity\Parts\Part; use App\Form\InfoProviderSystem\PartSearchType; -use App\Form\Part\PartBaseType; -use App\Services\Attachments\AttachmentSubmitHandler; +use App\Services\InfoProviderSystem\ExistingPartFinder; use App\Services\InfoProviderSystem\PartInfoRetriever; use App\Services\InfoProviderSystem\ProviderRegistry; -use App\Services\LogSystem\EventCommentHelper; -use App\Services\Parts\PartFormHelper; use Doctrine\ORM\EntityManagerInterface; +use Psr\Log\LoggerInterface; +use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpClient\Exception\ClientException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; -use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Component\Routing\Attribute\Route; + +use function Symfony\Component\Translation\t; #[Route('/tools/info_providers')] class InfoProviderController extends AbstractController { public function __construct(private readonly ProviderRegistry $providerRegistry, - private readonly PartInfoRetriever $infoRetriever) + private readonly PartInfoRetriever $infoRetriever, + private readonly ExistingPartFinder $existingPartFinder + ) { } @@ -61,7 +64,8 @@ class InfoProviderController extends AbstractController } #[Route('/search', name: 'info_providers_search')] - public function search(Request $request): Response + #[Route('/update/{target}', name: 'info_providers_update_part_search')] + public function search(Request $request, #[MapEntity(id: 'target')] ?Part $update_target, LoggerInterface $exceptionLogger): Response { $this->denyAccessUnlessGranted('@info_providers.create_parts'); @@ -70,16 +74,58 @@ class InfoProviderController extends AbstractController $results = null; + //When we are updating a part, use its name as keyword, to make searching easier + //However we can only do this, if the form was not submitted yet + if ($update_target !== null && !$form->isSubmitted()) { + //Use the provider reference if available, otherwise use the manufacturer product number + $keyword = $update_target->getProviderReference()->getProviderId() ?? $update_target->getManufacturerProductNumber(); + //Or the name if both are not available + if ($keyword === "") { + $keyword = $update_target->getName(); + } + + $form->get('keyword')->setData($keyword); + + //If we are updating a part, which already has a provider, preselect that provider in the form + if ($update_target->getProviderReference()->getProviderKey() !== null) { + try { + $form->get('providers')->setData([$this->providerRegistry->getProviderByKey($update_target->getProviderReference()->getProviderKey())]); + } catch (\InvalidArgumentException $e) { + //If the provider is not found, just ignore it + } + } + } + if ($form->isSubmitted() && $form->isValid()) { $keyword = $form->get('keyword')->getData(); $providers = $form->get('providers')->getData(); - $results = $this->infoRetriever->searchByKeyword(keyword: $keyword, providers: $providers); + $dtos = []; + + try { + $dtos = $this->infoRetriever->searchByKeyword(keyword: $keyword, providers: $providers); + } catch (ClientException $e) { + $this->addFlash('error', t('info_providers.search.error.client_exception')); + $this->addFlash('error',$e->getMessage()); + //Log the exception + $exceptionLogger->error('Error during info provider search: ' . $e->getMessage(), ['exception' => $e]); + } + + // modify the array to an array of arrays that has a field for a matching local Part + // the advantage to use that format even when we don't look for local parts is that we + // always work with the same interface + $results = array_map(function ($result) {return ['dto' => $result, 'localPart' => null];}, $dtos); + if(!$update_target) { + foreach ($results as $index => $result) { + $results[$index]['localPart'] = $this->existingPartFinder->findFirstExisting($result['dto']); + } + } } return $this->render('info_providers/search/part_search.html.twig', [ 'form' => $form, 'results' => $results, + 'update_target' => $update_target ]); } } \ No newline at end of file diff --git a/src/Controller/KiCadApiController.php b/src/Controller/KiCadApiController.php new file mode 100644 index 00000000..c28e87a6 --- /dev/null +++ b/src/Controller/KiCadApiController.php @@ -0,0 +1,85 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Controller; + +use App\Entity\Parts\Category; +use App\Entity\Parts\Part; +use App\Services\EDA\KiCadHelper; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Attribute\Route; + +/** + * @see \App\Tests\Controller\KiCadApiControllerTest + */ +#[Route('/kicad-api/v1')] +class KiCadApiController extends AbstractController +{ + public function __construct( + private readonly KiCadHelper $kiCADHelper, + ) + { + } + + #[Route('/', name: 'kicad_api_root')] + public function root(): Response + { + $this->denyAccessUnlessGranted('HAS_ACCESS_PERMISSIONS'); + + //The API documentation says this can be either blank or the URL to the endpoints + return $this->json([ + 'categories' => '', + 'parts' => '', + ]); + } + + #[Route('/categories.json', name: 'kicad_api_categories')] + public function categories(): Response + { + $this->denyAccessUnlessGranted('@categories.read'); + + return $this->json($this->kiCADHelper->getCategories()); + } + + #[Route('/parts/category/{category}.json', name: 'kicad_api_category')] + public function categoryParts(?Category $category): Response + { + if ($category !== null) { + $this->denyAccessUnlessGranted('read', $category); + } else { + $this->denyAccessUnlessGranted('@categories.read'); + } + $this->denyAccessUnlessGranted('@parts.read'); + + return $this->json($this->kiCADHelper->getCategoryParts($category)); + } + + #[Route('/parts/{part}.json', name: 'kicad_api_part')] + public function partDetails(Part $part): Response + { + $this->denyAccessUnlessGranted('read', $part); + + return $this->json($this->kiCADHelper->getKiCADPart($part)); + } +} \ No newline at end of file diff --git a/src/Controller/LabelController.php b/src/Controller/LabelController.php index f5da187e..4950628b 100644 --- a/src/Controller/LabelController.php +++ b/src/Controller/LabelController.php @@ -53,12 +53,11 @@ use App\Services\ElementTypeNameGenerator; use App\Services\LabelSystem\LabelGenerator; use App\Services\Misc\RangeParser; use Doctrine\ORM\EntityManagerInterface; -use InvalidArgumentException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\FormError; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Contracts\Translation\TranslatorInterface; #[Route(path: '/label')] @@ -109,8 +108,31 @@ class LabelController extends AbstractController $pdf_data = null; $filename = 'invalid.pdf'; - //Generate PDF either when the form is submitted and valid, or the form was not submit yet, and generate is set if (($form->isSubmitted() && $form->isValid()) || ($generate && !$form->isSubmitted() && $profile instanceof LabelProfile)) { + + //Check if the label should be saved as profile + if ($form->get('save_profile')->isClicked() && $this->isGranted('@labels.create_profiles')) { //@phpstan-ignore-line Phpstan does not recognize the isClicked method + //Retrieve the profile name from the form + $new_name = $form->get('save_profile_name')->getData(); + //ensure that the name is not empty + if ($new_name === '' || $new_name === null) { + $form->get('save_profile_name')->addError(new FormError($this->translator->trans('label_generator.profile_name_empty'))); + goto render; + } + + $profile = new LabelProfile(); + $profile->setName($form->get('save_profile_name')->getData()); + $profile->setOptions($form_options); + $this->em->persist($profile); + $this->em->flush(); + $this->addFlash('success', 'label_generator.profile_saved'); + + return $this->redirectToRoute('label_dialog_profile', [ + 'profile' => $profile->getID(), + 'target_id' => (string) $form->get('target_id')->getData() + ]); + } + $target_id = (string) $form->get('target_id')->getData(); $targets = $this->findObjects($form_options->getSupportedElement(), $target_id); if ($targets !== []) { @@ -118,7 +140,7 @@ class LabelController extends AbstractController $pdf_data = $this->labelGenerator->generateLabel($form_options, $targets); $filename = $this->getLabelName($targets[0], $profile); } catch (TwigModeException $exception) { - $form->get('options')->get('lines')->addError(new FormError($exception->getMessage())); + $form->get('options')->get('lines')->addError(new FormError($exception->getSafeMessage())); } } else { //$this->addFlash('warning', 'label_generator.no_entities_found'); @@ -133,6 +155,7 @@ class LabelController extends AbstractController } } + render: return $this->render('label_system/dialog.html.twig', [ 'form' => $form, 'pdf_data' => $pdf_data, @@ -153,7 +176,7 @@ class LabelController extends AbstractController { $id_array = $this->rangeParser->parse($ids); - /** @var DBElementRepository $repo */ + /** @var DBElementRepository $repo */ $repo = $this->em->getRepository($type->getEntityClass()); return $repo->getElementsFromIDArray($id_array); diff --git a/src/Controller/LogController.php b/src/Controller/LogController.php index afa32f7a..a849539d 100644 --- a/src/Controller/LogController.php +++ b/src/Controller/LogController.php @@ -22,7 +22,6 @@ declare(strict_types=1); namespace App\Controller; -use App\DataTables\Column\LogEntryTargetColumn; use App\DataTables\Filters\LogFilter; use App\DataTables\LogDataTable; use App\Entity\Base\AbstractDBElement; @@ -40,15 +39,13 @@ use App\Services\LogSystem\LogLevelHelper; use App\Services\LogSystem\LogTargetHelper; use App\Services\LogSystem\TimeTravel; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityRepository; use InvalidArgumentException; use Omines\DataTablesBundle\DataTableFactory; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; #[Route(path: '/log')] class LogController extends AbstractController @@ -154,7 +151,7 @@ class LogController extends AbstractController if (EventUndoMode::UNDO === $mode) { $this->undoLog($log_element); - } elseif (EventUndoMode::REVERT === $mode) { + } else { $this->revertLog($log_element); } diff --git a/src/Controller/OAuthClientController.php b/src/Controller/OAuthClientController.php index ff2aab0e..9606a4e4 100644 --- a/src/Controller/OAuthClientController.php +++ b/src/Controller/OAuthClientController.php @@ -28,7 +28,7 @@ use KnpU\OAuth2ClientBundle\Client\ClientRegistry; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use function Symfony\Component\Translation\t; @@ -51,7 +51,7 @@ class OAuthClientController extends AbstractController } #[Route('/{name}/check', name: 'oauth_client_check')] - public function check(string $name, Request $request): Response + public function check(string $name): Response { $this->denyAccessUnlessGranted('@system.manage_oauth_tokens'); diff --git a/src/Controller/PartController.php b/src/Controller/PartController.php index 3adfda5c..b11a5c90 100644 --- a/src/Controller/PartController.php +++ b/src/Controller/PartController.php @@ -23,12 +23,13 @@ declare(strict_types=1); namespace App\Controller; use App\DataTables\LogDataTable; +use App\Entity\Attachments\AttachmentUpload; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Orderdetail; use App\Entity\ProjectSystem\Project; @@ -36,6 +37,7 @@ use App\Exceptions\AttachmentDownloadException; use App\Form\Part\PartBaseType; use App\Services\Attachments\AttachmentSubmitHandler; use App\Services\Attachments\PartPreviewGenerator; +use App\Services\EntityMergers\Mergers\PartMerger; use App\Services\InfoProviderSystem\PartInfoRetriever; use App\Services\LogSystem\EventCommentHelper; use App\Services\LogSystem\HistoryHelper; @@ -48,14 +50,13 @@ use DateTime; use Doctrine\ORM\EntityManagerInterface; use Exception; use Omines\DataTablesBundle\DataTableFactory; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Bridge\Doctrine\Attribute\MapEntity; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Contracts\Translation\TranslatorInterface; @@ -160,7 +161,7 @@ class PartController extends AbstractController public function new(Request $request, EntityManagerInterface $em, TranslatorInterface $translator, AttachmentSubmitHandler $attachmentSubmitHandler, ProjectBuildPartHelper $projectBuildPartHelper, #[MapEntity(mapping: ['id' => 'id'])] ?Part $part = null, - #[MapEntity(mapping: ['id' => 'project_id'])] ?Project $project = null): Response + #[MapEntity(mapping: ['project_id' => 'id'])] ?Project $project = null): Response { if ($part instanceof Part) { @@ -201,8 +202,8 @@ class PartController extends AbstractController } $store_id = $request->get('storelocation', null); - $storelocation = $store_id ? $em->find(Storelocation::class, $store_id) : null; - if ($storelocation instanceof Storelocation && $new_part->getPartLots()->isEmpty()) { + $storelocation = $store_id ? $em->find(StorageLocation::class, $store_id) : null; + if ($storelocation instanceof StorageLocation && $new_part->getPartLots()->isEmpty()) { $partLot = new PartLot(); $partLot->setStorageLocation($storelocation); $partLot->setInstockUnknown(true); @@ -228,11 +229,57 @@ class PartController extends AbstractController $dto = $infoRetriever->getDetails($providerKey, $providerId); $new_part = $infoRetriever->dtoToPart($dto); + if ($new_part->getCategory() === null || $new_part->getCategory()->getID() === null) { + $this->addFlash('warning', t("part.create_from_info_provider.no_category_yet")); + } + return $this->renderPartForm('new', $request, $new_part, [ 'info_provider_dto' => $dto, ]); } + #[Route('/{target}/merge/{other}', name: 'part_merge')] + public function merge(Request $request, Part $target, Part $other, PartMerger $partMerger): Response + { + $this->denyAccessUnlessGranted('edit', $target); + $this->denyAccessUnlessGranted('delete', $other); + + //Save the old name of the target part for the template + $target_name = $target->getName(); + + $this->addFlash('notice', t('part.merge.flash.please_review')); + + $merged = $partMerger->merge($target, $other); + return $this->renderPartForm('merge', $request, $merged, [], [ + 'tname_before' => $target_name, + 'other_part' => $other, + ]); + } + + #[Route(path: '/{id}/from_info_provider/{providerKey}/{providerId}/update', name: 'info_providers_update_part', requirements: ['providerId' => '.+'])] + public function updateFromInfoProvider(Part $part, Request $request, string $providerKey, string $providerId, + PartInfoRetriever $infoRetriever, PartMerger $partMerger): Response + { + $this->denyAccessUnlessGranted('edit', $part); + $this->denyAccessUnlessGranted('@info_providers.create_parts'); + + //Save the old name of the target part for the template + $old_name = $part->getName(); + + $dto = $infoRetriever->getDetails($providerKey, $providerId); + $provider_part = $infoRetriever->dtoToPart($dto); + + $part = $partMerger->merge($part, $provider_part); + + $this->addFlash('notice', t('part.merge.flash.please_review')); + + return $this->renderPartForm('update_from_ip', $request, $part, [ + 'info_provider_dto' => $dto, + ], [ + 'tname_before' => $old_name + ]); + } + /** * This function provides a common implementation for methods, which use the part form. * @param Request $request @@ -240,10 +287,10 @@ class PartController extends AbstractController * @param array $form_options * @return Response */ - private function renderPartForm(string $mode, Request $request, Part $data, array $form_options = []): Response + private function renderPartForm(string $mode, Request $request, Part $data, array $form_options = [], array $merge_infos = []): Response { //Ensure that mode is either 'new' or 'edit - if (!in_array($mode, ['new', 'edit'], true)) { + if (!in_array($mode, ['new', 'edit', 'merge', 'update_from_ip'], true)) { throw new \InvalidArgumentException('Invalid mode given'); } @@ -258,13 +305,9 @@ class PartController extends AbstractController $attachments = $form['attachments']; foreach ($attachments as $attachment) { /** @var FormInterface $attachment */ - $options = [ - 'secure_attachment' => $attachment['secureFile']->getData(), - 'download_url' => $attachment['downloadURL']->getData(), - ]; try { - $this->attachmentSubmitHandler->handleFormSubmit($attachment->getData(), $attachment['file']->getData(), $options); + $this->attachmentSubmitHandler->handleUpload($attachment->getData(), AttachmentUpload::fromAttachmentForm($attachment)); } catch (AttachmentDownloadException $attachmentDownloadException) { $this->addFlash( 'error', @@ -273,13 +316,24 @@ class PartController extends AbstractController } } + //Ensure that the master picture is still part of the attachments + if ($new_part->getMasterPictureAttachment() !== null && !$new_part->getAttachments()->contains($new_part->getMasterPictureAttachment())) { + $new_part->setMasterPictureAttachment(null); + } + $this->commentHelper->setMessage($form['log_comment']->getData()); $this->em->persist($new_part); + + //When we are in merge mode, we have to remove the other part + if ($mode === 'merge') { + $this->em->remove($merge_infos['other_part']); + } + $this->em->flush(); if ($mode === 'new') { $this->addFlash('success', 'part.created_flash'); - } else if ($mode === 'edit') { + } elseif ($mode === 'edit') { $this->addFlash('success', 'part.edited_flash'); } @@ -308,14 +362,20 @@ class PartController extends AbstractController $template = ''; if ($mode === 'new') { $template = 'parts/edit/new_part.html.twig'; - } else if ($mode === 'edit') { + } elseif ($mode === 'edit') { $template = 'parts/edit/edit_part_info.html.twig'; + } elseif ($mode === 'merge') { + $template = 'parts/edit/merge_parts.html.twig'; + } elseif ($mode === 'update_from_ip') { + $template = 'parts/edit/update_from_ip.html.twig'; } return $this->render($template, [ 'part' => $new_part, 'form' => $form, + 'merge_old_name' => $merge_infos['tname_before'] ?? null, + 'merge_other' => $merge_infos['other_part'] ?? null ]); } @@ -345,23 +405,41 @@ class PartController extends AbstractController $amount = (float) $request->request->get('amount'); $comment = $request->request->get('comment'); $action = $request->request->get('action'); + $delete_lot_if_empty = $request->request->getBoolean('delete_lot_if_empty', false); + $timestamp = null; + $timestamp_str = $request->request->getString('timestamp', ''); + //Try to parse the timestamp + if($timestamp_str !== '') { + $timestamp = new DateTime($timestamp_str); + } + + //Ensure that the timestamp is not in the future + if($timestamp !== null && $timestamp > new DateTime("+20min")) { + throw new \LogicException("The timestamp must not be in the future!"); + } + + //Ensure that the amount is not null or negative + if ($amount <= 0) { + $this->addFlash('warning', 'part.withdraw.zero_amount'); + goto err; + } try { switch ($action) { case "withdraw": case "remove": $this->denyAccessUnlessGranted('withdraw', $partLot); - $withdrawAddHelper->withdraw($partLot, $amount, $comment); + $withdrawAddHelper->withdraw($partLot, $amount, $comment, $timestamp, $delete_lot_if_empty); break; case "add": $this->denyAccessUnlessGranted('add', $partLot); - $withdrawAddHelper->add($partLot, $amount, $comment); + $withdrawAddHelper->add($partLot, $amount, $comment, $timestamp); break; case "move": $this->denyAccessUnlessGranted('move', $partLot); $this->denyAccessUnlessGranted('move', $targetLot); - $withdrawAddHelper->move($partLot, $targetLot, $amount, $comment); + $withdrawAddHelper->move($partLot, $targetLot, $amount, $comment, $timestamp, $delete_lot_if_empty); break; default: throw new \RuntimeException("Unknown action!"); diff --git a/src/Controller/PartImportExportController.php b/src/Controller/PartImportExportController.php index 326ea923..45f90d75 100644 --- a/src/Controller/PartImportExportController.php +++ b/src/Controller/PartImportExportController.php @@ -32,7 +32,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; use UnexpectedValueException; @@ -112,8 +112,9 @@ class PartImportExportController extends AbstractController $ids = $request->query->get('ids', ''); $parts = $this->partsTableActionHandler->idStringToArray($ids); - if ($parts === []) { - throw new \RuntimeException('No parts found!'); + if (count($parts) === 0) { + $this->addFlash('error', 'entity.export.flash.error.no_entities'); + return $this->redirectToRoute('homepage'); } //Ensure that we have access to the parts diff --git a/src/Controller/PartListsController.php b/src/Controller/PartListsController.php index 90005447..48995228 100644 --- a/src/Controller/PartListsController.php +++ b/src/Controller/PartListsController.php @@ -29,7 +29,8 @@ use App\DataTables\PartsDataTable; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\Part; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Exceptions\InvalidRegexException; use App\Form\Filters\PartFilterType; @@ -40,12 +41,14 @@ use Doctrine\ORM\EntityManagerInterface; use Omines\DataTablesBundle\DataTableFactory; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\FormInterface; -use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Translation\TranslatableMessage; use Symfony\Contracts\Translation\TranslatorInterface; +use function Symfony\Component\Translation\t; + class PartListsController extends AbstractController { public function __construct(private readonly EntityManagerInterface $entityManager, private readonly NodesListBuilder $nodesListBuilder, private readonly DataTableFactory $dataTableFactory, private readonly TranslatorInterface $translator) @@ -61,6 +64,7 @@ class PartListsController extends AbstractController $ids = $request->request->get('ids'); $action = $request->request->get('action'); $target = $request->request->get('target'); + $redirectResponse = null; if (!$this->isCsrfTokenValid('table_action', $request->request->get('_token'))) { $this->addFlash('error', 'csfr_invalid'); @@ -71,17 +75,36 @@ class PartListsController extends AbstractController if (null === $action || null === $ids) { $this->addFlash('error', 'part.table.actions.no_params_given'); } else { + $errors = []; + $parts = $actionHandler->idStringToArray($ids); - $redirectResponse = $actionHandler->handleAction($action, $parts, $target ? (int) $target : null, $redirect); + $redirectResponse = $actionHandler->handleAction($action, $parts, $target ? (int) $target : null, $redirect, $errors); //Save changes $this->entityManager->flush(); - $this->addFlash('success', 'part.table.actions.success'); + if (count($errors) === 0) { + $this->addFlash('success', 'part.table.actions.success'); + } else { + $this->addFlash('error', t('part.table.actions.error', ['%count%' => count($errors)])); + //Create a flash message for each error + foreach ($errors as $error) { + /** @var Part $part */ + $part = $error['part']; + + $this->addFlash('error', + t('part.table.actions.error_detail', [ + '%part_name%' => $part->getName(), + '%part_id%' => $part->getID(), + '%message%' => $error['message'] + ]) + ); + } + } } //If the action handler returned a response, we use it, otherwise we redirect back to the previous page. - if (isset($redirectResponse) && $redirectResponse instanceof Response) { + if ($redirectResponse !== null) { return $redirectResponse; } @@ -132,7 +155,11 @@ class PartListsController extends AbstractController $filterForm->handleRequest($formRequest); - $table = $this->dataTableFactory->createFromType(PartsDataTable::class, array_merge(['filter' => $filter], $additional_table_vars)) + $table = $this->dataTableFactory->createFromType( + PartsDataTable::class, + array_merge(['filter' => $filter], $additional_table_vars), + ['lengthMenu' => PartsDataTable::LENGTH_MENU] + ) ->handleRequest($request); if ($table->isCallback()) { @@ -214,7 +241,7 @@ class PartListsController extends AbstractController } #[Route(path: '/store_location/{id}/parts', name: 'part_list_store_location')] - public function showStorelocation(Storelocation $storelocation, Request $request): Response + public function showStorelocation(StorageLocation $storelocation, Request $request): Response { $this->denyAccessUnlessGranted('@storelocations.read'); @@ -226,7 +253,7 @@ class PartListsController extends AbstractController $this->disableFormFieldAfterCreation($filterForm->get('storelocation')->get('value')); }, [ 'entity' => $storelocation, - 'repo' => $this->entityManager->getRepository(Storelocation::class), + 'repo' => $this->entityManager->getRepository(StorageLocation::class), ] ); } diff --git a/src/Controller/ProjectController.php b/src/Controller/ProjectController.php index 8c192319..761e498c 100644 --- a/src/Controller/ProjectController.php +++ b/src/Controller/ProjectController.php @@ -27,29 +27,22 @@ use App\Entity\Parts\Part; use App\Entity\ProjectSystem\Project; use App\Entity\ProjectSystem\ProjectBOMEntry; use App\Form\ProjectSystem\ProjectAddPartsType; -use App\Form\ProjectSystem\ProjectBOMEntryCollectionType; use App\Form\ProjectSystem\ProjectBuildType; -use App\Form\Type\StructuralEntityType; use App\Helpers\Projects\ProjectBuildRequest; use App\Services\ImportExportSystem\BOMImporter; use App\Services\ProjectSystem\ProjectBuildHelper; -use App\Validator\Constraints\UniqueObjectCollection; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\EntityManagerInterface; use League\Csv\SyntaxError; use Omines\DataTablesBundle\DataTableFactory; -use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; -use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Symfony\Component\Form\FormEvents; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Validator\Constraints\NotNull; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Validator\Validator\ValidatorInterface; use function Symfony\Component\Translation\t; @@ -214,6 +207,11 @@ class ProjectController extends AbstractController //Preset the BOM entries with the selected parts, when the form was not submitted yet $preset_data = new ArrayCollection(); foreach (explode(',', (string) $request->get('parts', '')) as $part_id) { + //Skip empty part IDs. Postgres seems to be especially sensitive to empty strings, as it does not allow them in integer columns + if ($part_id === '') { + continue; + } + $part = $entityManager->getRepository(Part::class)->find($part_id); if (null !== $part) { //If there is already a BOM entry for this part, we use this one (we edit it then) @@ -221,7 +219,7 @@ class ProjectController extends AbstractController 'project' => $project, 'part' => $part ]); - if ($bom_entry) { + if ($bom_entry !== null) { $preset_data->add($bom_entry); } else { //Otherwise create an empty one $entry = new ProjectBOMEntry(); diff --git a/src/Controller/RedirectController.php b/src/Controller/RedirectController.php index b0af0119..65bd78f5 100644 --- a/src/Controller/RedirectController.php +++ b/src/Controller/RedirectController.php @@ -58,7 +58,7 @@ class RedirectController extends AbstractController //If either mod_rewrite is not enabled or the index.php version is enforced, add index.php to the string if (($this->enforce_index_php || !$this->checkIfModRewriteAvailable()) - && !str_contains((string) $new_url, 'index.php')) { + && !str_contains($new_url, 'index.php')) { //Like Request::getUriForPath only with index.php $new_url = $request->getSchemeAndHttpHost().$request->getBaseUrl().'/index.php/'.$locale.$request->getPathInfo(); } @@ -73,6 +73,7 @@ class RedirectController extends AbstractController * Check if mod_rewrite is available (URL rewriting is possible). * If this is true, we can redirect to /en, otherwise we have to redirect to index.php/en. * When the PHP is not used via Apache SAPI, we just assume that URL rewriting is available. + * @noinspection PhpUndefinedFunctionInspection */ public function checkIfModRewriteAvailable(): bool { diff --git a/src/Controller/ScanController.php b/src/Controller/ScanController.php index b261f3fd..aebadd89 100644 --- a/src/Controller/ScanController.php +++ b/src/Controller/ScanController.php @@ -42,20 +42,25 @@ declare(strict_types=1); namespace App\Controller; use App\Form\LabelSystem\ScanDialogType; -use App\Services\LabelSystem\Barcodes\BarcodeNormalizer; -use App\Services\LabelSystem\Barcodes\BarcodeRedirector; +use App\Services\LabelSystem\BarcodeScanner\BarcodeRedirector; +use App\Services\LabelSystem\BarcodeScanner\BarcodeScanHelper; +use App\Services\LabelSystem\BarcodeScanner\BarcodeSourceType; +use App\Services\LabelSystem\BarcodeScanner\LocalBarcodeScanResult; use Doctrine\ORM\EntityNotFoundException; use InvalidArgumentException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\MapQueryParameter; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; +/** + * @see \App\Tests\Controller\ScanControllerTest + */ #[Route(path: '/scan')] class ScanController extends AbstractController { - public function __construct(protected BarcodeRedirector $barcodeParser, protected BarcodeNormalizer $barcodeNormalizer) + public function __construct(protected BarcodeRedirector $barcodeParser, protected BarcodeScanHelper $barcodeNormalizer) { } @@ -69,16 +74,24 @@ class ScanController extends AbstractController if ($input === null && $form->isSubmitted() && $form->isValid()) { $input = $form['input']->getData(); + $mode = $form['mode']->getData(); } + $infoModeData = null; + if ($input !== null) { try { - [$type, $id] = $this->barcodeNormalizer->normalizeBarcodeContent($input); + $scan_result = $this->barcodeNormalizer->scanBarcodeContent($input, $mode ?? null); + //Perform a redirect if the info mode is not enabled + if (!$form['info_mode']->getData()) { + try { + return $this->redirect($this->barcodeParser->getRedirectURL($scan_result)); + } catch (EntityNotFoundException) { + $this->addFlash('success', 'scan.qr_not_found'); + } + } else { //Otherwise retrieve infoModeData + $infoModeData = $scan_result->getDecodedForInfoMode(); - try { - return $this->redirect($this->barcodeParser->getRedirectURL($type, $id)); - } catch (EntityNotFoundException) { - $this->addFlash('success', 'scan.qr_not_found'); } } catch (InvalidArgumentException) { $this->addFlash('error', 'scan.format_unknown'); @@ -87,6 +100,7 @@ class ScanController extends AbstractController return $this->render('label_system/scanner/scanner.html.twig', [ 'form' => $form, + 'infoModeData' => $infoModeData, ]); } @@ -95,10 +109,23 @@ class ScanController extends AbstractController */ public function scanQRCode(string $type, int $id): Response { + $type = strtolower($type); + try { $this->addFlash('success', 'scan.qr_success'); - return $this->redirect($this->barcodeParser->getRedirectURL($type, $id)); + if (!isset(BarcodeScanHelper::QR_TYPE_MAP[$type])) { + throw new InvalidArgumentException('Unknown type: '.$type); + } + //Construct the scan result manually, as we don't have a barcode here + $scan_result = new LocalBarcodeScanResult( + target_type: BarcodeScanHelper::QR_TYPE_MAP[$type], + target_id: $id, + //The routes are only used on the internal generated QR codes + source_type: BarcodeSourceType::INTERNAL + ); + + return $this->redirect($this->barcodeParser->getRedirectURL($scan_result)); } catch (EntityNotFoundException) { $this->addFlash('success', 'scan.qr_not_found'); diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index 095dfd54..4e2077c4 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -39,7 +39,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; @@ -170,7 +170,7 @@ class SecurityController extends AbstractController $this->addFlash('success', 'pw_reset.new_pw.success'); $repo = $em->getRepository(User::class); - $u = $repo->findOneBy(['name' => $data['username']]); + $u = $repo->findByUsername($data['username']); $event = new SecurityEvent($u); /** @var EventDispatcher $eventDispatcher */ $eventDispatcher->dispatch($event, SecurityEvents::PASSWORD_RESET); diff --git a/src/Controller/SelectAPIController.php b/src/Controller/SelectAPIController.php index c403ab82..c1e682c8 100644 --- a/src/Controller/SelectAPIController.php +++ b/src/Controller/SelectAPIController.php @@ -29,13 +29,14 @@ use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; +use App\Entity\Parts\StorageLocation; use App\Entity\ProjectSystem\Project; use App\Form\Type\Helper\StructuralEntityChoiceHelper; use App\Services\Trees\NodesListBuilder; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Contracts\Translation\TranslatorInterface; /** @@ -78,6 +79,12 @@ class SelectAPIController extends AbstractController return $this->getResponseForClass(Project::class, false); } + #[Route(path: '/storage_location', name: 'select_storage_location')] + public function locations(): Response + { + return $this->getResponseForClass(StorageLocation::class, true); + } + #[Route(path: '/export_level', name: 'select_export_level')] public function exportLevel(): Response { diff --git a/src/Controller/StatisticsController.php b/src/Controller/StatisticsController.php index 6ff09e83..67c29781 100644 --- a/src/Controller/StatisticsController.php +++ b/src/Controller/StatisticsController.php @@ -44,7 +44,7 @@ namespace App\Controller; use App\Services\Tools\StatisticsHelper; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; class StatisticsController extends AbstractController { diff --git a/src/Controller/ToolsController.php b/src/Controller/ToolsController.php index c14e1a13..dbcb91a1 100644 --- a/src/Controller/ToolsController.php +++ b/src/Controller/ToolsController.php @@ -22,17 +22,17 @@ declare(strict_types=1); */ namespace App\Controller; -use App\Services\Attachments\AttachmentPathResolver; use App\Services\Attachments\AttachmentSubmitHandler; use App\Services\Attachments\AttachmentURLGenerator; use App\Services\Attachments\BuiltinAttachmentsFinder; +use App\Services\Doctrine\DBInfoHelper; +use App\Services\Doctrine\NatsortDebugHelper; use App\Services\Misc\GitVersionInfo; -use App\Services\Misc\DBInfoHelper; -use Doctrine\ORM\EntityManagerInterface; +use App\Services\System\UpdateAvailableManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Routing\Generator\UrlGenerator; +use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Runtime\SymfonyRuntime; #[Route(path: '/tools')] class ToolsController extends AbstractController @@ -46,8 +46,8 @@ class ToolsController extends AbstractController } #[Route(path: '/server_infos', name: 'tools_server_infos')] - public function systemInfos(GitVersionInfo $versionInfo, DBInfoHelper $DBInfoHelper, - AttachmentSubmitHandler $attachmentSubmitHandler): Response + public function systemInfos(GitVersionInfo $versionInfo, DBInfoHelper $DBInfoHelper, NatsortDebugHelper $natsortDebugHelper, + AttachmentSubmitHandler $attachmentSubmitHandler, UpdateAvailableManager $updateAvailableManager): Response { $this->denyAccessUnlessGranted('@system.server_infos'); @@ -61,10 +61,10 @@ class ToolsController extends AbstractController 'default_theme' => $this->getParameter('partdb.global_theme'), 'enabled_locales' => $this->getParameter('partdb.locale_menu'), 'demo_mode' => $this->getParameter('partdb.demo_mode'), - 'gpdr_compliance' => $this->getParameter('partdb.gdpr_compliance'), + 'gdpr_compliance' => $this->getParameter('partdb.gdpr_compliance'), 'use_gravatar' => $this->getParameter('partdb.users.use_gravatar'), 'email_password_reset' => $this->getParameter('partdb.users.email_pw_reset'), - 'enviroment' => $this->getParameter('kernel.environment'), + 'environment' => $this->getParameter('kernel.environment'), 'is_debug' => $this->getParameter('kernel.debug'), 'email_sender' => $this->getParameter('partdb.mail.sender_email'), 'email_sender_name' => $this->getParameter('partdb.mail.sender_name'), @@ -79,10 +79,14 @@ class ToolsController extends AbstractController 'php_version' => PHP_VERSION, 'php_uname' => php_uname('a'), 'php_sapi' => PHP_SAPI, + 'php_bit_size' => PHP_INT_SIZE * 8, 'php_extensions' => [...get_loaded_extensions()], 'php_opcache_enabled' => ini_get('opcache.enable'), 'php_upload_max_filesize' => ini_get('upload_max_filesize'), 'php_post_max_size' => ini_get('post_max_size'), + 'kernel_runtime_environment' => $this->getParameter('kernel.runtime_environment'), + 'kernel_runtime_mode' => $this->getParameter('kernel.runtime_mode'), + 'kernel_runtime' => $_SERVER['APP_RUNTIME'] ?? $_ENV['APP_RUNTIME'] ?? SymfonyRuntime::class, //DB section 'db_type' => $DBInfoHelper->getDatabaseType() ?? 'Unknown', @@ -90,6 +94,13 @@ class ToolsController extends AbstractController 'db_size' => $DBInfoHelper->getDatabaseSize(), 'db_name' => $DBInfoHelper->getDatabaseName() ?? 'Unknown', 'db_user' => $DBInfoHelper->getDatabaseUsername() ?? 'Unknown', + 'db_natsort_method' => $natsortDebugHelper->getNaturalSortMethod(), + 'db_natsort_slow_allowed' => $natsortDebugHelper->isSlowNaturalSortAllowed(), + + //New version section + 'new_version_available' => $updateAvailableManager->isUpdateAvailable(), + 'new_version' => $updateAvailableManager->getLatestVersionString(), + 'new_version_url' => $updateAvailableManager->getLatestVersionUrl(), ]); } @@ -99,7 +110,7 @@ class ToolsController extends AbstractController $this->denyAccessUnlessGranted('@tools.builtin_footprints_viewer'); $grouped_footprints = $builtinAttachmentsFinder->getListOfFootprintsGroupedByFolder(); - $grouped_footprints = array_map(fn($group) => array_map(fn($placeholder_filepath) => [ + $grouped_footprints = array_map(static fn($group) => array_map(static fn($placeholder_filepath) => [ 'filename' => basename((string) $placeholder_filepath), 'assets_path' => $urlGenerator->placeholderPathToAssetPath($placeholder_filepath), ], $group), $grouped_footprints); diff --git a/src/Controller/TreeController.php b/src/Controller/TreeController.php index e7ce0b72..71f8ba5c 100644 --- a/src/Controller/TreeController.php +++ b/src/Controller/TreeController.php @@ -27,13 +27,13 @@ use App\Entity\ProjectSystem\Project; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Services\Trees\ToolsTreeBuilder; use App\Services\Trees\TreeViewGenerator; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; /** * This controller has the purpose to provide the data for all treeviews. @@ -80,10 +80,10 @@ class TreeController extends AbstractController #[Route(path: '/location/{id}', name: 'tree_location')] #[Route(path: '/locations', name: 'tree_location_root')] - public function locationTree(?Storelocation $location = null): JsonResponse + public function locationTree(?StorageLocation $location = null): JsonResponse { if ($this->isGranted('@parts.read') && $this->isGranted('@storelocations.read')) { - $tree = $this->treeGenerator->getTreeView(Storelocation::class, $location, 'list_parts_root'); + $tree = $this->treeGenerator->getTreeView(StorageLocation::class, $location, 'list_parts_root'); } else { return new JsonResponse("Access denied", Response::HTTP_FORBIDDEN); } diff --git a/src/Controller/TypeaheadController.php b/src/Controller/TypeaheadController.php index 3c0d76e9..89eac7ff 100644 --- a/src/Controller/TypeaheadController.php +++ b/src/Controller/TypeaheadController.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace App\Controller; +use App\Entity\Parameters\AbstractParameter; use Symfony\Component\HttpFoundation\Response; use App\Entity\Attachments\Attachment; use App\Entity\Parts\Category; @@ -34,7 +35,7 @@ use App\Entity\Parameters\GroupParameter; use App\Entity\Parameters\ManufacturerParameter; use App\Entity\Parameters\MeasurementUnitParameter; use App\Entity\Parameters\PartParameter; -use App\Entity\Parameters\StorelocationParameter; +use App\Entity\Parameters\StorageLocationParameter; use App\Entity\Parameters\SupplierParameter; use App\Entity\Parts\Part; use App\Entity\PriceInformations\Currency; @@ -48,7 +49,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Asset\Packages; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; @@ -92,7 +93,7 @@ class TypeaheadController extends AbstractController /** * This function map the parameter type to the class, so we can access its repository - * @return class-string + * @return class-string */ private function typeToParameterClass(string $type): string { @@ -102,7 +103,7 @@ class TypeaheadController extends AbstractController 'device' => ProjectParameter::class, 'footprint' => FootprintParameter::class, 'manufacturer' => ManufacturerParameter::class, - 'storelocation' => StorelocationParameter::class, + 'storelocation' => StorageLocationParameter::class, 'supplier' => SupplierParameter::class, 'attachment_type' => AttachmentTypeParameter::class, 'group' => GroupParameter::class, @@ -155,7 +156,7 @@ class TypeaheadController extends AbstractController //Ensure user has the correct permissions $this->denyAccessUnlessGranted('read', $test_obj); - /** @var ParameterRepository $repository */ + /** @var ParameterRepository $repository */ $repository = $entityManager->getRepository($class); $data = $repository->autocompleteParamName($query); diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 9332b6d3..968bd1e3 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -45,7 +45,8 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Validator\Validator\ValidatorInterface; #[Route(path: '/user')] class UserController extends BaseAdminController @@ -77,9 +78,10 @@ class UserController extends BaseAdminController * * @throws Exception */ - #[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'user_edit')] + #[Route(path: '/{id}/edit/{timestamp}', name: 'user_edit', requirements: ['id' => '\d+'])] #[Route(path: '/{id}/', requirements: ['id' => '\d+'])] - public function edit(User $entity, Request $request, EntityManagerInterface $em, PermissionPresetsHelper $permissionPresetsHelper, PermissionSchemaUpdater $permissionSchemaUpdater, ?string $timestamp = null): Response + public function edit(User $entity, Request $request, EntityManagerInterface $em, PermissionPresetsHelper $permissionPresetsHelper, + PermissionSchemaUpdater $permissionSchemaUpdater, ValidatorInterface $validator, ?string $timestamp = null): Response { //Do an upgrade of the permission schema if needed (so the user can see the permissions a user get on next request (even if it was not done yet) $permissionSchemaUpdater->userUpgradeSchemaRecursively($entity); @@ -108,7 +110,7 @@ class UserController extends BaseAdminController $this->addFlash('success', 'user.edit.reset_success'); } else { - $this->addFlash('danger', 'csfr_invalid'); + $this->addFlash('error', 'csfr_invalid'); } } @@ -120,15 +122,25 @@ class UserController extends BaseAdminController $permissionPresetsHelper->applyPreset($entity, $preset); - $em->flush(); + //Ensure that the user is valid after applying the preset + $errors = $validator->validate($entity); + if (count($errors) > 0) { + $this->addFlash('error', 'validator.noLockout'); + //Refresh the entity to remove the changes + $em->refresh($entity); + } else { + $em->flush(); - $this->addFlash('success', 'user.edit.permission_success'); + $this->addFlash('success', 'user.edit.permission_success'); - //We need to stop the execution here, or our permissions changes will be overwritten by the form values - return $this->redirectToRoute('user_edit', ['id' => $entity->getID()]); + //We need to stop the execution here, or our permissions changes will be overwritten by the form values + return $this->redirectToRoute('user_edit', ['id' => $entity->getID()]); + } + + + } else { + $this->addFlash('error', 'csfr_invalid'); } - - $this->addFlash('danger', 'csfr_invalid'); } return $this->_edit($entity, $request, $em, $timestamp); @@ -154,11 +166,17 @@ class UserController extends BaseAdminController return $this->_new($request, $em, $importer, $entity); } - #[Route(path: '/{id}', name: 'user_delete', methods: ['DELETE'], requirements: ['id' => '\d+'])] + #[Route(path: '/{id}', name: 'user_delete', requirements: ['id' => '\d+'], methods: ['DELETE'])] public function delete(Request $request, User $entity, StructuralElementRecursionHelper $recursionHelper): RedirectResponse { + //Disallow deleting the anonymous user if (User::ID_ANONYMOUS === $entity->getID()) { - throw new InvalidArgumentException('You can not delete the anonymous user! It is needed for permission checking without a logged in user'); + throw new \LogicException('You can not delete the anonymous user! It is needed for permission checking without a logged in user'); + } + + //Disallow deleting the current logged-in user + if ($entity === $this->getUser()) { + throw new \LogicException('You can not delete your own user account!'); } return $this->_delete($request, $entity, $recursionHelper); diff --git a/src/Controller/UserSettingsController.php b/src/Controller/UserSettingsController.php index 704bacb7..4e56015a 100644 --- a/src/Controller/UserSettingsController.php +++ b/src/Controller/UserSettingsController.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace App\Controller; use App\Entity\Attachments\Attachment; +use App\Entity\UserSystem\ApiToken; +use App\Entity\UserSystem\ApiTokenLevel; use App\Entity\UserSystem\U2FKey; use App\Entity\UserSystem\User; use App\Entity\UserSystem\WebauthnKey; @@ -34,11 +36,11 @@ use App\Services\UserSystem\TFA\BackupCodeManager; use App\Services\UserSystem\UserAvatarHelper; use Doctrine\ORM\EntityManagerInterface; use RuntimeException; -use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticator; use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticatorInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Form\Extension\Core\Type\DateTimeType; +use Symfony\Component\Form\Extension\Core\Type\EnumType; use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; @@ -49,21 +51,15 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Security\Core\Validator\Constraints\UserPassword; use Symfony\Component\Validator\Constraints\Length; #[Route(path: '/user')] class UserSettingsController extends AbstractController { - /** - * @var EventDispatcher|EventDispatcherInterface - */ - protected $eventDispatcher; - - public function __construct(protected bool $demo_mode, EventDispatcherInterface $eventDispatcher) + public function __construct(protected bool $demo_mode, protected EventDispatcherInterface $eventDispatcher) { - $this->eventDispatcher = $eventDispatcher; } #[Route(path: '/2fa_backup_codes', name: 'show_backup_codes')] @@ -244,7 +240,10 @@ class UserSettingsController extends AbstractController $page_need_reload = true; } - /** @var Form $form We need a form implementation for the next calls */ + if (!$form instanceof Form) { + throw new RuntimeException('Form is not an instance of Form, so we cannot retrieve the clicked button!'); + } + //Remove the avatar attachment from the user if requested if ($form->getClickedButton() && 'remove_avatar' === $form->getClickedButton()->getName() && $user->getMasterPictureAttachment() instanceof Attachment) { $em->remove($user->getMasterPictureAttachment()); @@ -395,4 +394,99 @@ class UserSettingsController extends AbstractController ], ]); } + + /** + * @return Response + */ + #[Route('/api_token/create', name: 'user_api_token_create')] + public function addApiToken(Request $request, EntityManagerInterface $entityManager): Response + { + $this->denyAccessUnlessGranted('@api.manage_tokens'); + //When user change its settings, he should be logged in fully. + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + + $token = new ApiToken(); + if (!$this->getUser() instanceof User) { + throw new RuntimeException('This controller only works only for Part-DB User objects!'); + } + $token->setUser($this->getUser()); + + $secret = null; + + $form = $this->createFormBuilder($token) + ->add('name', TextType::class, [ + 'label' => 'api_tokens.name', + ]) + ->add('level', EnumType::class, [ + 'class' => ApiTokenLevel::class, + 'label' => 'api_tokens.access_level', + 'help' => 'api_tokens.access_level.help', + 'choice_label' => fn (ApiTokenLevel $level) => $level->getTranslationKey(), + ]) + ->add('valid_until', DateTimeType::class, [ + 'label' => 'api_tokens.expiration_date', + 'widget' => 'single_text', + 'help' => 'api_tokens.expiration_date.help', + 'required' => false, + 'html5' => true + ]) + ->add('submit', SubmitType::class, [ + 'label' => 'save', + ]) + ->getForm(); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $entityManager->persist($token); + $entityManager->flush(); + + $secret = $token->getToken(); + } + + return $this->render('users/api_token_create.html.twig', [ + 'token' => $token, + 'form' => $form, + 'secret' => $secret, + ]); + } + + #[Route(path: '/api_token/delete', name: 'user_api_tokens_delete', methods: ['DELETE'])] + public function apiTokenRemove(Request $request, EntityManagerInterface $entityManager): Response + { + $this->denyAccessUnlessGranted('@api.manage_tokens'); + //When user change its settings, he should be logged in fully. + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + + $user = $this->getUser(); + if (!$user instanceof User) { + throw new RuntimeException('This controller only works only for Part-DB User objects!'); + } + + if (!$this->isCsrfTokenValid('delete'.$user->getID(), $request->request->get('_token'))) { + $this->addFlash('error', 'csfr_invalid'); + return $this->redirectToRoute('user_settings'); + } + + //Extract the token id from the request + $token_id = $request->request->getInt('token_id'); + + $token = $entityManager->find(ApiToken::class, $token_id); + if ($token === null) { + $this->addFlash('error', 'tfa_u2f.u2f_delete.not_existing'); + return $this->redirectToRoute('user_settings'); + } + //User can only delete its own API tokens + if ($token->getUser() !== $user) { + $this->addFlash('error', 'tfa_u2f.u2f_delete.access_denied'); + return $this->redirectToRoute('user_settings'); + } + + //Do the actual deletion + $entityManager->remove($token); + $entityManager->flush(); + + $this->addFlash('success', 'api_tokens.deleted'); + return $this->redirectToRoute('user_settings'); + } } diff --git a/src/Controller/WebauthnKeyRegistrationController.php b/src/Controller/WebauthnKeyRegistrationController.php index 9329a3b9..b2c4f344 100644 --- a/src/Controller/WebauthnKeyRegistrationController.php +++ b/src/Controller/WebauthnKeyRegistrationController.php @@ -30,7 +30,7 @@ use RuntimeException; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Routing\Attribute\Route; use function Symfony\Component\Translation\t; diff --git a/src/DataFixtures/APITokenFixtures.php b/src/DataFixtures/APITokenFixtures.php new file mode 100644 index 00000000..0ab0b7bb --- /dev/null +++ b/src/DataFixtures/APITokenFixtures.php @@ -0,0 +1,97 @@ +. + */ + +declare(strict_types=1); + + +namespace App\DataFixtures; + +use App\Entity\UserSystem\ApiToken; +use App\Entity\UserSystem\ApiTokenLevel; +use App\Entity\UserSystem\User; +use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Common\DataFixtures\DependentFixtureInterface; +use Doctrine\Persistence\ObjectManager; + +class APITokenFixtures extends Fixture implements DependentFixtureInterface +{ + public const TOKEN_READONLY = 'tcp_readonly'; + public const TOKEN_EDIT = 'tcp_edit'; + public const TOKEN_ADMIN = 'tcp_admin'; + public const TOKEN_FULL = 'tcp_full'; + public const TOKEN_EXPIRED = 'tcp_expired'; + + public function load(ObjectManager $manager): void + { + /** @var User $admin_user */ + $admin_user = $this->getReference(UserFixtures::ADMIN, User::class); + + $read_only_token = new ApiToken(); + $read_only_token->setUser($admin_user); + $read_only_token->setLevel(ApiTokenLevel::READ_ONLY); + $read_only_token->setName('read-only'); + $this->setTokenSecret($read_only_token, self::TOKEN_READONLY); + $manager->persist($read_only_token); + + $editor_token = new ApiToken(); + $editor_token->setUser($admin_user); + $editor_token->setLevel(ApiTokenLevel::EDIT); + $editor_token->setName('edit'); + $this->setTokenSecret($editor_token, self::TOKEN_EDIT); + $manager->persist($editor_token); + + $admin_token = new ApiToken(); + $admin_token->setUser($admin_user); + $admin_token->setLevel(ApiTokenLevel::ADMIN); + $admin_token->setName('admin'); + $this->setTokenSecret($admin_token, self::TOKEN_ADMIN); + $manager->persist($admin_token); + + $full_token = new ApiToken(); + $full_token->setUser($admin_user); + $full_token->setLevel(ApiTokenLevel::FULL); + $full_token->setName('full'); + $this->setTokenSecret($full_token, self::TOKEN_FULL); + $manager->persist($full_token); + + $expired_token = new ApiToken(); + $expired_token->setUser($admin_user); + $expired_token->setLevel(ApiTokenLevel::FULL); + $expired_token->setName('expired'); + $expired_token->setValidUntil(new \DateTimeImmutable('-1 day')); + $this->setTokenSecret($expired_token, self::TOKEN_EXPIRED); + $manager->persist($expired_token); + + $manager->flush(); + } + + private function setTokenSecret(ApiToken $token, string $secret): void + { + //Access private property + $reflection = new \ReflectionClass($token); + $property = $reflection->getProperty('token'); + $property->setValue($token, $secret); + } + + public function getDependencies(): array + { + return [UserFixtures::class]; + } +} \ No newline at end of file diff --git a/src/DataFixtures/DataStructureFixtures.php b/src/DataFixtures/DataStructureFixtures.php index a2043bdb..fc713d4d 100644 --- a/src/DataFixtures/DataStructureFixtures.php +++ b/src/DataFixtures/DataStructureFixtures.php @@ -29,9 +29,8 @@ use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; -use App\Entity\UserSystem\User; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\DataFixtures\DependentFixtureInterface; use Doctrine\ORM\EntityManagerInterface; @@ -51,7 +50,7 @@ class DataStructureFixtures extends Fixture implements DependentFixtureInterface { //Reset autoincrement $types = [AttachmentType::class, Project::class, Category::class, Footprint::class, Manufacturer::class, - MeasurementUnit::class, Storelocation::class, Supplier::class,]; + MeasurementUnit::class, StorageLocation::class, Supplier::class,]; foreach ($types as $type) { $this->createNodesForClass($type, $manager); @@ -75,30 +74,37 @@ class DataStructureFixtures extends Fixture implements DependentFixtureInterface /** @var AbstractStructuralDBElement $node1 */ $node1 = new $class(); $node1->setName('Node 1'); + $this->addReference($class . '_1', $node1); /** @var AbstractStructuralDBElement $node2 */ $node2 = new $class(); $node2->setName('Node 2'); + $this->addReference($class . '_2', $node2); /** @var AbstractStructuralDBElement $node3 */ $node3 = new $class(); $node3->setName('Node 3'); + $this->addReference($class . '_3', $node3); $node1_1 = new $class(); $node1_1->setName('Node 1.1'); $node1_1->setParent($node1); + $this->addReference($class . '_4', $node1_1); $node1_2 = new $class(); $node1_2->setName('Node 1.2'); $node1_2->setParent($node1); + $this->addReference($class . '_5', $node1_2); $node2_1 = new $class(); $node2_1->setName('Node 2.1'); $node2_1->setParent($node2); + $this->addReference($class . '_6', $node2_1); $node1_1_1 = new $class(); $node1_1_1->setName('Node 1.1.1'); $node1_1_1->setParent($node1_1); + $this->addReference($class . '_7', $node1_1_1); $manager->persist($node1); $manager->persist($node2); diff --git a/src/DataFixtures/EDADataFixtures.php b/src/DataFixtures/EDADataFixtures.php new file mode 100644 index 00000000..1484f03e --- /dev/null +++ b/src/DataFixtures/EDADataFixtures.php @@ -0,0 +1,71 @@ +. + */ + +declare(strict_types=1); + + +namespace App\DataFixtures; + +use App\Entity\Parts\Category; +use App\Entity\Parts\Footprint; +use App\Entity\Parts\Part; +use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Common\DataFixtures\DependentFixtureInterface; +use Doctrine\Persistence\ObjectManager; + +class EDADataFixtures extends Fixture implements DependentFixtureInterface +{ + + public function getDependencies(): array + { + return [PartFixtures::class]; + } + + public function load(ObjectManager $manager): void + { + //Load elements from DB + $category1 = $manager->find(Category::class, 1); + $footprint1 = $manager->find(Footprint::class, 1); + + $part1 = $manager->find(Part::class, 1); + + //Put some data into category1 and foorprint1 + $category1?->getEdaInfo() + ->setExcludeFromBoard(true) + ->setKicadSymbol('Category:1') + ->setReferencePrefix('C') + ; + + $footprint1?->getEdaInfo() + ->setKicadFootprint('Footprint:1') + ; + + //Put some data into part1 (which overrides the data from category1 and footprint1 on part1) + $part1?->getEdaInfo() + ->setExcludeFromSim(false) + ->setKicadSymbol('Part:1') + ->setKicadFootprint('Part:1') + ->setReferencePrefix('P') + ; + + //Flush the changes + $manager->flush(); + } +} \ No newline at end of file diff --git a/src/DataFixtures/LogEntryFixtures.php b/src/DataFixtures/LogEntryFixtures.php new file mode 100644 index 00000000..eb9cf731 --- /dev/null +++ b/src/DataFixtures/LogEntryFixtures.php @@ -0,0 +1,106 @@ +. + */ + +declare(strict_types=1); + + +namespace App\DataFixtures; + +use App\Entity\LogSystem\ElementCreatedLogEntry; +use App\Entity\LogSystem\ElementDeletedLogEntry; +use App\Entity\LogSystem\ElementEditedLogEntry; +use App\Entity\Parts\Category; +use App\Entity\UserSystem\User; +use Doctrine\Bundle\FixturesBundle\Fixture; +use Doctrine\Common\DataFixtures\DependentFixtureInterface; +use Doctrine\Persistence\ObjectManager; + +class LogEntryFixtures extends Fixture implements DependentFixtureInterface +{ + + public function load(ObjectManager $manager): void + { + $this->createCategoryEntries($manager); + $this->createDeletedCategory($manager); + } + + public function createCategoryEntries(ObjectManager $manager): void + { + $category = $this->getReference(Category::class . '_1', Category::class); + + $logEntry = new ElementCreatedLogEntry($category); + $logEntry->setTimestamp(new \DateTimeImmutable("+1 second")); + $logEntry->setUser($this->getReference(UserFixtures::ADMIN, User::class)); + $logEntry->setComment('Test'); + $manager->persist($logEntry); + + $logEntry = new ElementEditedLogEntry($category); + $logEntry->setTimestamp(new \DateTimeImmutable("+2 second")); + $logEntry->setUser($this->getReference(UserFixtures::ADMIN, User::class)); + $logEntry->setComment('Test'); + + $logEntry->setOldData(['name' => 'Test']); + $logEntry->setNewData(['name' => 'Node 1.1']); + + $manager->persist($logEntry); + $manager->flush(); + } + + public function createDeletedCategory(ObjectManager $manager): void + { + //We create a fictive category to test the deletion + $category = new Category(); + $category->setName('Node 100'); + + //Assume a category with id 100 was deleted + $reflClass = new \ReflectionClass($category); + $reflClass->getProperty('id')->setValue($category, 100); + + //The whole lifecycle from creation to deletion + $logEntry = new ElementCreatedLogEntry($category); + $logEntry->setUser($this->getReference(UserFixtures::ADMIN, User::class)); + $logEntry->setComment('Creation'); + $manager->persist($logEntry); + + $logEntry = new ElementEditedLogEntry($category); + $logEntry->setTimestamp(new \DateTimeImmutable("+1 second")); + $logEntry->setUser($this->getReference(UserFixtures::ADMIN, User::class)); + $logEntry->setComment('Edit'); + $logEntry->setOldData(['name' => 'Test']); + $logEntry->setNewData(['name' => 'Node 100']); + $manager->persist($logEntry); + + $logEntry = new ElementDeletedLogEntry($category); + $logEntry->setTimestamp(new \DateTimeImmutable("+2 second")); + $logEntry->setUser($this->getReference(UserFixtures::ADMIN, User::class)); + $logEntry->setOldData(['name' => 'Node 100', 'id' => 100, 'comment' => 'Test comment']); + $manager->persist($logEntry); + + $manager->flush(); + } + + public function getDependencies(): array + { + return [ + UserFixtures::class, + DataStructureFixtures::class + ]; + } +} \ No newline at end of file diff --git a/src/DataFixtures/PartFixtures.php b/src/DataFixtures/PartFixtures.php index 477d0dd3..a60d037d 100644 --- a/src/DataFixtures/PartFixtures.php +++ b/src/DataFixtures/PartFixtures.php @@ -49,7 +49,7 @@ use App\Entity\Parts\Manufacturer; use App\Entity\Parts\ManufacturingStatus; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Orderdetail; use App\Entity\PriceInformations\Pricedetail; @@ -73,6 +73,7 @@ class PartFixtures extends Fixture implements DependentFixtureInterface $part = new Part(); $part->setName('Part 1'); $part->setCategory($manager->find(Category::class, 1)); + $this->addReference(Part::class . '_1', $part); $manager->persist($part); /** More complex part */ @@ -83,8 +84,10 @@ class PartFixtures extends Fixture implements DependentFixtureInterface $part->setManufacturer($manager->find(Manufacturer::class, 1)); $part->setTags('test, Test, Part2'); $part->setMass(100.2); + $part->setIpn('IPN123'); $part->setNeedsReview(true); $part->setManufacturingStatus(ManufacturingStatus::ACTIVE); + $this->addReference(Part::class . '_2', $part); $manager->persist($part); /** Part with orderdetails, storelocations and Attachments */ @@ -94,14 +97,16 @@ class PartFixtures extends Fixture implements DependentFixtureInterface $part->setCategory($manager->find(Category::class, 1)); $partLot1 = new PartLot(); $partLot1->setAmount(1.0); - $partLot1->setStorageLocation($manager->find(Storelocation::class, 1)); + $partLot1->setStorageLocation($manager->find(StorageLocation::class, 1)); $part->addPartLot($partLot1); + $partLot2 = new PartLot(); - $partLot2->setExpirationDate(new DateTime()); + $partLot2->setExpirationDate(new \DateTimeImmutable()); $partLot2->setComment('Test'); $partLot2->setNeedsRefill(true); - $partLot2->setStorageLocation($manager->find(Storelocation::class, 3)); + $partLot2->setStorageLocation($manager->find(StorageLocation::class, 3)); + $partLot2->setUserBarcode('lot2_vendor_barcode'); $part->addPartLot($partLot2); $orderdetail = new Orderdetail(); @@ -126,11 +131,13 @@ class PartFixtures extends Fixture implements DependentFixtureInterface $attachment = new PartAttachment(); $attachment->setName('Test2'); - $attachment->setPath('invalid'); + $attachment->setInternalPath('invalid'); $attachment->setShowInTable(true); $attachment->setAttachmentType($manager->find(AttachmentType::class, 1)); $part->addAttachment($attachment); + $this->addReference(Part::class . '_3', $part); + $manager->persist($part); $manager->flush(); } diff --git a/src/DataFixtures/UserFixtures.php b/src/DataFixtures/UserFixtures.php index 171f671e..922d0b1e 100644 --- a/src/DataFixtures/UserFixtures.php +++ b/src/DataFixtures/UserFixtures.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace App\DataFixtures; +use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\DataFixtures\DependentFixtureInterface; @@ -31,6 +32,8 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; class UserFixtures extends Fixture implements DependentFixtureInterface { + public const ADMIN = 'user-admin'; + public function __construct(protected UserPasswordHasherInterface $encoder, protected EntityManagerInterface $em) { } @@ -39,7 +42,7 @@ class UserFixtures extends Fixture implements DependentFixtureInterface { $anonymous = new User(); $anonymous->setName('anonymous'); - $anonymous->setGroup($this->getReference(GroupFixtures::READONLY)); + $anonymous->setGroup($this->getReference(GroupFixtures::READONLY, Group::class)); $anonymous->setNeedPwChange(false); $anonymous->setPassword($this->encoder->hashPassword($anonymous, 'test')); $manager->persist($anonymous); @@ -48,15 +51,17 @@ class UserFixtures extends Fixture implements DependentFixtureInterface $admin->setName('admin'); $admin->setPassword($this->encoder->hashPassword($admin, 'test')); $admin->setNeedPwChange(false); - $admin->setGroup($this->getReference(GroupFixtures::ADMINS)); + $admin->setGroup($this->getReference(GroupFixtures::ADMINS, Group::class)); $manager->persist($admin); + $this->addReference(self::ADMIN, $admin); $user = new User(); $user->setName('user'); $user->setNeedPwChange(false); + $user->setEmail('user@invalid.invalid'); $user->setFirstName('Test')->setLastName('User'); $user->setPassword($this->encoder->hashPassword($user, 'test')); - $user->setGroup($this->getReference(GroupFixtures::USERS)); + $user->setGroup($this->getReference(GroupFixtures::USERS, Group::class)); $manager->persist($user); $noread = new User(); @@ -66,6 +71,9 @@ class UserFixtures extends Fixture implements DependentFixtureInterface $manager->persist($noread); $manager->flush(); + + //Ensure that the anonymous user has the ID 0 + $manager->getRepository(User::class)->changeID($anonymous, User::ID_ANONYMOUS); } public function getDependencies(): array diff --git a/src/DataTables/Adapters/CustomFetchJoinORMAdapter.php b/src/DataTables/Adapters/CustomFetchJoinORMAdapter.php index b296c4fa..ff69a69e 100644 --- a/src/DataTables/Adapters/CustomFetchJoinORMAdapter.php +++ b/src/DataTables/Adapters/CustomFetchJoinORMAdapter.php @@ -50,6 +50,6 @@ class CustomFetchJoinORMAdapter extends FetchJoinORMAdapter $paginator = new Paginator($qb_without_group_by); - return $paginator->count() ?? 0; + return $paginator->count(); } } diff --git a/src/DataTables/Adapters/FetchResultsAtOnceORMAdapter.php b/src/DataTables/Adapters/FetchResultsAtOnceORMAdapter.php index 182dcbda..eda48038 100644 --- a/src/DataTables/Adapters/FetchResultsAtOnceORMAdapter.php +++ b/src/DataTables/Adapters/FetchResultsAtOnceORMAdapter.php @@ -23,8 +23,6 @@ declare(strict_types=1); namespace App\DataTables\Adapters; -use App\DataTables\Events\ORMPostQueryEvent; -use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\QueryBuilder; use Omines\DataTablesBundle\Adapter\AdapterQuery; use Omines\DataTablesBundle\Adapter\Doctrine\Event\ORMAdapterQueryEvent; @@ -45,7 +43,7 @@ class FetchResultsAtOnceORMAdapter extends ORMAdapter $state = $query->getState(); // Apply definitive view state for current 'page' of the table - foreach ($state->getOrderBy() as list($column, $direction)) { + foreach ($state->getOrderBy() as [$column, $direction]) { /** @var AbstractColumn $column */ if ($column->isOrderable()) { $builder->addOrderBy($column->getOrderField(), $direction); diff --git a/src/DataTables/Adapters/TwoStepORMAdapater.php b/src/DataTables/Adapters/TwoStepORMAdapter.php similarity index 84% rename from src/DataTables/Adapters/TwoStepORMAdapater.php rename to src/DataTables/Adapters/TwoStepORMAdapter.php index 9246e6d1..51315c32 100644 --- a/src/DataTables/Adapters/TwoStepORMAdapater.php +++ b/src/DataTables/Adapters/TwoStepORMAdapter.php @@ -23,12 +23,9 @@ declare(strict_types=1); namespace App\DataTables\Adapters; -use Doctrine\ORM\AbstractQuery; +use Doctrine\ORM\Query\Expr\From; use Doctrine\ORM\Query; -use Doctrine\ORM\Query\Expr\Select; -use Doctrine\ORM\Query\ResultSetMapping; use Doctrine\ORM\QueryBuilder; -use Doctrine\ORM\Tools\Pagination\CountOutputWalker; use Doctrine\ORM\Tools\Pagination\Paginator; use Doctrine\Persistence\ManagerRegistry; use Omines\DataTablesBundle\Adapter\AdapterQuery; @@ -49,16 +46,18 @@ use Symfony\Component\OptionsResolver\OptionsResolver; * This way we save the overhead of the fetch join query for the count and counting, which can be very slow, cause * no indexes can be used. */ -class TwoStepORMAdapater extends ORMAdapter +class TwoStepORMAdapter extends ORMAdapter { private \Closure $detailQueryCallable; private bool $use_simple_total = false; - public function __construct(ManagerRegistry $registry = null) + private \Closure|null $query_modifier = null; + + public function __construct(?ManagerRegistry $registry = null) { parent::__construct($registry); - $this->detailQueryCallable = static function (QueryBuilder $qb, array $ids) { + $this->detailQueryCallable = static function (QueryBuilder $qb, array $ids): never { throw new \RuntimeException('You need to set the detail_query option to use the TwoStepORMAdapter'); }; } @@ -68,9 +67,7 @@ class TwoStepORMAdapater extends ORMAdapter parent::configureOptions($resolver); $resolver->setRequired('filter_query'); - $resolver->setDefault('query', function (Options $options) { - return $options['filter_query']; - }); + $resolver->setDefault('query', fn(Options $options) => $options['filter_query']); $resolver->setRequired('detail_query'); $resolver->setAllowedTypes('detail_query', \Closure::class); @@ -81,6 +78,10 @@ class TwoStepORMAdapater extends ORMAdapter */ $resolver->setDefault('simple_total_query', false); + //Add the possibility of a closure to modify the query builder before the query is executed + $resolver->setDefault('query_modifier', null); + $resolver->setAllowedTypes('query_modifier', ['null', \Closure::class]); + } protected function afterConfiguration(array $options): void @@ -88,6 +89,7 @@ class TwoStepORMAdapater extends ORMAdapter parent::afterConfiguration($options); $this->detailQueryCallable = $options['detail_query']; $this->use_simple_total = $options['simple_total_query']; + $this->query_modifier = $options['query_modifier']; } protected function prepareQuery(AdapterQuery $query): void @@ -105,7 +107,7 @@ class TwoStepORMAdapater extends ORMAdapter } } - /** @var Query\Expr\From $fromClause */ + /** @var From $fromClause */ $fromClause = $builder->getDQLPart('from')[0]; $identifier = "{$fromClause->getAlias()}.{$this->metadata->getSingleIdentifierFieldName()}"; @@ -126,8 +128,18 @@ class TwoStepORMAdapater extends ORMAdapter $query->setIdentifierPropertyPath($this->mapFieldToPropertyPath($identifier, $aliases)); } + protected function hasGroupByPart(string $identifier, array $gbList): bool + { + //Always return true, to fix the issue with the count query, when having mutliple group by parts + return true; + } + protected function getCount(QueryBuilder $queryBuilder, $identifier): int { + if ($this->query_modifier !== null) { + $queryBuilder = $this->query_modifier->__invoke(clone $queryBuilder); + } + //Check if the queryBuilder is having a HAVING clause, which would make the count query invalid if (empty($queryBuilder->getDQLPart('having'))) { //If not, we can use the simple count query @@ -146,7 +158,7 @@ class TwoStepORMAdapater extends ORMAdapter $state = $query->getState(); // Apply definitive view state for current 'page' of the table - foreach ($state->getOrderBy() as list($column, $direction)) { + foreach ($state->getOrderBy() as [$column, $direction]) { /** @var AbstractColumn $column */ if ($column->isOrderable()) { $builder->addOrderBy($column->getOrderField(), $direction); @@ -159,6 +171,11 @@ class TwoStepORMAdapater extends ORMAdapter ; } + //Apply the query modifier, if set + if ($this->query_modifier !== null) { + $builder = $this->query_modifier->__invoke($builder); + } + $id_query = $builder->getQuery(); $event = new ORMAdapterQueryEvent($id_query); $state->getDataTable()->getEventDispatcher()->dispatch($event, ORMAdapterEvents::PRE_QUERY); @@ -183,7 +200,7 @@ class TwoStepORMAdapater extends ORMAdapter /** The paginator count queries can be rather slow, so when query for total count (100ms or longer), * just return the entity count. */ - /** @var Query\Expr\From $from_expr */ + /** @var From $from_expr */ $from_expr = $queryBuilder->getDQLPart('from')[0]; return $this->manager->getRepository($from_expr->getFrom())->count([]); diff --git a/src/DataTables/AttachmentDataTable.php b/src/DataTables/AttachmentDataTable.php index 62a35049..16e6a7a7 100644 --- a/src/DataTables/AttachmentDataTable.php +++ b/src/DataTables/AttachmentDataTable.php @@ -27,7 +27,6 @@ use App\DataTables\Column\PrettyBoolColumn; use App\DataTables\Column\RowClassColumn; use App\DataTables\Filters\AttachmentFilter; use App\Entity\Attachments\Attachment; -use App\Entity\LogSystem\AbstractLogEntry; use App\Services\Attachments\AttachmentManager; use App\Services\Attachments\AttachmentURLGenerator; use App\Services\ElementTypeNameGenerator; @@ -35,6 +34,7 @@ use App\Services\EntityURLGenerator; use Doctrine\ORM\QueryBuilder; use Omines\DataTablesBundle\Adapter\Doctrine\ORM\SearchCriteriaProvider; use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapter; +use Omines\DataTablesBundle\Column\NumberColumn; use Omines\DataTablesBundle\Column\TextColumn; use Omines\DataTablesBundle\DataTable; use Omines\DataTablesBundle\DataTableTypeInterface; @@ -50,8 +50,8 @@ final class AttachmentDataTable implements DataTableTypeInterface { $dataTable->add('dont_matter', RowClassColumn::class, [ 'render' => function ($value, Attachment $context): string { - //Mark attachments with missing files yellow - if(!$this->attachmentHelper->isFileExisting($context)){ + //Mark attachments yellow which have an internal file linked that doesn't exist + if($context->hasInternal() && !$this->attachmentHelper->isInternalFileExisting($context)){ return 'table-warning'; } @@ -64,8 +64,8 @@ final class AttachmentDataTable implements DataTableTypeInterface 'className' => 'no-colvis', 'render' => function ($value, Attachment $context): string { if ($context->isPicture() - && !$context->isExternal() - && $this->attachmentHelper->isFileExisting($context)) { + && $this->attachmentHelper->isInternalFileExisting($context)) { + $title = htmlspecialchars($context->getName()); if ($context->getFilename()) { $title .= ' ('.htmlspecialchars($context->getFilename()).')'; @@ -85,33 +85,20 @@ final class AttachmentDataTable implements DataTableTypeInterface }, ]); + $dataTable->add('id', NumberColumn::class, [ + 'label' => $this->translator->trans('part.table.id'), + 'visible' => false, + ]); + $dataTable->add('name', TextColumn::class, [ 'label' => 'attachment.edit.name', - 'render' => function ($value, Attachment $context) { - //Link to external source - if ($context->isExternal()) { - return sprintf( - '%s', - htmlspecialchars($context->getURL()), - htmlspecialchars($value) - ); - } - - if ($this->attachmentHelper->isFileExisting($context)) { - return sprintf( - '%s', - $this->entityURLGenerator->viewURL($context), - htmlspecialchars($value) - ); - } - - return $value; - }, + 'orderField' => 'NATSORT(attachment.name)', ]); $dataTable->add('attachment_type', TextColumn::class, [ 'label' => 'attachment.table.type', 'field' => 'attachment_type.name', + 'orderField' => 'NATSORT(attachment_type.name)', 'render' => fn($value, Attachment $context): string => sprintf( '%s', $this->entityURLGenerator->editURL($context->getAttachmentType()), @@ -129,25 +116,60 @@ final class AttachmentDataTable implements DataTableTypeInterface ), ]); - $dataTable->add('filename', TextColumn::class, [ - 'label' => $this->translator->trans('attachment.table.filename'), + $dataTable->add('internal_link', TextColumn::class, [ + 'label' => 'attachment.table.internal_file', 'propertyPath' => 'filename', + 'orderField' => 'NATSORT(attachment.original_filename)', + 'render' => function ($value, Attachment $context) { + if ($this->attachmentHelper->isInternalFileExisting($context)) { + return sprintf( + '%s', + $this->entityURLGenerator->viewURL($context), + htmlspecialchars($value) + ); + } + + return $value; + } + ]); + + $dataTable->add('external_link', TextColumn::class, [ + 'label' => 'attachment.table.external_link', + 'propertyPath' => 'host', + 'orderField' => 'attachment.external_path', + 'render' => function ($value, Attachment $context) { + if ($context->hasExternal()) { + return sprintf( + '%s', + htmlspecialchars((string) $context->getExternalPath()), + htmlspecialchars((string) $context->getExternalPath()), + htmlspecialchars($value), + ); + } + + return $value; + } ]); $dataTable->add('filesize', TextColumn::class, [ 'label' => $this->translator->trans('attachment.table.filesize'), 'render' => function ($value, Attachment $context) { - if ($context->isExternal()) { + if (!$context->hasInternal()) { return sprintf( ' %s ', - $this->translator->trans('attachment.external') + $this->translator->trans('attachment.external_only') ); } - if ($this->attachmentHelper->isFileExisting($context)) { - return $this->attachmentHelper->getHumanFileSize($context); + if ($this->attachmentHelper->isInternalFileExisting($context)) { + return sprintf( + ' + %s + ', + $this->attachmentHelper->getHumanFileSize($context) + ); } return sprintf( @@ -221,7 +243,7 @@ final class AttachmentDataTable implements DataTableTypeInterface //We do the most stuff here in the filter class if (isset($options['filter'])) { if(!$options['filter'] instanceof AttachmentFilter) { - throw new \Exception('filter must be an instance of AttachmentFilter!'); + throw new \RuntimeException('filter must be an instance of AttachmentFilter!'); } $filter = $options['filter']; diff --git a/src/DataTables/Column/EntityColumn.php b/src/DataTables/Column/EntityColumn.php index 2facdc81..54ae3fb3 100644 --- a/src/DataTables/Column/EntityColumn.php +++ b/src/DataTables/Column/EntityColumn.php @@ -42,7 +42,7 @@ class EntityColumn extends AbstractColumn * @param mixed $value The single value of the column * @return mixed */ - public function normalize($value): mixed + public function normalize(mixed $value): mixed { /** @var AbstractNamedDBElement $value */ return $value; diff --git a/src/DataTables/Column/EnumColumn.php b/src/DataTables/Column/EnumColumn.php index e41b79e4..5a5d998d 100644 --- a/src/DataTables/Column/EnumColumn.php +++ b/src/DataTables/Column/EnumColumn.php @@ -1,4 +1,7 @@ . */ - namespace App\DataTables\Column; use Omines\DataTablesBundle\Column\AbstractColumn; diff --git a/src/DataTables/Column/LocaleDateTimeColumn.php b/src/DataTables/Column/LocaleDateTimeColumn.php index ce8cccda..e60b2867 100644 --- a/src/DataTables/Column/LocaleDateTimeColumn.php +++ b/src/DataTables/Column/LocaleDateTimeColumn.php @@ -47,7 +47,7 @@ class LocaleDateTimeColumn extends AbstractColumn } if (!$value instanceof DateTimeInterface) { - $value = new DateTime((string) $value); + $value = new \DateTimeImmutable((string) $value); } $formatValues = [ @@ -79,10 +79,7 @@ class LocaleDateTimeColumn extends AbstractColumn ); } - /** - * @return $this - */ - protected function configureOptions(OptionsResolver $resolver): self + protected function configureOptions(OptionsResolver $resolver): static { parent::configureOptions($resolver); diff --git a/src/DataTables/Column/LogEntryTargetColumn.php b/src/DataTables/Column/LogEntryTargetColumn.php index 272ff732..7a329cd7 100644 --- a/src/DataTables/Column/LogEntryTargetColumn.php +++ b/src/DataTables/Column/LogEntryTargetColumn.php @@ -22,25 +22,9 @@ declare(strict_types=1); namespace App\DataTables\Column; -use App\Entity\Attachments\Attachment; -use App\Entity\Base\AbstractDBElement; -use App\Entity\Contracts\NamedElementInterface; -use App\Entity\LogSystem\AbstractLogEntry; -use App\Entity\LogSystem\UserNotAllowedLogEntry; -use App\Entity\Parameters\AbstractParameter; -use App\Entity\Parts\PartLot; -use App\Entity\PriceInformations\Orderdetail; -use App\Entity\PriceInformations\Pricedetail; -use App\Entity\ProjectSystem\ProjectBOMEntry; -use App\Exceptions\EntityNotSupportedException; -use App\Repository\LogEntryRepository; -use App\Services\ElementTypeNameGenerator; -use App\Services\EntityURLGenerator; use App\Services\LogSystem\LogTargetHelper; -use Doctrine\ORM\EntityManagerInterface; use Omines\DataTablesBundle\Column\AbstractColumn; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Contracts\Translation\TranslatorInterface; class LogEntryTargetColumn extends AbstractColumn { @@ -57,10 +41,7 @@ class LogEntryTargetColumn extends AbstractColumn return $value; } - /** - * @return $this - */ - public function configureOptions(OptionsResolver $resolver): self + public function configureOptions(OptionsResolver $resolver): static { parent::configureOptions($resolver); $resolver->setDefault('show_associated', true); diff --git a/src/DataTables/Column/MarkdownColumn.php b/src/DataTables/Column/MarkdownColumn.php index 9120c4c5..41f62649 100644 --- a/src/DataTables/Column/MarkdownColumn.php +++ b/src/DataTables/Column/MarkdownColumn.php @@ -35,9 +35,9 @@ class MarkdownColumn extends AbstractColumn * The normalize function is responsible for converting parsed and processed data to a datatables-appropriate type. * * @param mixed $value The single value of the column - * @return mixed + * @return string */ - public function normalize($value): mixed + public function normalize(mixed $value): string { return $this->markdown->markForRendering($value, true); } diff --git a/src/DataTables/Column/PartAttachmentsColumn.php b/src/DataTables/Column/PartAttachmentsColumn.php index 0787a1e0..7b209028 100644 --- a/src/DataTables/Column/PartAttachmentsColumn.php +++ b/src/DataTables/Column/PartAttachmentsColumn.php @@ -43,7 +43,7 @@ class PartAttachmentsColumn extends AbstractColumn * @param mixed $value The single value of the column * @return mixed */ - public function normalize($value): mixed + public function normalize(mixed $value): mixed { return $value; } @@ -79,10 +79,7 @@ class PartAttachmentsColumn extends AbstractColumn return $tmp; } - /** - * @return $this - */ - public function configureOptions(OptionsResolver $resolver): self + public function configureOptions(OptionsResolver $resolver): static { parent::configureOptions($resolver); diff --git a/src/DataTables/Column/RowClassColumn.php b/src/DataTables/Column/RowClassColumn.php index 9b7aa0a0..15bf8bf2 100644 --- a/src/DataTables/Column/RowClassColumn.php +++ b/src/DataTables/Column/RowClassColumn.php @@ -28,11 +28,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class RowClassColumn extends AbstractColumn { - - /** - * @return $this - */ - public function configureOptions(OptionsResolver $resolver): self + public function configureOptions(OptionsResolver $resolver): static { parent::configureOptions($resolver); @@ -56,7 +52,7 @@ class RowClassColumn extends AbstractColumn /** * @return mixed */ - public function normalize($value) + public function normalize($value): mixed { return $value; } diff --git a/src/DataTables/Column/SIUnitNumberColumn.php b/src/DataTables/Column/SIUnitNumberColumn.php index be50505d..b64152be 100644 --- a/src/DataTables/Column/SIUnitNumberColumn.php +++ b/src/DataTables/Column/SIUnitNumberColumn.php @@ -32,10 +32,7 @@ class SIUnitNumberColumn extends AbstractColumn { } - /** - * @return $this - */ - public function configureOptions(OptionsResolver $resolver): self + public function configureOptions(OptionsResolver $resolver): static { parent::configureOptions($resolver); diff --git a/src/DataTables/Column/SelectColumn.php b/src/DataTables/Column/SelectColumn.php index 82003a62..39445ac8 100644 --- a/src/DataTables/Column/SelectColumn.php +++ b/src/DataTables/Column/SelectColumn.php @@ -30,10 +30,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; */ class SelectColumn extends AbstractColumn { - /** - * @return $this - */ - public function configureOptions(OptionsResolver $resolver): self + public function configureOptions(OptionsResolver $resolver): static { parent::configureOptions($resolver); @@ -41,7 +38,7 @@ class SelectColumn extends AbstractColumn 'label' => '', 'orderable' => false, 'searchable' => false, - 'className' => 'select-checkbox no-colvis', + 'className' => 'dt-select no-colvis', 'visible' => true, ]); diff --git a/src/DataTables/Column/TagsColumn.php b/src/DataTables/Column/TagsColumn.php index 49ed89c7..f98a3900 100644 --- a/src/DataTables/Column/TagsColumn.php +++ b/src/DataTables/Column/TagsColumn.php @@ -37,7 +37,7 @@ class TagsColumn extends AbstractColumn * @param mixed $value The single value of the column * @return mixed */ - public function normalize($value): mixed + public function normalize(mixed $value): mixed { if (empty($value)) { return []; diff --git a/src/DataTables/ErrorDataTable.php b/src/DataTables/ErrorDataTable.php index ea3c1e76..833ea934 100644 --- a/src/DataTables/ErrorDataTable.php +++ b/src/DataTables/ErrorDataTable.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace App\DataTables; use App\DataTables\Column\RowClassColumn; -use App\Entity\Parts\Part; use Omines\DataTablesBundle\Adapter\ArrayAdapter; use Omines\DataTablesBundle\Column\TextColumn; use Omines\DataTablesBundle\DataTable; @@ -67,8 +66,10 @@ class ErrorDataTable implements DataTableTypeInterface //Build the array containing data $data = []; + $n = 0; foreach ($options['errors'] as $error) { - $data[] = ['error' => $error]; + $data['error_' . $n] = ['error' => $error]; + $n++; } $dataTable->createAdapter(ArrayAdapter::class, $data); diff --git a/src/DataTables/Filters/AttachmentFilter.php b/src/DataTables/Filters/AttachmentFilter.php index 9f8cf094..d41bbe39 100644 --- a/src/DataTables/Filters/AttachmentFilter.php +++ b/src/DataTables/Filters/AttachmentFilter.php @@ -45,6 +45,9 @@ class AttachmentFilter implements FilterInterface public readonly DateTimeConstraint $lastModified; public readonly DateTimeConstraint $addedDate; + public readonly TextConstraint $originalFileName; + public readonly TextConstraint $externalLink; + public function __construct(NodesListBuilder $nodesListBuilder) { @@ -55,6 +58,9 @@ class AttachmentFilter implements FilterInterface $this->lastModified = new DateTimeConstraint('attachment.lastModified'); $this->addedDate = new DateTimeConstraint('attachment.addedDate'); $this->showInTable = new BooleanConstraint('attachment.show_in_table'); + $this->originalFileName = new TextConstraint('attachment.original_filename'); + $this->externalLink = new TextConstraint('attachment.external_path'); + } public function apply(QueryBuilder $queryBuilder): void diff --git a/src/DataTables/Filters/Constraints/AbstractConstraint.php b/src/DataTables/Filters/Constraints/AbstractConstraint.php index cbb62352..7f16511e 100644 --- a/src/DataTables/Filters/Constraints/AbstractConstraint.php +++ b/src/DataTables/Filters/Constraints/AbstractConstraint.php @@ -45,7 +45,7 @@ abstract class AbstractConstraint implements FilterInterface * @var string The property where this BooleanConstraint should apply to */ protected string $property, - string $identifier = null) + ?string $identifier = null) { $this->identifier = $identifier ?? $this->generateParameterIdentifier($property); } diff --git a/src/DataTables/Filters/Constraints/BooleanConstraint.php b/src/DataTables/Filters/Constraints/BooleanConstraint.php index b3f1dc47..8eb4f042 100644 --- a/src/DataTables/Filters/Constraints/BooleanConstraint.php +++ b/src/DataTables/Filters/Constraints/BooleanConstraint.php @@ -28,7 +28,7 @@ class BooleanConstraint extends AbstractConstraint { public function __construct( string $property, - string $identifier = null, + ?string $identifier = null, /** @var bool|null The value of our constraint */ protected ?bool $value = null ) diff --git a/src/DataTables/Filters/Constraints/DateTimeConstraint.php b/src/DataTables/Filters/Constraints/DateTimeConstraint.php index 1ded472e..a3043170 100644 --- a/src/DataTables/Filters/Constraints/DateTimeConstraint.php +++ b/src/DataTables/Filters/Constraints/DateTimeConstraint.php @@ -22,9 +22,92 @@ declare(strict_types=1); */ namespace App\DataTables\Filters\Constraints; +use Doctrine\ORM\QueryBuilder; +use RuntimeException; + /** - * An alias of NumberConstraint to use to filter on a DateTime + * Similar to NumberConstraint but for DateTime values */ -class DateTimeConstraint extends NumberConstraint +class DateTimeConstraint extends AbstractConstraint { + protected const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN']; + + public function __construct( + string $property, + ?string $identifier = null, + /** + * The value1 used for comparison (this is the main one used for all mono-value comparisons) + */ + protected \DateTimeInterface|null $value1 = null, + protected ?string $operator = null, + /** + * The second value used when operator is RANGE; this is the upper bound of the range + */ + protected \DateTimeInterface|null $value2 = null) + { + parent::__construct($property, $identifier); + } + + public function getValue1(): ?\DateTimeInterface + { + return $this->value1; + } + + public function setValue1(\DateTimeInterface|null $value1): void + { + $this->value1 = $value1; + } + + public function getValue2(): ?\DateTimeInterface + { + return $this->value2; + } + + public function setValue2(?\DateTimeInterface $value2): void + { + $this->value2 = $value2; + } + + public function getOperator(): string|null + { + return $this->operator; + } + + /** + * @param string $operator + */ + public function setOperator(?string $operator): void + { + $this->operator = $operator; + } + + public function isEnabled(): bool + { + return $this->value1 !== null + && ($this->operator !== null && $this->operator !== ''); + } + + public function apply(QueryBuilder $queryBuilder): void + { + //If no value is provided then we do not apply a filter + if (!$this->isEnabled()) { + return; + } + + //Ensure we have an valid operator + if(!in_array($this->operator, self::ALLOWED_OPERATOR_VALUES, true)) { + throw new \RuntimeException('Invalid operator '. $this->operator . ' provided. Valid operators are '. implode(', ', self::ALLOWED_OPERATOR_VALUES)); + } + + if ($this->operator !== 'BETWEEN') { + $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, $this->operator, $this->value1); + } else { + if ($this->value2 === null) { + throw new RuntimeException("Cannot use operator BETWEEN without value2!"); + } + + $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier . '1', '>=', $this->value1); + $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier . '2', '<=', $this->value2); + } + } } diff --git a/src/DataTables/Filters/Constraints/EntityConstraint.php b/src/DataTables/Filters/Constraints/EntityConstraint.php index 7365890b..c75da80d 100644 --- a/src/DataTables/Filters/Constraints/EntityConstraint.php +++ b/src/DataTables/Filters/Constraints/EntityConstraint.php @@ -40,14 +40,14 @@ class EntityConstraint extends AbstractConstraint * @param class-string $class * @param string $property * @param string|null $identifier - * @param null|T $value + * @param T|null $value * @param string|null $operator */ public function __construct(protected ?NodesListBuilder $nodesListBuilder, protected string $class, string $property, - string $identifier = null, - protected $value = null, + ?string $identifier = null, + protected ?AbstractDBElement $value = null, protected ?string $operator = null) { if (!$nodesListBuilder instanceof NodesListBuilder && $this->isStructural()) { @@ -137,7 +137,7 @@ class EntityConstraint extends AbstractConstraint } //We need to handle null values differently, as they can not be compared with == or != - if (!$this->value instanceof AbstractDBElement) { + if ($this->value === null) { if($this->operator === '=' || $this->operator === 'INCLUDING_CHILDREN') { $queryBuilder->andWhere(sprintf("%s IS NULL", $this->property)); return; @@ -152,8 +152,9 @@ class EntityConstraint extends AbstractConstraint } if($this->operator === '=' || $this->operator === '!=') { - $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, $this->operator, $this->value); - return; + //Include null values on != operator, so that really all values are returned that are not equal to the given value + $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, $this->operator, $this->value, $this->operator === '!='); + return; } //Otherwise retrieve the children list and apply the operator to it @@ -168,7 +169,8 @@ class EntityConstraint extends AbstractConstraint } if ($this->operator === 'EXCLUDING_CHILDREN') { - $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, 'NOT IN', $list); + //Include null values in the result, so that all elements that are not in the list are returned + $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, 'NOT IN', $list, true); return; } } else { diff --git a/src/DataTables/Filters/Constraints/FilterTrait.php b/src/DataTables/Filters/Constraints/FilterTrait.php index 26707841..3260e4e3 100644 --- a/src/DataTables/Filters/Constraints/FilterTrait.php +++ b/src/DataTables/Filters/Constraints/FilterTrait.php @@ -56,8 +56,14 @@ trait FilterTrait /** * Adds a simple constraint in the form of (property OPERATOR value) (e.g. "part.name = :name") to the given query builder. + * @param QueryBuilder $queryBuilder The query builder to add the constraint to + * @param string $property The property to compare + * @param string $parameterIdentifier The identifier for the parameter + * @param string $comparison_operator The comparison operator to use + * @param mixed $value The value to compare to + * @param bool $include_null If true, the result of this constraint will also include null values of this property (useful for exclusion filters) */ - protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, mixed $value): void + protected function addSimpleAndConstraint(QueryBuilder $queryBuilder, string $property, string $parameterIdentifier, string $comparison_operator, mixed $value, bool $include_null = false): void { if ($comparison_operator === 'IN' || $comparison_operator === 'NOT IN') { $expression = sprintf("%s %s (:%s)", $property, $comparison_operator, $parameterIdentifier); @@ -65,6 +71,10 @@ trait FilterTrait $expression = sprintf("%s %s :%s", $property, $comparison_operator, $parameterIdentifier); } + if ($include_null) { + $expression = sprintf("(%s OR %s IS NULL)", $expression, $property); + } + if($this->useHaving || $this->isAggregateFunctionString($property)) { //If the property is an aggregate function, we have to use the "having" instead of the "where" $queryBuilder->andHaving($expression); } else { diff --git a/src/DataTables/Filters/Constraints/NumberConstraint.php b/src/DataTables/Filters/Constraints/NumberConstraint.php index 9e53b8f3..dc7cf733 100644 --- a/src/DataTables/Filters/Constraints/NumberConstraint.php +++ b/src/DataTables/Filters/Constraints/NumberConstraint.php @@ -29,12 +29,28 @@ class NumberConstraint extends AbstractConstraint { protected const ALLOWED_OPERATOR_VALUES = ['=', '!=', '<', '>', '<=', '>=', 'BETWEEN']; - public function getValue1(): float|int|null|\DateTimeInterface + public function __construct( + string $property, + ?string $identifier = null, + /** + * The value1 used for comparison (this is the main one used for all mono-value comparisons) + */ + protected float|int|null $value1 = null, + protected ?string $operator = null, + /** + * The second value used when operator is RANGE; this is the upper bound of the range + */ + protected float|int|null $value2 = null) + { + parent::__construct($property, $identifier); + } + + public function getValue1(): float|int|null { return $this->value1; } - public function setValue1(float|int|\DateTimeInterface|null $value1): void + public function setValue1(float|int|null $value1): void { $this->value1 = $value1; } @@ -63,22 +79,6 @@ class NumberConstraint extends AbstractConstraint } - public function __construct( - string $property, - string $identifier = null, - /** - * The value1 used for comparison (this is the main one used for all mono-value comparisons) - */ - protected float|int|\DateTimeInterface|null $value1 = null, - protected ?string $operator = null, - /** - * The second value used when operator is RANGE; this is the upper bound of the range - */ - protected float|int|\DateTimeInterface|null $value2 = null) - { - parent::__construct($property, $identifier); - } - public function isEnabled(): bool { return $this->value1 !== null @@ -105,7 +105,13 @@ class NumberConstraint extends AbstractConstraint } $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier . '1', '>=', $this->value1); - $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier . '2', '<=', $this->value2); + + //Workaround for the amountSum which we need to add twice on postgres. Replace one of the __ with __2 to make it work + //Otherwise we get an error, that __partLot was already defined + + $property2 = str_replace('__', '__2', $this->property); + + $this->addSimpleAndConstraint($queryBuilder, $property2, $this->identifier . '2', '<=', $this->value2); } } } diff --git a/src/DataTables/Filters/Constraints/Part/LessThanDesiredConstraint.php b/src/DataTables/Filters/Constraints/Part/LessThanDesiredConstraint.php index eed37b8b..011824e5 100644 --- a/src/DataTables/Filters/Constraints/Part/LessThanDesiredConstraint.php +++ b/src/DataTables/Filters/Constraints/Part/LessThanDesiredConstraint.php @@ -23,13 +23,20 @@ declare(strict_types=1); namespace App\DataTables\Filters\Constraints\Part; use App\DataTables\Filters\Constraints\BooleanConstraint; +use App\Entity\Parts\PartLot; use Doctrine\ORM\QueryBuilder; class LessThanDesiredConstraint extends BooleanConstraint { - public function __construct(string $property = null, string $identifier = null, ?bool $default_value = null) + public function __construct(?string $property = null, ?string $identifier = null, ?bool $default_value = null) { - parent::__construct($property ?? 'amountSum', $identifier, $default_value); + parent::__construct($property ?? '( + SELECT COALESCE(SUM(ld_partLot.amount), 0.0) + FROM '.PartLot::class.' ld_partLot + WHERE ld_partLot.part = part.id + AND ld_partLot.instock_unknown = false + AND (ld_partLot.expiration_date IS NULL OR ld_partLot.expiration_date > CURRENT_DATE()) + )', $identifier ?? 'amountSumLessThanDesired', $default_value); } public function apply(QueryBuilder $queryBuilder): void @@ -41,9 +48,9 @@ class LessThanDesiredConstraint extends BooleanConstraint //If value is true, we want to filter for parts with stock < desired stock if ($this->value) { - $queryBuilder->andHaving('amountSum < minamount'); + $queryBuilder->andHaving( $this->property . ' < part.minamount'); } else { - $queryBuilder->andHaving('amountSum >= minamount'); + $queryBuilder->andHaving($this->property . ' >= part.minamount'); } } } diff --git a/src/DataTables/Filters/Constraints/Part/TagsConstraint.php b/src/DataTables/Filters/Constraints/Part/TagsConstraint.php index acd04745..02eab7a1 100644 --- a/src/DataTables/Filters/Constraints/Part/TagsConstraint.php +++ b/src/DataTables/Filters/Constraints/Part/TagsConstraint.php @@ -24,23 +24,15 @@ namespace App\DataTables\Filters\Constraints\Part; use Doctrine\ORM\Query\Expr\Orx; use App\DataTables\Filters\Constraints\AbstractConstraint; -use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; class TagsConstraint extends AbstractConstraint { final public const ALLOWED_OPERATOR_VALUES = ['ANY', 'ALL', 'NONE']; - /** - * @param string $value - */ - public function __construct(string $property, string $identifier = null, /** - * @var string The value to compare to - */ - protected $value = null, /** - * @var string|null The operator to use - */ - protected ?string $operator = '') + public function __construct(string $property, ?string $identifier = null, + protected ?string $value = null, + protected ?string $operator = '') { parent::__construct($property, $identifier); } @@ -62,12 +54,12 @@ class TagsConstraint extends AbstractConstraint return $this; } - public function getValue(): string + public function getValue(): ?string { return $this->value; } - public function setValue(string $value): self + public function setValue(?string $value): self { $this->value = $value; return $this; @@ -93,15 +85,18 @@ class TagsConstraint extends AbstractConstraint */ protected function getExpressionForTag(QueryBuilder $queryBuilder, string $tag): Orx { + //Escape any %, _ or \ in the tag + $tag = addcslashes($tag, '%_\\'); + $tag_identifier_prefix = uniqid($this->identifier . '_', false); $expr = $queryBuilder->expr(); $tmp = $expr->orX( - $expr->like($this->property, ':' . $tag_identifier_prefix . '_1'), - $expr->like($this->property, ':' . $tag_identifier_prefix . '_2'), - $expr->like($this->property, ':' . $tag_identifier_prefix . '_3'), - $expr->eq($this->property, ':' . $tag_identifier_prefix . '_4'), + 'ILIKE(' . $this->property . ', :' . $tag_identifier_prefix . '_1) = TRUE', + 'ILIKE(' . $this->property . ', :' . $tag_identifier_prefix . '_2) = TRUE', + 'ILIKE(' . $this->property . ', :' . $tag_identifier_prefix . '_3) = TRUE', + 'ILIKE(' . $this->property . ', :' . $tag_identifier_prefix . '_4) = TRUE', ); //Set the parameters for the LIKE expression, in each variation of the tag (so with a comma, at the end, at the beginning, and on both ends, and equaling the tag) @@ -138,6 +133,7 @@ class TagsConstraint extends AbstractConstraint return; } + //@phpstan-ignore-next-line Keep this check to ensure that everything has the same structure even if we add a new operator if ($this->operator === 'NONE') { $queryBuilder->andWhere($queryBuilder->expr()->not($queryBuilder->expr()->orX(...$tagsExpressions))); return; diff --git a/src/DataTables/Filters/Constraints/TextConstraint.php b/src/DataTables/Filters/Constraints/TextConstraint.php index 60f83328..31b12a5e 100644 --- a/src/DataTables/Filters/Constraints/TextConstraint.php +++ b/src/DataTables/Filters/Constraints/TextConstraint.php @@ -32,10 +32,10 @@ class TextConstraint extends AbstractConstraint /** * @param string $value */ - public function __construct(string $property, string $identifier = null, /** - * @var string The value to compare to + public function __construct(string $property, ?string $identifier = null, /** + * @var string|null The value to compare to */ - protected $value = null, /** + protected ?string $value = null, /** * @var string|null The operator to use */ protected ?string $operator = '') @@ -60,12 +60,12 @@ class TextConstraint extends AbstractConstraint return $this; } - public function getValue(): string + public function getValue(): ?string { return $this->value; } - public function setValue(string $value): self + public function setValue(?string $value): self { $this->value = $value; return $this; @@ -107,13 +107,14 @@ class TextConstraint extends AbstractConstraint } if ($like_value !== null) { - $this->addSimpleAndConstraint($queryBuilder, $this->property, $this->identifier, 'LIKE', $like_value); + $queryBuilder->andWhere(sprintf('ILIKE(%s, :%s) = TRUE', $this->property, $this->identifier)); + $queryBuilder->setParameter($this->identifier, $like_value); return; } //Regex is only supported on MySQL and needs a special function if ($this->operator === 'REGEX') { - $queryBuilder->andWhere(sprintf('REGEXP(%s, :%s) = 1', $this->property, $this->identifier)); + $queryBuilder->andWhere(sprintf('REGEXP(%s, :%s) = TRUE', $this->property, $this->identifier)); $queryBuilder->setParameter($this->identifier, $this->value); } } diff --git a/src/DataTables/Filters/LogFilter.php b/src/DataTables/Filters/LogFilter.php index a3bbd851..35d32e74 100644 --- a/src/DataTables/Filters/LogFilter.php +++ b/src/DataTables/Filters/LogFilter.php @@ -27,7 +27,6 @@ use App\DataTables\Filters\Constraints\DateTimeConstraint; use App\DataTables\Filters\Constraints\EntityConstraint; use App\DataTables\Filters\Constraints\InstanceOfConstraint; use App\DataTables\Filters\Constraints\IntConstraint; -use App\DataTables\Filters\Constraints\NumberConstraint; use App\Entity\UserSystem\User; use Doctrine\ORM\QueryBuilder; diff --git a/src/DataTables/Filters/PartFilter.php b/src/DataTables/Filters/PartFilter.php index 3d03f00c..ff98c76f 100644 --- a/src/DataTables/Filters/PartFilter.php +++ b/src/DataTables/Filters/PartFilter.php @@ -37,8 +37,10 @@ use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\PartLot; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; +use App\Entity\ProjectSystem\Project; use App\Entity\UserSystem\User; use App\Services\Trees\NodesListBuilder; use Doctrine\Common\Collections\ArrayCollection; @@ -90,6 +92,15 @@ class PartFilter implements FilterInterface public readonly ArrayCollection $parameters; public readonly IntConstraint $parametersCount; + /************************************************* + * Project tab + *************************************************/ + + public readonly EntityConstraint $project; + public readonly NumberConstraint $bomQuantity; + public readonly TextConstraint $bomName; + public readonly TextConstraint $bomComment; + public function __construct(NodesListBuilder $nodesListBuilder) { $this->name = new TextConstraint('part.name'); @@ -113,33 +124,44 @@ class PartFilter implements FilterInterface This seems to be related to the fact, that PDO does not have an float parameter type and using string type does not work in this situation (at least in SQLite) TODO: Find a better solution here */ - //We have to use Having here, as we use an alias column which is not supported on the where clause and would result in an error - $this->amountSum = (new IntConstraint('amountSum'))->useHaving(); - $this->lotCount = new IntConstraint('COUNT(partLots)'); + $this->amountSum = (new IntConstraint('( + SELECT COALESCE(SUM(__partLot.amount), 0.0) + FROM '.PartLot::class.' __partLot + WHERE __partLot.part = part.id + AND __partLot.instock_unknown = false + AND (__partLot.expiration_date IS NULL OR __partLot.expiration_date > CURRENT_DATE()) + )', identifier: "amountSumWhere")); + $this->lotCount = new IntConstraint('COUNT(_partLots)'); $this->lessThanDesired = new LessThanDesiredConstraint(); - $this->storelocation = new EntityConstraint($nodesListBuilder, Storelocation::class, 'partLots.storage_location'); - $this->lotNeedsRefill = new BooleanConstraint('partLots.needs_refill'); - $this->lotUnknownAmount = new BooleanConstraint('partLots.instock_unknown'); - $this->lotExpirationDate = new DateTimeConstraint('partLots.expiration_date'); - $this->lotDescription = new TextConstraint('partLots.description'); - $this->lotOwner = new EntityConstraint($nodesListBuilder, User::class, 'partLots.owner'); + $this->storelocation = new EntityConstraint($nodesListBuilder, StorageLocation::class, '_partLots.storage_location'); + $this->lotNeedsRefill = new BooleanConstraint('_partLots.needs_refill'); + $this->lotUnknownAmount = new BooleanConstraint('_partLots.instock_unknown'); + $this->lotExpirationDate = new DateTimeConstraint('_partLots.expiration_date'); + $this->lotDescription = new TextConstraint('_partLots.description'); + $this->lotOwner = new EntityConstraint($nodesListBuilder, User::class, '_partLots.owner'); $this->manufacturer = new EntityConstraint($nodesListBuilder, Manufacturer::class, 'part.manufacturer'); $this->manufacturer_product_number = new TextConstraint('part.manufacturer_product_number'); $this->manufacturer_product_url = new TextConstraint('part.manufacturer_product_url'); $this->manufacturing_status = new ChoiceConstraint('part.manufacturing_status'); - $this->attachmentsCount = new IntConstraint('COUNT(attachments)'); - $this->attachmentType = new EntityConstraint($nodesListBuilder, AttachmentType::class, 'attachments.attachment_type'); - $this->attachmentName = new TextConstraint('attachments.name'); + $this->attachmentsCount = new IntConstraint('COUNT(_attachments)'); + $this->attachmentType = new EntityConstraint($nodesListBuilder, AttachmentType::class, '_attachments.attachment_type'); + $this->attachmentName = new TextConstraint('_attachments.name'); - $this->supplier = new EntityConstraint($nodesListBuilder, Supplier::class, 'orderdetails.supplier'); - $this->orderdetailsCount = new IntConstraint('COUNT(orderdetails)'); - $this->obsolete = new BooleanConstraint('orderdetails.obsolete'); + $this->supplier = new EntityConstraint($nodesListBuilder, Supplier::class, '_orderdetails.supplier'); + $this->orderdetailsCount = new IntConstraint('COUNT(_orderdetails)'); + $this->obsolete = new BooleanConstraint('_orderdetails.obsolete'); $this->parameters = new ArrayCollection(); - $this->parametersCount = new IntConstraint('COUNT(parameters)'); + $this->parametersCount = new IntConstraint('COUNT(_parameters)'); + + $this->project = new EntityConstraint($nodesListBuilder, Project::class, '_projectBomEntries.project'); + $this->bomQuantity = new NumberConstraint('_projectBomEntries.quantity'); + $this->bomName = new TextConstraint('_projectBomEntries.name'); + $this->bomComment = new TextConstraint('_projectBomEntries.comment'); + } public function apply(QueryBuilder $queryBuilder): void diff --git a/src/DataTables/Filters/PartSearchFilter.php b/src/DataTables/Filters/PartSearchFilter.php index b94d805a..6e2e5894 100644 --- a/src/DataTables/Filters/PartSearchFilter.php +++ b/src/DataTables/Filters/PartSearchFilter.php @@ -21,8 +21,6 @@ declare(strict_types=1); * along with this program. If not, see . */ namespace App\DataTables\Filters; - -use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; class PartSearchFilter implements FilterInterface @@ -82,7 +80,7 @@ class PartSearchFilter implements FilterInterface $fields_to_search[] = 'part.name'; } if($this->category) { - $fields_to_search[] = 'category.name'; + $fields_to_search[] = '_category.name'; } if($this->description) { $fields_to_search[] = 'part.description'; @@ -94,22 +92,22 @@ class PartSearchFilter implements FilterInterface $fields_to_search[] = 'part.tags'; } if($this->storelocation) { - $fields_to_search[] = 'storelocations.name'; + $fields_to_search[] = '_storelocations.name'; } if($this->ordernr) { - $fields_to_search[] = 'orderdetails.supplierpartnr'; + $fields_to_search[] = '_orderdetails.supplierpartnr'; } if($this->mpn) { $fields_to_search[] = 'part.manufacturer_product_number'; } if($this->supplier) { - $fields_to_search[] = 'suppliers.name'; + $fields_to_search[] = '_suppliers.name'; } if($this->manufacturer) { - $fields_to_search[] = 'manufacturer.name'; + $fields_to_search[] = '_manufacturer.name'; } if($this->footprint) { - $fields_to_search[] = 'footprint.name'; + $fields_to_search[] = '_footprint.name'; } if ($this->ipn) { $fields_to_search[] = 'part.ipn'; @@ -130,18 +128,18 @@ class PartSearchFilter implements FilterInterface //Convert the fields to search to a list of expressions $expressions = array_map(function (string $field): string { if ($this->regex) { - return sprintf("REGEXP(%s, :search_query) = 1", $field); + return sprintf("REGEXP(%s, :search_query) = TRUE", $field); } - return sprintf("%s LIKE :search_query", $field); + return sprintf("ILIKE(%s, :search_query) = TRUE", $field); }, $fields_to_search); - //Add Or concatation of the expressions to our query + //Add Or concatenation of the expressions to our query $queryBuilder->andWhere( $queryBuilder->expr()->orX(...$expressions) ); - //For regex we pass the query as is, for like we add % to the start and end as wildcards + //For regex, we pass the query as is, for like we add % to the start and end as wildcards if ($this->regex) { $queryBuilder->setParameter('search_query', $this->keyword); } else { diff --git a/src/DataTables/Helpers/ColumnSortHelper.php b/src/DataTables/Helpers/ColumnSortHelper.php new file mode 100644 index 00000000..05bd8182 --- /dev/null +++ b/src/DataTables/Helpers/ColumnSortHelper.php @@ -0,0 +1,130 @@ +. + */ + +declare(strict_types=1); + + +namespace App\DataTables\Helpers; + +use Omines\DataTablesBundle\DataTable; +use Psr\Log\LoggerInterface; + +class ColumnSortHelper +{ + private array $columns = []; + + public function __construct(private readonly LoggerInterface $logger) + { + } + + /** + * Add a new column which can be sorted and visibility controlled by the user. The basic syntax is similar to + * the DataTable add method, but with additional options. + * @param string $name + * @param string $type + * @param array $options + * @param string|null $alias If an alias is set here, the column will be available under this alias in the config + * string instead of the name. + * @param bool $visibility_configurable If set to false, this column can not be visibility controlled by the user + * @return $this + */ + public function add(string $name, string $type, array $options = [], ?string $alias = null, + bool $visibility_configurable = true): self + { + //Alias allows us to override the name of the column in the env variable + $this->columns[$alias ?? $name] = [ + 'name' => $name, + 'type' => $type, + 'options' => $options, + 'visibility_configurable' => $visibility_configurable + ]; + + return $this; + } + + /** + * Remove all columns saved inside this helper + * @return void + */ + public function reset(): void + { + $this->columns = []; + } + + /** + * Apply the visibility configuration to the given DataTable and configure the columns. + * @param DataTable $dataTable + * @param string|array $visible_columns Either a list or a comma separated string of column names, which should + * be visible by default. If a column is not listed here, it will be hidden by default. + * @return void + */ + public function applyVisibilityAndConfigureColumns(DataTable $dataTable, string|array $visible_columns, + string $config_var_name): void + { + //If the config is given as a string, convert it to an array first + if (!is_array($visible_columns)) { + $visible_columns = array_map(trim(...), explode(",", $visible_columns)); + } + + $processed_columns = []; + + //First add all columns which visibility is not configurable + foreach ($this->columns as $col_id => $col_data) { + if (!$col_data['visibility_configurable']) { + $this->addColumnEntry($dataTable, $this->columns[$col_id], null); + $processed_columns[] = $col_id; + } + } + + //Afterwards the columns, which should be visible by default + foreach ($visible_columns as $col_id) { + if (!isset($this->columns[$col_id]) || !$this->columns[$col_id]['visibility_configurable']) { + $this->logger->warning("Configuration option $config_var_name specify invalid column '$col_id'. Column is skipped."); + continue; + } + + if (in_array($col_id, $processed_columns, true)) { + $this->logger->warning("Configuration option $config_var_name specify column '$col_id' multiple time. Only first occurrence is used."); + continue; + } + $this->addColumnEntry($dataTable, $this->columns[$col_id], true); + $processed_columns[] = $col_id; + } + + //and the remaining non-visible columns + foreach (array_keys($this->columns) as $col_id) { + if (in_array($col_id, $processed_columns, true)) { + // column already processed + continue; + } + $this->addColumnEntry($dataTable, $this->columns[$col_id], false); + $processed_columns[] = $col_id; + } + } + + private function addColumnEntry(DataTable $dataTable, array $entry, ?bool $visible): void + { + $options = $entry['options'] ?? []; + if (!is_null($visible)) { + $options["visible"] = $visible; + } + $dataTable->add($entry['name'], $entry['type'], $options); + } +} \ No newline at end of file diff --git a/src/DataTables/Helpers/PartDataTableHelper.php b/src/DataTables/Helpers/PartDataTableHelper.php index 8499e303..c33c3a82 100644 --- a/src/DataTables/Helpers/PartDataTableHelper.php +++ b/src/DataTables/Helpers/PartDataTableHelper.php @@ -20,14 +20,17 @@ declare(strict_types=1); * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + namespace App\DataTables\Helpers; +use App\Entity\Parts\StorageLocation; use App\Entity\ProjectSystem\Project; use App\Entity\Attachments\Attachment; use App\Entity\Parts\Part; use App\Services\Attachments\AttachmentURLGenerator; use App\Services\Attachments\PartPreviewGenerator; use App\Services\EntityURLGenerator; +use App\Services\Formatters\AmountFormatter; use Symfony\Contracts\Translation\TranslatorInterface; /** @@ -35,8 +38,13 @@ use Symfony\Contracts\Translation\TranslatorInterface; */ class PartDataTableHelper { - public function __construct(private readonly PartPreviewGenerator $previewGenerator, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly EntityURLGenerator $entityURLGenerator, private readonly TranslatorInterface $translator) - { + public function __construct( + private readonly PartPreviewGenerator $previewGenerator, + private readonly AttachmentURLGenerator $attachmentURLGenerator, + private readonly EntityURLGenerator $entityURLGenerator, + private readonly TranslatorInterface $translator, + private readonly AmountFormatter $amountFormatter, + ) { } public function renderName(Part $context): string @@ -45,14 +53,16 @@ class PartDataTableHelper //Depending on the part status we show a different icon (the later conditions have higher priority) if ($context->isFavorite()) { - $icon = sprintf('', $this->translator->trans('part.favorite.badge')); + $icon = sprintf('', + $this->translator->trans('part.favorite.badge')); } if ($context->isNeedsReview()) { - $icon = sprintf('', $this->translator->trans('part.needs_review.badge')); + $icon = sprintf('', + $this->translator->trans('part.needs_review.badge')); } if ($context->getBuiltProject() instanceof Project) { $icon = sprintf('', - $this->translator->trans('part.info.projectBuildPart.hint') . ': ' . $context->getBuiltProject()->getName()); + $this->translator->trans('part.info.projectBuildPart.hint').': '.$context->getBuiltProject()->getName()); } @@ -85,4 +95,62 @@ class PartDataTableHelper $title ); } + + public function renderStorageLocations(Part $context): string + { + $tmp = []; + foreach ($context->getPartLots() as $lot) { + //Ignore lots without storelocation + if (!$lot->getStorageLocation() instanceof StorageLocation) { + continue; + } + $tmp[] = sprintf( + '%s', + $this->entityURLGenerator->listPartsURL($lot->getStorageLocation()), + htmlspecialchars($lot->getStorageLocation()->getFullPath()), + htmlspecialchars($lot->getStorageLocation()->getName()) + ); + } + + return implode('
', $tmp); + } + + public function renderAmount(Part $context): string + { + $amount = $context->getAmountSum(); + $expiredAmount = $context->getExpiredAmountSum(); + + $ret = ''; + + if ($context->isAmountUnknown()) { + //When all amounts are unknown, we show a question mark + if ($amount === 0.0) { + $ret .= sprintf('?', + $this->translator->trans('part_lots.instock_unknown')); + } else { //Otherwise mark it with greater equal and the (known) amount + $ret .= sprintf('', + $this->translator->trans('part_lots.instock_unknown') + ); + $ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit())); + } + } else { + $ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit())); + } + + //If we have expired lots, we show them in parentheses behind + if ($expiredAmount > 0) { + $ret .= sprintf(' (+%s)', + $this->translator->trans('part_lots.is_expired'), + htmlspecialchars($this->amountFormatter->format($expiredAmount, $context->getPartUnit()))); + } + + //When the amount is below the minimum amount, we highlight the number red + if ($context->isNotEnoughInstock()) { + $ret = sprintf('%s', + $this->translator->trans('part.info.amount.less_than_desired'), + $ret); + } + + return $ret; + } } diff --git a/src/DataTables/LogDataTable.php b/src/DataTables/LogDataTable.php index c00b7446..f6604279 100644 --- a/src/DataTables/LogDataTable.php +++ b/src/DataTables/LogDataTable.php @@ -40,7 +40,6 @@ use App\Entity\LogSystem\ElementCreatedLogEntry; use App\Entity\LogSystem\ElementDeletedLogEntry; use App\Entity\LogSystem\ElementEditedLogEntry; use App\Entity\LogSystem\PartStockChangedLogEntry; -use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; use App\Exceptions\EntityNotSupportedException; use App\Repository\LogEntryRepository; @@ -55,7 +54,6 @@ use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapter; use Omines\DataTablesBundle\Column\TextColumn; use Omines\DataTablesBundle\DataTable; use Omines\DataTablesBundle\DataTableTypeInterface; -use Psr\Log\LogLevel; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -139,7 +137,7 @@ class LogDataTable implements DataTableTypeInterface if ($context instanceof PartStockChangedLogEntry) { $text .= sprintf( ' (%s)', - $this->translator->trans('log.part_stock_changed.' . $context->getInstockChangeType()->toExtraShortType()) + $this->translator->trans($context->getInstockChangeType()->toTranslationKey()) ); } @@ -156,7 +154,7 @@ class LogDataTable implements DataTableTypeInterface $dataTable->add('user', TextColumn::class, [ 'label' => 'log.user', - 'orderField' => 'user.name', + 'orderField' => 'NATSORT(user.name)', 'render' => function ($value, AbstractLogEntry $context): string { $user = $context->getUser(); @@ -164,7 +162,7 @@ class LogDataTable implements DataTableTypeInterface if (!$user instanceof User) { if ($context->isCLIEntry()) { return sprintf('%s [%s]', - htmlentities($context->getCLIUsername()), + htmlentities((string) $context->getCLIUsername()), $this->translator->trans('log.cli_user') ); } diff --git a/src/DataTables/PartsDataTable.php b/src/DataTables/PartsDataTable.php index eac739f8..3163a38b 100644 --- a/src/DataTables/PartsDataTable.php +++ b/src/DataTables/PartsDataTable.php @@ -22,20 +22,9 @@ declare(strict_types=1); namespace App\DataTables; -use App\DataTables\Adapters\FetchResultsAtOnceORMAdapter; -use App\DataTables\Adapters\TwoStepORMAdapater; -use App\DataTables\Column\EnumColumn; -use App\Doctrine\Helpers\FieldHelper; -use App\Entity\Parts\ManufacturingStatus; -use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Mapping\ClassMetadataInfo; -use Doctrine\ORM\Query; -use Doctrine\ORM\Tools\Pagination\Paginator; -use Omines\DataTablesBundle\Adapter\Doctrine\Event\ORMAdapterQueryEvent; -use Omines\DataTablesBundle\Adapter\Doctrine\ORMAdapterEvents; -use Symfony\Bundle\SecurityBundle\Security; -use App\Entity\Parts\Storelocation; +use App\DataTables\Adapters\TwoStepORMAdapter; use App\DataTables\Column\EntityColumn; +use App\DataTables\Column\EnumColumn; use App\DataTables\Column\IconLinkColumn; use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\MarkdownColumn; @@ -47,23 +36,38 @@ use App\DataTables\Column\SIUnitNumberColumn; use App\DataTables\Column\TagsColumn; use App\DataTables\Filters\PartFilter; use App\DataTables\Filters\PartSearchFilter; +use App\DataTables\Helpers\ColumnSortHelper; use App\DataTables\Helpers\PartDataTableHelper; +use App\Doctrine\Helpers\FieldHelper; +use App\Entity\Parts\ManufacturingStatus; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Services\Formatters\AmountFormatter; +use App\Entity\ProjectSystem\Project; use App\Services\EntityURLGenerator; +use App\Services\Formatters\AmountFormatter; +use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\QueryBuilder; use Omines\DataTablesBundle\Adapter\Doctrine\ORM\SearchCriteriaProvider; use Omines\DataTablesBundle\Column\TextColumn; use Omines\DataTablesBundle\DataTable; use Omines\DataTablesBundle\DataTableTypeInterface; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Contracts\Translation\TranslatorInterface; final class PartsDataTable implements DataTableTypeInterface { - public function __construct(private readonly EntityURLGenerator $urlGenerator, private readonly TranslatorInterface $translator, private readonly AmountFormatter $amountFormatter, private readonly PartDataTableHelper $partDataTableHelper, private readonly Security $security) - { + const LENGTH_MENU = [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]]; + + public function __construct( + private readonly EntityURLGenerator $urlGenerator, + private readonly TranslatorInterface $translator, + private readonly AmountFormatter $amountFormatter, + private readonly PartDataTableHelper $partDataTableHelper, + private readonly Security $security, + private readonly string $visible_columns, + private readonly ColumnSortHelper $csh, + ) { } public function configureOptions(OptionsResolver $optionsResolver): void @@ -83,9 +87,9 @@ final class PartsDataTable implements DataTableTypeInterface $this->configureOptions($resolver); $options = $resolver->resolve($options); - $dataTable + $this->csh //Color the table rows depending on the review and favorite status - ->add('dont_matter', RowClassColumn::class, [ + ->add('row_color', RowClassColumn::class, [ 'render' => function ($value, Part $context): string { if ($context->isNeedsReview()) { return 'table-secondary'; @@ -96,193 +100,171 @@ final class PartsDataTable implements DataTableTypeInterface return ''; //Default coloring otherwise }, - ]) - - ->add('select', SelectColumn::class) + ], visibility_configurable: false) + ->add('select', SelectColumn::class, visibility_configurable: false) ->add('picture', TextColumn::class, [ 'label' => '', 'className' => 'no-colvis', 'render' => fn($value, Part $context) => $this->partDataTableHelper->renderPicture($context), - ]) + ], visibility_configurable: false) ->add('name', TextColumn::class, [ 'label' => $this->translator->trans('part.table.name'), 'render' => fn($value, Part $context) => $this->partDataTableHelper->renderName($context), + 'orderField' => 'NATSORT(part.name)' ]) ->add('id', TextColumn::class, [ 'label' => $this->translator->trans('part.table.id'), - 'visible' => false, ]) ->add('ipn', TextColumn::class, [ 'label' => $this->translator->trans('part.table.ipn'), - 'visible' => false, + 'orderField' => 'NATSORT(part.ipn)' ]) ->add('description', MarkdownColumn::class, [ 'label' => $this->translator->trans('part.table.description'), - ]); - - if ($this->security->isGranted('@categories.read')) { - $dataTable->add('category', EntityColumn::class, [ + ]) + ->add('category', EntityColumn::class, [ 'label' => $this->translator->trans('part.table.category'), 'property' => 'category', - ]); - } - - if ($this->security->isGranted('@footprints.read')) { - $dataTable->add('footprint', EntityColumn::class, [ + 'orderField' => 'NATSORT(_category.name)' + ]) + ->add('footprint', EntityColumn::class, [ 'property' => 'footprint', 'label' => $this->translator->trans('part.table.footprint'), - ]); - } - if ($this->security->isGranted('@manufacturers.read')) { - $dataTable->add('manufacturer', EntityColumn::class, [ + 'orderField' => 'NATSORT(_footprint.name)' + ]) + ->add('manufacturer', EntityColumn::class, [ 'property' => 'manufacturer', 'label' => $this->translator->trans('part.table.manufacturer'), - ]); - } - if ($this->security->isGranted('@storelocations.read')) { - $dataTable->add('storelocation', TextColumn::class, [ + 'orderField' => 'NATSORT(_manufacturer.name)' + ]) + ->add('storelocation', TextColumn::class, [ 'label' => $this->translator->trans('part.table.storeLocations'), - 'orderField' => 'storelocations.name', - 'render' => function ($value, Part $context): string { - $tmp = []; - foreach ($context->getPartLots() as $lot) { - //Ignore lots without storelocation - if (!$lot->getStorageLocation() instanceof Storelocation) { - continue; - } - $tmp[] = sprintf( - '%s', - $this->urlGenerator->listPartsURL($lot->getStorageLocation()), - htmlspecialchars($lot->getStorageLocation()->getFullPath()), - htmlspecialchars($lot->getStorageLocation()->getName()) - ); - } + //We need to use a aggregate function to get the first store location, as we have a one-to-many relation + 'orderField' => 'NATSORT(MIN(_storelocations.name))', + 'render' => fn ($value, Part $context) => $this->partDataTableHelper->renderStorageLocations($context), + ], alias: 'storage_location') - return implode('
', $tmp); - }, - ]); - } - - $dataTable->add('amount', TextColumn::class, [ - 'label' => $this->translator->trans('part.table.amount'), - 'render' => function ($value, Part $context) { - $amount = $context->getAmountSum(); - $expiredAmount = $context->getExpiredAmountSum(); - - $ret = ''; - - if ($context->isAmountUnknown()) { - //When all amounts are unknown, we show a question mark - if ($amount === 0.0) { - $ret .= sprintf('?', - $this->translator->trans('part_lots.instock_unknown')); - } else { //Otherwise mark it with greater equal and the (known) amount - $ret .= sprintf('', - $this->translator->trans('part_lots.instock_unknown') - ); - $ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit())); - } - } else { - $ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit())); - } - - //If we have expired lots, we show them in parentheses behind - if ($expiredAmount > 0) { - $ret .= sprintf(' (+%s)', - $this->translator->trans('part_lots.is_expired'), - htmlspecialchars($this->amountFormatter->format($expiredAmount, $context->getPartUnit()))); - } - - //When the amount is below the minimum amount, we highlight the number red - if ($context->isNotEnoughInstock()) { - $ret = sprintf('%s', - $this->translator->trans('part.info.amount.less_than_desired'), - $ret); - } - - return $ret; - }, - 'orderField' => 'amountSum' - ]) + ->add('amount', TextColumn::class, [ + 'label' => $this->translator->trans('part.table.amount'), + 'render' => fn ($value, Part $context) => $this->partDataTableHelper->renderAmount($context), + 'orderField' => 'amountSum' + ]) ->add('minamount', TextColumn::class, [ 'label' => $this->translator->trans('part.table.minamount'), - 'visible' => false, - 'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value, $context->getPartUnit())), - ]); - - if ($this->security->isGranted('@footprints.read')) { - $dataTable->add('partUnit', TextColumn::class, [ - 'field' => 'partUnit.name', + 'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value, + $context->getPartUnit())), + ]) + ->add('partUnit', TextColumn::class, [ 'label' => $this->translator->trans('part.table.partUnit'), - 'visible' => false, - ]); - } + 'orderField' => 'NATSORT(_partUnit.name)', + 'render' => function($value, Part $context): string { + $partUnit = $context->getPartUnit(); + if ($partUnit === null) { + return ''; + } - $dataTable->add('addedDate', LocaleDateTimeColumn::class, [ - 'label' => $this->translator->trans('part.table.addedDate'), - 'visible' => false, - ]) + $tmp = htmlspecialchars($partUnit->getName()); + + if ($partUnit->getUnit()) { + $tmp .= ' ('.htmlspecialchars($partUnit->getUnit()).')'; + } + return $tmp; + } + ]) + ->add('addedDate', LocaleDateTimeColumn::class, [ + 'label' => $this->translator->trans('part.table.addedDate'), + ]) ->add('lastModified', LocaleDateTimeColumn::class, [ 'label' => $this->translator->trans('part.table.lastModified'), - 'visible' => false, ]) ->add('needs_review', PrettyBoolColumn::class, [ 'label' => $this->translator->trans('part.table.needsReview'), - 'visible' => false, ]) ->add('favorite', PrettyBoolColumn::class, [ 'label' => $this->translator->trans('part.table.favorite'), - 'visible' => false, ]) ->add('manufacturing_status', EnumColumn::class, [ 'label' => $this->translator->trans('part.table.manufacturingStatus'), - 'visible' => false, 'class' => ManufacturingStatus::class, - 'render' => function(?ManufacturingStatus $status, Part $context): string { - if (!$status) { + 'render' => function (?ManufacturingStatus $status, Part $context): string { + if ($status === null) { return ''; } return $this->translator->trans($status->toTranslationKey()); - } , + }, ]) ->add('manufacturer_product_number', TextColumn::class, [ 'label' => $this->translator->trans('part.table.mpn'), - 'visible' => false, + 'orderField' => 'NATSORT(part.manufacturer_product_number)' ]) ->add('mass', SIUnitNumberColumn::class, [ 'label' => $this->translator->trans('part.table.mass'), - 'visible' => false, 'unit' => 'g' ]) ->add('tags', TagsColumn::class, [ 'label' => $this->translator->trans('part.table.tags'), - 'visible' => false, ]) ->add('attachments', PartAttachmentsColumn::class, [ 'label' => $this->translator->trans('part.table.attachments'), - 'visible' => false, - ]) + ]); + + //Add a column to list the projects where the part is used, when the user has the permission to see the projects + if ($this->security->isGranted('read', Project::class)) { + $this->csh->add('projects', TextColumn::class, [ + 'label' => $this->translator->trans('project.labelp'), + 'render' => function ($value, Part $context): string { + //Only show the first 5 projects names + $projects = $context->getProjects(); + $tmp = ""; + + $max = 5; + + for ($i = 0; $i < min($max, count($projects)); $i++) { + $url = $this->urlGenerator->infoURL($projects[$i]); + $tmp .= sprintf('%s', $url, htmlspecialchars($projects[$i]->getName())); + if ($i < count($projects) - 1) { + $tmp .= ", "; + } + } + + if (count($projects) > $max) { + $tmp .= ", + ".(count($projects) - $max); + } + + return $tmp; + } + ]); + } + + $this->csh ->add('edit', IconLinkColumn::class, [ 'label' => $this->translator->trans('part.table.edit'), - 'visible' => false, 'href' => fn($value, Part $context) => $this->urlGenerator->editURL($context), 'disabled' => fn($value, Part $context) => !$this->security->isGranted('edit', $context), 'title' => $this->translator->trans('part.table.edit.title'), - ]) + ]); - ->addOrderBy('name') - ->createAdapter(TwoStepORMAdapater::class, [ + //Apply the user configured order and visibility and add the columns to the table + $this->csh->applyVisibilityAndConfigureColumns($dataTable, $this->visible_columns, + "TABLE_PARTS_DEFAULT_COLUMNS"); + + $dataTable->addOrderBy('name') + ->createAdapter(TwoStepORMAdapter::class, [ 'filter_query' => $this->getFilterQuery(...), 'detail_query' => $this->getDetailQuery(...), 'entity' => Part::class, - 'hydrate' => Query::HYDRATE_OBJECT, + 'hydrate' => AbstractQuery::HYDRATE_OBJECT, + //Use the simple total query, as we just want to get the total number of parts without any conditions + //For this the normal query would be pretty slow + 'simple_total_query' => true, 'criteria' => [ function (QueryBuilder $builder) use ($options): void { $this->buildCriteria($builder, $options); }, new SearchCriteriaProvider(), ], + 'query_modifier' => $this->addJoins(...), ]); } @@ -292,42 +274,22 @@ final class PartsDataTable implements DataTableTypeInterface /* In the filter query we only select the IDs. The fetching of the full entities is done in the detail query. * We only need to join the entities here, so we can filter by them. * The filter conditions are added to this QB in the buildCriteria method. + * + * The amountSum field and the joins are dynmically added by the addJoins method, if the fields are used in the query. + * This improves the performance, as we do not need to join all tables, if we do not need them. */ $builder ->select('part.id') ->addSelect('part.minamount AS HIDDEN minamount') - //Calculate amount sum using a subquery, so we can filter and sort by it - ->addSelect( - '( - SELECT IFNULL(SUM(partLot.amount), 0.0) - FROM '. PartLot::class. ' partLot - WHERE partLot.part = part.id - AND partLot.instock_unknown = false - AND (partLot.expiration_date IS NULL OR partLot.expiration_date > CURRENT_DATE()) - ) AS HIDDEN amountSum' - ) ->from(Part::class, 'part') - ->leftJoin('part.category', 'category') - ->leftJoin('part.master_picture_attachment', 'master_picture_attachment') - ->leftJoin('part.partLots', 'partLots') - ->leftJoin('partLots.storage_location', 'storelocations') - ->leftJoin('part.footprint', 'footprint') - ->leftJoin('footprint.master_picture_attachment', 'footprint_attachment') - ->leftJoin('part.manufacturer', 'manufacturer') - ->leftJoin('part.orderdetails', 'orderdetails') - ->leftJoin('orderdetails.supplier', 'suppliers') - ->leftJoin('part.attachments', 'attachments') - ->leftJoin('part.partUnit', 'partUnit') - ->leftJoin('part.parameters', 'parameters') - //This must be the only group by, or the paginator will not work correctly - ->addGroupBy('part.id') - ; + //The other group by fields, are dynamically added by the addJoins method + ->addGroupBy('part'); } private function getDetailQuery(QueryBuilder $builder, array $filter_results): void { - $ids = array_map(fn($row) => $row['id'], $filter_results); + $ids = array_map(static fn($row) => $row['id'], $filter_results); /* * In this query we take the IDs which were filtered, paginated and sorted in the filter query, and fetch the @@ -335,6 +297,8 @@ final class PartsDataTable implements DataTableTypeInterface * We can do complex fetch joins, as we do not need to filter or sort here (which would kill the performance). * The only condition should be for the IDs. * It is important that elements are ordered the same way, as the IDs are passed, or ordering will be wrong. + * + * We do not require the subqueries like amountSum here, as it is not used to render the table (and only for sorting) */ $builder ->select('part') @@ -348,16 +312,6 @@ final class PartsDataTable implements DataTableTypeInterface ->addSelect('orderdetails') ->addSelect('attachments') ->addSelect('storelocations') - //Calculate amount sum using a subquery, so we can filter and sort by it - ->addSelect( - '( - SELECT IFNULL(SUM(partLot.amount), 0.0) - FROM '. PartLot::class. ' partLot - WHERE partLot.part = part.id - AND partLot.instock_unknown = false - AND (partLot.expiration_date IS NULL OR partLot.expiration_date > CURRENT_DATE()) - ) AS HIDDEN amountSum' - ) ->from(Part::class, 'part') ->leftJoin('part.category', 'category') ->leftJoin('part.master_picture_attachment', 'master_picture_attachment') @@ -371,7 +325,6 @@ final class PartsDataTable implements DataTableTypeInterface ->leftJoin('part.attachments', 'attachments') ->leftJoin('part.partUnit', 'partUnit') ->leftJoin('part.parameters', 'parameters') - ->where('part.id IN (:ids)') ->setParameter('ids', $ids) @@ -388,13 +341,91 @@ final class PartsDataTable implements DataTableTypeInterface ->addGroupBy('suppliers') ->addGroupBy('attachments') ->addGroupBy('partUnit') - ->addGroupBy('parameters') - ; + ->addGroupBy('parameters'); //Get the results in the same order as the IDs were passed FieldHelper::addOrderByFieldParam($builder, 'part.id', 'ids'); } + /** + * This function is called right before the filter query is executed. + * We use it to dynamically add joins to the query, if the fields are used in the query. + * @param QueryBuilder $builder + * @return QueryBuilder + */ + private function addJoins(QueryBuilder $builder): QueryBuilder + { + //Check if the query contains certain conditions, for which we need to add additional joins + //The join fields get prefixed with an underscore, so we can check if they are used in the query easy without confusing them for a part subfield + $dql = $builder->getDQL(); + + //Add the amountSum field, if it is used in the query + if (str_contains($dql, 'amountSum')) { + //Calculate amount sum using a subquery, so we can filter and sort by it + $builder->addSelect( + '( + SELECT COALESCE(SUM(partLot.amount), 0.0) + FROM '.PartLot::class.' partLot + WHERE partLot.part = part.id + AND partLot.instock_unknown = false + AND (partLot.expiration_date IS NULL OR partLot.expiration_date > CURRENT_DATE()) + ) AS HIDDEN amountSum' + ); + } + + if (str_contains($dql, '_category')) { + $builder->leftJoin('part.category', '_category'); + $builder->addGroupBy('_category'); + } + if (str_contains($dql, '_master_picture_attachment')) { + $builder->leftJoin('part.master_picture_attachment', '_master_picture_attachment'); + $builder->addGroupBy('_master_picture_attachment'); + } + if (str_contains($dql, '_partLots') || str_contains($dql, '_storelocations')) { + $builder->leftJoin('part.partLots', '_partLots'); + $builder->leftJoin('_partLots.storage_location', '_storelocations'); + //Do not group by many-to-* relations, as it would restrict the COUNT having clauses to be maximum 1 + //$builder->addGroupBy('_partLots'); + //$builder->addGroupBy('_storelocations'); + } + if (str_contains($dql, '_footprint')) { + $builder->leftJoin('part.footprint', '_footprint'); + $builder->addGroupBy('_footprint'); + } + if (str_contains($dql, '_manufacturer')) { + $builder->leftJoin('part.manufacturer', '_manufacturer'); + $builder->addGroupBy('_manufacturer'); + } + if (str_contains($dql, '_orderdetails') || str_contains($dql, '_suppliers')) { + $builder->leftJoin('part.orderdetails', '_orderdetails'); + $builder->leftJoin('_orderdetails.supplier', '_suppliers'); + //Do not group by many-to-* relations, as it would restrict the COUNT having clauses to be maximum 1 + //$builder->addGroupBy('_orderdetails'); + //$builder->addGroupBy('_suppliers'); + } + if (str_contains($dql, '_attachments')) { + $builder->leftJoin('part.attachments', '_attachments'); + //Do not group by many-to-* relations, as it would restrict the COUNT having clauses to be maximum 1 + //$builder->addGroupBy('_attachments'); + } + if (str_contains($dql, '_partUnit')) { + $builder->leftJoin('part.partUnit', '_partUnit'); + $builder->addGroupBy('_partUnit'); + } + if (str_contains($dql, '_parameters')) { + $builder->leftJoin('part.parameters', '_parameters'); + //Do not group by many-to-* relations, as it would restrict the COUNT having clauses to be maximum 1 + //$builder->addGroupBy('_parameters'); + } + if (str_contains($dql, '_projectBomEntries')) { + $builder->leftJoin('part.project_bom_entries', '_projectBomEntries'); + //Do not group by many-to-* relations, as it would restrict the COUNT having clauses to be maximum 1 + //$builder->addGroupBy('_projectBomEntries'); + } + + return $builder; + } + private function buildCriteria(QueryBuilder $builder, array $options): void { //Apply the search criterias first @@ -408,6 +439,5 @@ final class PartsDataTable implements DataTableTypeInterface $filter = $options['filter']; $filter->apply($builder); } - } } diff --git a/src/DataTables/ProjectBomEntriesDataTable.php b/src/DataTables/ProjectBomEntriesDataTable.php index 4586d2f7..fcb06984 100644 --- a/src/DataTables/ProjectBomEntriesDataTable.php +++ b/src/DataTables/ProjectBomEntriesDataTable.php @@ -25,7 +25,6 @@ namespace App\DataTables; use App\DataTables\Column\EntityColumn; use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\MarkdownColumn; -use App\DataTables\Column\SelectColumn; use App\DataTables\Helpers\PartDataTableHelper; use App\Entity\Attachments\Attachment; use App\Entity\Parts\Part; @@ -83,24 +82,31 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface ->add('name', TextColumn::class, [ 'label' => $this->translator->trans('part.table.name'), - 'orderField' => 'part.name', + 'orderField' => 'NATSORT(part.name)', 'render' => function ($value, ProjectBOMEntry $context) { if(!$context->getPart() instanceof Part) { - return htmlspecialchars($context->getName()); - } - if($context->getPart() instanceof Part) { - $tmp = $this->partDataTableHelper->renderName($context->getPart()); - if($context->getName() !== null && $context->getName() !== '') { - $tmp .= '
'.htmlspecialchars($context->getName()).''; - } - return $tmp; + return htmlspecialchars((string) $context->getName()); } - //@phpstan-ignore-next-line - throw new \Exception('This should never happen!'); + //Part exists if we reach this point + + $tmp = $this->partDataTableHelper->renderName($context->getPart()); + if($context->getName() !== null && $context->getName() !== '') { + $tmp .= '
'.htmlspecialchars($context->getName()).''; + } + return $tmp; }, ]) - + ->add('ipn', TextColumn::class, [ + 'label' => $this->translator->trans('part.table.ipn'), + 'orderField' => 'NATSORT(part.ipn)', + 'visible' => false, + 'render' => function ($value, ProjectBOMEntry $context) { + if($context->getPart() instanceof Part) { + return $context->getPart()->getIpn(); + } + } + ]) ->add('description', MarkdownColumn::class, [ 'label' => $this->translator->trans('part.table.description'), 'data' => function (ProjectBOMEntry $context) { @@ -116,18 +122,18 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface ->add('category', EntityColumn::class, [ 'label' => $this->translator->trans('part.table.category'), 'property' => 'part.category', - 'orderField' => 'category.name', + 'orderField' => 'NATSORT(category.name)', ]) ->add('footprint', EntityColumn::class, [ 'property' => 'part.footprint', 'label' => $this->translator->trans('part.table.footprint'), - 'orderField' => 'footprint.name', + 'orderField' => 'NATSORT(footprint.name)', ]) ->add('manufacturer', EntityColumn::class, [ 'property' => 'part.manufacturer', 'label' => $this->translator->trans('part.table.manufacturer'), - 'orderField' => 'manufacturer.name', + 'orderField' => 'NATSORT(manufacturer.name)', ]) ->add('mountnames', TextColumn::class, [ @@ -142,6 +148,28 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface }, ]) + ->add('instockAmount', TextColumn::class, [ + 'label' => 'project.bom.instockAmount', + 'visible' => false, + 'render' => function ($value, ProjectBOMEntry $context) { + if ($context->getPart() !== null) { + return $this->partDataTableHelper->renderAmount($context->getPart()); + } + + return ''; + } + ]) + ->add('storageLocations', TextColumn::class, [ + 'label' => 'part.table.storeLocations', + 'visible' => false, + 'render' => function ($value, ProjectBOMEntry $context) { + if ($context->getPart() !== null) { + return $this->partDataTableHelper->renderStorageLocations($context->getPart()); + } + + return ''; + } + ]) ->add('addedDate', LocaleDateTimeColumn::class, [ 'label' => $this->translator->trans('part.table.addedDate'), diff --git a/src/Doctrine/Functions/ArrayPosition.php b/src/Doctrine/Functions/ArrayPosition.php new file mode 100644 index 00000000..39276912 --- /dev/null +++ b/src/Doctrine/Functions/ArrayPosition.php @@ -0,0 +1,59 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Functions; + +use Doctrine\ORM\Query\AST\Functions\FunctionNode; +use Doctrine\ORM\Query\AST\Node; +use Doctrine\ORM\Query\Parser; +use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; + +class ArrayPosition extends FunctionNode +{ + private ?Node $array = null; + + private ?Node $field = null; + + public function parse(Parser $parser): void + { + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); + + $this->array = $parser->InParameter(); + + $parser->match(TokenType::T_COMMA); + + $this->field = $parser->ArithmeticPrimary(); + + $parser->match(TokenType::T_CLOSE_PARENTHESIS); + } + + public function getSql(SqlWalker $sqlWalker): string + { + return 'ARRAY_POSITION(' . + $this->array->dispatch($sqlWalker) . ', ' . + $this->field->dispatch($sqlWalker) . + ')'; + } +} \ No newline at end of file diff --git a/src/Doctrine/Functions/Field2.php b/src/Doctrine/Functions/Field2.php index dc12b294..57f55653 100644 --- a/src/Doctrine/Functions/Field2.php +++ b/src/Doctrine/Functions/Field2.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Doctrine\Functions; +use Doctrine\ORM\Query\Parser; +use Doctrine\ORM\Query\SqlWalker; use Doctrine\ORM\Query\AST\Functions\FunctionNode; -use Doctrine\ORM\Query\Lexer; +use Doctrine\ORM\Query\TokenType; /** * Basically the same as the original Field function, but uses FIELD2 for the SQL query. @@ -36,10 +38,10 @@ class Field2 extends FunctionNode private $values = []; - public function parse(\Doctrine\ORM\Query\Parser $parser) + public function parse(Parser $parser): void { - $parser->match(Lexer::T_IDENTIFIER); - $parser->match(Lexer::T_OPEN_PARENTHESIS); + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); // Do the field. $this->field = $parser->ArithmeticPrimary(); @@ -50,23 +52,24 @@ class Field2 extends FunctionNode $lexer = $parser->getLexer(); while (count($this->values) < 1 || - $lexer->lookahead['type'] != Lexer::T_CLOSE_PARENTHESIS) { - $parser->match(Lexer::T_COMMA); + $lexer->lookahead->type !== TokenType::T_CLOSE_PARENTHESIS) { + $parser->match(TokenType::T_COMMA); $this->values[] = $parser->ArithmeticPrimary(); } - $parser->match(Lexer::T_CLOSE_PARENTHESIS); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); } - public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) + public function getSql(SqlWalker $sqlWalker): string { $query = 'FIELD2('; $query .= $this->field->dispatch($sqlWalker); $query .= ', '; + $counter = count($this->values); - for ($i = 0; $i < count($this->values); $i++) { + for ($i = 0; $i < $counter; $i++) { if ($i > 0) { $query .= ', '; } @@ -74,8 +77,6 @@ class Field2 extends FunctionNode $query .= $this->values[$i]->dispatch($sqlWalker); } - $query .= ')'; - - return $query; + return $query . ')'; } } \ No newline at end of file diff --git a/src/Doctrine/Functions/ILike.php b/src/Doctrine/Functions/ILike.php new file mode 100644 index 00000000..5246220a --- /dev/null +++ b/src/Doctrine/Functions/ILike.php @@ -0,0 +1,71 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Functions; + +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; +use Doctrine\ORM\Query\AST\Functions\FunctionNode; +use Doctrine\ORM\Query\Parser; +use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; + +/** + * A platform invariant version of the case-insensitive LIKE operation. + * On MySQL and SQLite this is the normal LIKE, but on PostgreSQL it is the ILIKE operator. + */ +class ILike extends FunctionNode +{ + + public $value = null; + + public $expr = null; + + public function parse(Parser $parser): void + { + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); + $this->value = $parser->StringPrimary(); + $parser->match(TokenType::T_COMMA); + $this->expr = $parser->StringExpression(); + $parser->match(TokenType::T_CLOSE_PARENTHESIS); + } + + public function getSql(SqlWalker $sqlWalker): string + { + $platform = $sqlWalker->getConnection()->getDatabasePlatform(); + + // + if ($platform instanceof AbstractMySQLPlatform || $platform instanceof SQLitePlatform) { + $operator = 'LIKE'; + } elseif ($platform instanceof PostgreSQLPlatform) { + //Use the case-insensitive operator, to have the same behavior as MySQL + $operator = 'ILIKE'; + } else { + throw new \RuntimeException('Platform ' . gettype($platform) . ' does not support case insensitive like expressions.'); + } + + return '(' . $this->value->dispatch($sqlWalker) . ' ' . $operator . ' ' . $this->expr->dispatch($sqlWalker) . ')'; + } +} \ No newline at end of file diff --git a/src/Doctrine/Functions/Natsort.php b/src/Doctrine/Functions/Natsort.php new file mode 100644 index 00000000..bd05e0d6 --- /dev/null +++ b/src/Doctrine/Functions/Natsort.php @@ -0,0 +1,151 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Functions; + +use Doctrine\DBAL\Exception; +use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Driver\AbstractPostgreSQLDriver; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; +use Doctrine\DBAL\Platforms\MariaDBPlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; +use Doctrine\ORM\Query\AST\Functions\FunctionNode; +use Doctrine\ORM\Query\AST\Node; +use Doctrine\ORM\Query\Parser; +use Doctrine\ORM\Query\SqlWalker; +use Doctrine\ORM\Query\TokenType; + +class Natsort extends FunctionNode +{ + private ?Node $field = null; + + private static ?bool $supportsNaturalSort = null; + + private static bool $allowSlowNaturalSort = false; + + /** + * As we can not inject parameters into the function, we use an event listener, to call the value on the static function. + * This is the only way to inject the value into the function. + * @param bool $allow + * @return void + */ + public static function allowSlowNaturalSort(bool $allow = true): void + { + self::$allowSlowNaturalSort = $allow; + } + + /** + * Check if the slow natural sort is allowed + * @return bool + */ + public static function isSlowNaturalSortAllowed(): bool + { + return self::$allowSlowNaturalSort; + } + + /** + * Check if the MariaDB version which is connected to supports the natural sort (meaning it has a version of 10.7.0 or higher) + * The result is cached in memory. + * @param Connection $connection + * @return bool + * @throws Exception + */ + private function mariaDBSupportsNaturalSort(Connection $connection): bool + { + if (self::$supportsNaturalSort !== null) { + return self::$supportsNaturalSort; + } + + $version = $connection->getServerVersion(); + + //Get the effective MariaDB version number + $version = $this->getMariaDbMysqlVersionNumber($version); + + //We need at least MariaDB 10.7.0 to support the natural sort + self::$supportsNaturalSort = version_compare($version, '10.7.0', '>='); + return self::$supportsNaturalSort; + } + + /** + * Taken from Doctrine\DBAL\Driver\AbstractMySQLDriver + * + * Detect MariaDB server version, including hack for some mariadb distributions + * that starts with the prefix '5.5.5-' + * + * @param string $versionString Version string as returned by mariadb server, i.e. '5.5.5-Mariadb-10.0.8-xenial' + */ + private function getMariaDbMysqlVersionNumber(string $versionString) : string + { + if ( ! preg_match( + '/^(?:5\.5\.5-)?(mariadb-)?(?P\d+)\.(?P\d+)\.(?P\d+)/i', + $versionString, + $versionParts + )) { + throw new \RuntimeException('Could not detect MariaDB version from version string ' . $versionString); + } + + return $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch']; + } + + public function parse(Parser $parser): void + { + $parser->match(TokenType::T_IDENTIFIER); + $parser->match(TokenType::T_OPEN_PARENTHESIS); + + $this->field = $parser->ArithmeticExpression(); + + $parser->match(TokenType::T_CLOSE_PARENTHESIS); + } + + public function getSql(SqlWalker $sqlWalker): string + { + assert($this->field !== null, 'Field is not set'); + + $platform = $sqlWalker->getConnection()->getDatabasePlatform(); + + if ($platform instanceof PostgreSQLPlatform) { + return $this->field->dispatch($sqlWalker) . ' COLLATE numeric'; + } + + if ($platform instanceof MariaDBPlatform && $this->mariaDBSupportsNaturalSort($sqlWalker->getConnection())) { + return 'NATURAL_SORT_KEY(' . $this->field->dispatch($sqlWalker) . ')'; + } + + //Do the following operations only if we allow slow natural sort + if (self::$allowSlowNaturalSort) { + if ($platform instanceof SQLitePlatform) { + return $this->field->dispatch($sqlWalker).' COLLATE NATURAL_CMP'; + } + + if ($platform instanceof AbstractMySQLPlatform) { + return 'NatSortKey(' . $this->field->dispatch($sqlWalker) . ', 0)'; + } + } + + //For every other platform, return the field as is + return $this->field->dispatch($sqlWalker); + } + + +} \ No newline at end of file diff --git a/src/Doctrine/Functions/Regexp.php b/src/Doctrine/Functions/Regexp.php new file mode 100644 index 00000000..d7c6f1e7 --- /dev/null +++ b/src/Doctrine/Functions/Regexp.php @@ -0,0 +1,52 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Functions; + +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; +use Doctrine\ORM\Query\SqlWalker; + +/** + * Similar to the regexp function, but with support for multi platform. + */ +class Regexp extends \DoctrineExtensions\Query\Mysql\Regexp +{ + public function getSql(SqlWalker $sqlWalker): string + { + $platform = $sqlWalker->getConnection()->getDatabasePlatform(); + + // + if ($platform instanceof AbstractMySQLPlatform || $platform instanceof SQLitePlatform) { + $operator = 'REGEXP'; + } elseif ($platform instanceof PostgreSQLPlatform) { + //Use the case-insensitive operator, to have the same behavior as MySQL + $operator = '~*'; + } else { + throw new \RuntimeException('Platform ' . gettype($platform) . ' does not support regular expressions.'); + } + + return '(' . $this->value->dispatch($sqlWalker) . ' ' . $operator . ' ' . $this->regexp->dispatch($sqlWalker) . ')'; + } +} \ No newline at end of file diff --git a/src/Doctrine/Helpers/FieldHelper.php b/src/Doctrine/Helpers/FieldHelper.php index 49dc1475..11300db3 100644 --- a/src/Doctrine/Helpers/FieldHelper.php +++ b/src/Doctrine/Helpers/FieldHelper.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace App\Doctrine\Helpers; use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; use Doctrine\ORM\QueryBuilder; /** @@ -45,10 +46,10 @@ final class FieldHelper $db_platform = $qb->getEntityManager()->getConnection()->getDatabasePlatform(); //If we are on MySQL, we can just use the FIELD function - if ($db_platform instanceof AbstractMySQLPlatform) { - $param = (is_numeric($bound_param) ? '?' : ":") . (string) $bound_param; + if ($db_platform instanceof AbstractMySQLPlatform ) { + $param = (is_numeric($bound_param) ? '?' : ":").(string)$bound_param; $qb->orderBy("FIELD($field_expr, $param)", $order); - } else { + } else { //Use the sqlite/portable version or postgresql //Retrieve the values from the bound parameter $param = $qb->getParameter($bound_param); if ($param === null) { @@ -57,12 +58,31 @@ final class FieldHelper //Generate a unique key from the field_expr $key = 'field2_' . (string) $bound_param; - self::addSqliteOrderBy($qb, $field_expr, $key, $param->getValue(), $order); + + if ($db_platform instanceof PostgreSQLPlatform) { + self::addPostgresOrderBy($qb, $field_expr, $key, $param->getValue(), $order); + } else { + self::addSqliteOrderBy($qb, $field_expr, $key, $param->getValue(), $order); + } } return $qb; } + + private static function addPostgresOrderBy(QueryBuilder $qb, string $field_expr, string $key, array $values, ?string $order = null): void + { + //Use postgres native array_position function, to get the index of the value in the array + //In the end it gives a similar result as the FIELD function + $qb->orderBy("array_position(:$key, $field_expr)", $order); + + //Convert the values to a literal array, to overcome the problem of passing more than 100 parameters + $values = array_map(fn($value) => is_string($value) ? "'$value'" : $value, $values); + $literalArray = '{' . implode(',', $values) . '}'; + + $qb->setParameter($key, $literalArray); + } + private static function addSqliteOrderBy(QueryBuilder $qb, string $field_expr, string $key, array $values, ?string $order = null): void { //Otherwise we emulate it using @@ -88,11 +108,12 @@ final class FieldHelper //If we are on MySQL, we can just use the FIELD function if ($db_platform instanceof AbstractMySQLPlatform) { - $qb->orderBy("FIELD($field_expr, :field_arr)", $order); + $qb->orderBy("FIELD2($field_expr, :field_arr)", $order); + } elseif ($db_platform instanceof PostgreSQLPlatform) { + //Use the postgres native array_position function + self::addPostgresOrderBy($qb, $field_expr, $key, $values, $order); } else { - //Generate a unique key from the field_expr - - //Otherwise we have to it using the FIELD2 function + //Otherwise use the portable version using string concatenation self::addSqliteOrderBy($qb, $field_expr, $key, $values, $order); } diff --git a/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareDriver.php b/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareDriver.php new file mode 100644 index 00000000..2a707e1f --- /dev/null +++ b/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareDriver.php @@ -0,0 +1,51 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Middleware; + +use Composer\CaBundle\CaBundle; +use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware; + +/** + * This middleware sets SSL options for MySQL connections + */ +class MySQLSSLConnectionMiddlewareDriver extends AbstractDriverMiddleware +{ + public function __construct(Driver $wrappedDriver, private readonly bool $enabled, private readonly bool $verify = true) + { + parent::__construct($wrappedDriver); + } + + public function connect(array $params): Connection + { + //Only set this on MySQL connections, as other databases don't support this parameter + if($this->enabled && $params['driver'] === 'pdo_mysql') { + $params['driverOptions'][\PDO::MYSQL_ATTR_SSL_CA] = CaBundle::getSystemCaRootBundlePath(); + $params['driverOptions'][\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $this->verify; + } + + return parent::connect($params); + } +} \ No newline at end of file diff --git a/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareWrapper.php b/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareWrapper.php new file mode 100644 index 00000000..8bd25971 --- /dev/null +++ b/src/Doctrine/Middleware/MySQLSSLConnectionMiddlewareWrapper.php @@ -0,0 +1,39 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Middleware; + +use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Driver\Middleware; + +class MySQLSSLConnectionMiddlewareWrapper implements Middleware +{ + public function __construct(private readonly bool $enabled, private readonly bool $verify = true) + { + } + + public function wrap(Driver $driver): Driver + { + return new MySQLSSLConnectionMiddlewareDriver($driver, $this->enabled, $this->verify); + } +} \ No newline at end of file diff --git a/src/Doctrine/SQLiteRegexExtension.php b/src/Doctrine/Middleware/SQLiteRegexExtensionMiddlewareDriver.php similarity index 74% rename from src/Doctrine/SQLiteRegexExtension.php rename to src/Doctrine/Middleware/SQLiteRegexExtensionMiddlewareDriver.php index 2407880d..ad572d4c 100644 --- a/src/Doctrine/SQLiteRegexExtension.php +++ b/src/Doctrine/Middleware/SQLiteRegexExtensionMiddlewareDriver.php @@ -1,11 +1,8 @@ . */ -namespace App\Doctrine; + +declare(strict_types=1); + + +namespace App\Doctrine\Middleware; use App\Exceptions\InvalidRegexException; -use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener; -use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface; -use Doctrine\DBAL\Event\ConnectionEventArgs; -use Doctrine\DBAL\Events; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware; /** - * This subscriber is used to add the regexp operator to the SQLite platform. + * This middleware is used to add the regexp operator to the SQLite platform. * As a PHP callback is called for every entry to compare it is most likely much slower than using regex on MySQL. * But as regex is not often used, this should be fine for most use cases, also it is almost impossible to implement a better solution. */ -#[AsDoctrineListener(Events::postConnect)] -class SQLiteRegexExtension +class SQLiteRegexExtensionMiddlewareDriver extends AbstractDriverMiddleware { - public function postConnect(ConnectionEventArgs $eventArgs): void + public function connect(#[\SensitiveParameter] array $params): Connection { - $connection = $eventArgs->getConnection(); + //Do connect process first + $connection = parent::connect($params); // TODO: Change the autogenerated stub - //We only execute this on SQLite databases - if ($connection->getDatabasePlatform() instanceof SqlitePlatform) { + //Then add the functions if we are on SQLite + if ($params['driver'] === 'pdo_sqlite') { $native_connection = $connection->getNativeConnection(); //Ensure that the function really exists on the connection, as it is marked as experimental according to PHP documentation - if($native_connection instanceof \PDO && method_exists($native_connection, 'sqliteCreateFunction' )) { + if($native_connection instanceof \PDO) { $native_connection->sqliteCreateFunction('REGEXP', self::regexp(...), 2, \PDO::SQLITE_DETERMINISTIC); $native_connection->sqliteCreateFunction('FIELD', self::field(...), -1, \PDO::SQLITE_DETERMINISTIC); $native_connection->sqliteCreateFunction('FIELD2', self::field2(...), 2, \PDO::SQLITE_DETERMINISTIC); + + //Create a new collation for natural sorting + $native_connection->sqliteCreateCollation('NATURAL_CMP', strnatcmp(...)); } } + + + return $connection; } /** @@ -60,8 +64,12 @@ class SQLiteRegexExtension * @param string $value * @return int */ - final public static function regexp(string $pattern, string $value): int + final public static function regexp(string $pattern, ?string $value): int { + if ($value === null) { + return 0; + } + try { return (mb_ereg($pattern, $value)) ? 1 : 0; @@ -88,10 +96,9 @@ class SQLiteRegexExtension * This function returns the index (position) of the first argument in the subsequent arguments. * If the first argument is not found or is NULL, 0 is returned. * @param string|int|null $value - * @param mixed ...$array * @return int */ - final public static function field(string|int|null $value, ...$array): int + final public static function field(string|int|null $value, mixed ...$array): int { if ($value === null) { return 0; @@ -107,4 +114,4 @@ class SQLiteRegexExtension return $index + 1; } -} +} \ No newline at end of file diff --git a/src/Doctrine/Middleware/SQLiteRegexExtensionMiddlewareWrapper.php b/src/Doctrine/Middleware/SQLiteRegexExtensionMiddlewareWrapper.php new file mode 100644 index 00000000..42aafaad --- /dev/null +++ b/src/Doctrine/Middleware/SQLiteRegexExtensionMiddlewareWrapper.php @@ -0,0 +1,35 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Middleware; + +use Doctrine\DBAL\Driver; +use Doctrine\DBAL\Driver\Middleware; + +class SQLiteRegexExtensionMiddlewareWrapper implements Middleware +{ + public function wrap(Driver $driver): Driver + { + return new SQLiteRegexExtensionMiddlewareDriver($driver); + } +} \ No newline at end of file diff --git a/src/Doctrine/SetSQLMode/SetSQLModeMiddlewareDriver.php b/src/Doctrine/Middleware/SetSQLModeMiddlewareDriver.php similarity index 84% rename from src/Doctrine/SetSQLMode/SetSQLModeMiddlewareDriver.php rename to src/Doctrine/Middleware/SetSQLModeMiddlewareDriver.php index 5501b231..d05b6b9c 100644 --- a/src/Doctrine/SetSQLMode/SetSQLModeMiddlewareDriver.php +++ b/src/Doctrine/Middleware/SetSQLModeMiddlewareDriver.php @@ -20,11 +20,10 @@ declare(strict_types=1); * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -namespace App\Doctrine\SetSQLMode; +namespace App\Doctrine\Middleware; use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware; -use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; /** * This command sets the initial command parameter for MySQL connections, so we can set the SQL mode @@ -35,9 +34,9 @@ class SetSQLModeMiddlewareDriver extends AbstractDriverMiddleware public function connect(array $params): Connection { //Only set this on MySQL connections, as other databases don't support this parameter - if($this->getDatabasePlatform() instanceof AbstractMySQLPlatform) { + if($params['driver'] === 'pdo_mysql') { //1002 is \PDO::MYSQL_ATTR_INIT_COMMAND constant value - $params['driverOptions'][1002] = 'SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode, \'ONLY_FULL_GROUP_BY\', \'\'))'; + $params['driverOptions'][\PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode, \'ONLY_FULL_GROUP_BY\', \'\'))'; } return parent::connect($params); diff --git a/src/Doctrine/SetSQLMode/SetSQLModeMiddlewareWrapper.php b/src/Doctrine/Middleware/SetSQLModeMiddlewareWrapper.php similarity index 97% rename from src/Doctrine/SetSQLMode/SetSQLModeMiddlewareWrapper.php rename to src/Doctrine/Middleware/SetSQLModeMiddlewareWrapper.php index 34320fa5..3307bc7f 100644 --- a/src/Doctrine/SetSQLMode/SetSQLModeMiddlewareWrapper.php +++ b/src/Doctrine/Middleware/SetSQLModeMiddlewareWrapper.php @@ -20,7 +20,7 @@ declare(strict_types=1); * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -namespace App\Doctrine\SetSQLMode; +namespace App\Doctrine\Middleware; use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver\Middleware; @@ -30,7 +30,6 @@ use Doctrine\DBAL\Driver\Middleware; */ class SetSQLModeMiddlewareWrapper implements Middleware { - public function wrap(Driver $driver): Driver { return new SetSQLModeMiddlewareDriver($driver); diff --git a/src/Doctrine/Purger/DoNotUsePurgerFactory.php b/src/Doctrine/Purger/DoNotUsePurgerFactory.php new file mode 100644 index 00000000..6d487573 --- /dev/null +++ b/src/Doctrine/Purger/DoNotUsePurgerFactory.php @@ -0,0 +1,53 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Doctrine\Purger; + +use Doctrine\Bundle\FixturesBundle\Purger\PurgerFactory; +use Doctrine\Common\DataFixtures\Purger\ORMPurgerInterface; +use Doctrine\Common\DataFixtures\Purger\PurgerInterface; +use Doctrine\ORM\EntityManagerInterface; + +class DoNotUsePurgerFactory implements PurgerFactory +{ + + public function createForEntityManager( + ?string $emName, + EntityManagerInterface $em, + array $excluded = [], + bool $purgeWithTruncate = false + ): PurgerInterface { + return new class() implements ORMPurgerInterface { + + public function purge(): void + { + throw new \LogicException('Do not use doctrine:fixtures:load directly. Use partdb:fixtures:load instead!'); + } + + public function setEntityManager(EntityManagerInterface $em): void + { + // TODO: Implement setEntityManager() method. + } + }; + } +} \ No newline at end of file diff --git a/src/Doctrine/Purger/ResetAutoIncrementORMPurger.php b/src/Doctrine/Purger/ResetAutoIncrementORMPurger.php index 755fd553..0fbf6cdb 100644 --- a/src/Doctrine/Purger/ResetAutoIncrementORMPurger.php +++ b/src/Doctrine/Purger/ResetAutoIncrementORMPurger.php @@ -27,13 +27,10 @@ use Doctrine\Common\DataFixtures\Purger\PurgerInterface; use Doctrine\Common\DataFixtures\Sorter\TopologicalSorter; use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Schema\Identifier; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Mapping\ClassMetadataInfo; - use function array_reverse; use function assert; use function count; @@ -190,7 +187,6 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface //Reseting autoincrement is only supported on MySQL platforms if ($platform instanceof AbstractMySQLPlatform ) { //|| $platform instanceof SqlitePlatform) { - $connection->beginTransaction(); $connection->executeQuery($this->getResetAutoIncrementSQL($tbl, $platform)); } } @@ -209,6 +205,8 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface return 'ALTER TABLE '.$tableIdentifier->getQuotedName($platform).' AUTO_INCREMENT = 1;'; } + throw new \RuntimeException("Resetting autoincrement is not supported on this platform!"); + //This seems to cause problems somehow /*if ($platform instanceof SqlitePlatform) { return 'DELETE FROM `sqlite_sequence` WHERE name = \''.$tableIdentifier->getQuotedName($platform).'\';'; @@ -280,7 +278,7 @@ class ResetAutoIncrementORMPurger implements PurgerInterface, ORMPurgerInterface foreach ($classes as $class) { foreach ($class->associationMappings as $assoc) { - if (! $assoc['isOwningSide'] || $assoc['type'] !== ClassMetadataInfo::MANY_TO_MANY) { + if (! $assoc['isOwningSide'] || $assoc['type'] !== ClassMetadata::MANY_TO_MANY) { continue; } diff --git a/src/Doctrine/Types/ArrayType.php b/src/Doctrine/Types/ArrayType.php new file mode 100644 index 00000000..daab9b75 --- /dev/null +++ b/src/Doctrine/Types/ArrayType.php @@ -0,0 +1,116 @@ +. + */ + +declare(strict_types=1); + +namespace App\Doctrine\Types; + +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Types\Exception\SerializationFailed; +use Doctrine\DBAL\Types\Type; +use Doctrine\Deprecations\Deprecation; + +use function is_resource; +use function restore_error_handler; +use function serialize; +use function set_error_handler; +use function stream_get_contents; +use function unserialize; + +use const E_DEPRECATED; +use const E_USER_DEPRECATED; + +/** + * This class is taken from doctrine ORM 3.8. https://github.com/doctrine/dbal/blob/3.8.x/src/Types/ArrayType.php + * + * It was removed in doctrine ORM 4.0. However, we require it for backward compatibility with WebauthnKey. + * Therefore, we manually added it here as a custom type as a forward compatibility layer. + */ +class ArrayType extends Type +{ + /** + * {@inheritDoc} + */ + public function getSQLDeclaration(array $column, AbstractPlatform $platform): string + { + return $platform->getClobTypeDeclarationSQL($column); + } + + /** + * {@inheritDoc} + */ + public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): string + { + return serialize($value); + } + + /** + * {@inheritDoc} + */ + public function convertToPHPValue(mixed $value, AbstractPlatform $platform): mixed + { + if ($value === null) { + return null; + } + + $value = is_resource($value) ? stream_get_contents($value) : $value; + + set_error_handler(function (int $code, string $message): bool { + if ($code === E_DEPRECATED || $code === E_USER_DEPRECATED) { + return false; + } + + //Change to original code. Use SerializationFailed instead of ConversionException. + throw new SerializationFailed("Serialization failed (Code $code): " . $message); + }); + + try { + //Change to original code. Use false for allowed_classes, to avoid unsafe unserialization of objects. + return unserialize($value, ['allowed_classes' => false]); + } finally { + restore_error_handler(); + } + } + + /** + * {@inheritDoc} + */ + public function getName(): string + { + return "array"; + } + + /** + * {@inheritDoc} + * + * @deprecated + */ + public function requiresSQLCommentHint(AbstractPlatform $platform): bool + { + Deprecation::triggerIfCalledFromOutside( + 'doctrine/dbal', + 'https://github.com/doctrine/dbal/pull/5509', + '%s is deprecated.', + __METHOD__, + ); + + return true; + } +} \ No newline at end of file diff --git a/src/Doctrine/Types/TinyIntType.php b/src/Doctrine/Types/TinyIntType.php index 9b2fc7a9..c2daeeca 100644 --- a/src/Doctrine/Types/TinyIntType.php +++ b/src/Doctrine/Types/TinyIntType.php @@ -22,7 +22,9 @@ declare(strict_types=1); */ namespace App\Doctrine\Types; +use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\DBAL\Types\Type; /** @@ -33,7 +35,15 @@ class TinyIntType extends Type public function getSQLDeclaration(array $column, AbstractPlatform $platform): string { - return 'TINYINT'; + //MySQL knows the TINYINT type directly + //We do not use the TINYINT for sqlite, as it will be resolved to a BOOL type and bring problems with migrations + if ($platform instanceof AbstractMySQLPlatform ) { + //Use TINYINT(1) to allow for proper migration diffs + return 'TINYINT(1)'; + } + + //For other platforms, we use the smallest integer type available + return $platform->getSmallIntTypeDeclarationSQL($column); } public function getName(): string @@ -41,6 +51,20 @@ class TinyIntType extends Type return 'tinyint'; } + /** + * {@inheritDoc} + * + * @param T $value + * + * @return (T is null ? null : int) + * + * @template T + */ + public function convertToPHPValue($value, AbstractPlatform $platform): ?int + { + return $value === null ? null : (int) $value; + } + public function requiresSQLCommentHint(AbstractPlatform $platform): bool { //We use the comment, so that doctrine migrations can properly detect, that nothing has changed and no migration is needed. diff --git a/src/Doctrine/Types/UTCDateTimeImmutableType.php b/src/Doctrine/Types/UTCDateTimeImmutableType.php new file mode 100644 index 00000000..c0d6659d --- /dev/null +++ b/src/Doctrine/Types/UTCDateTimeImmutableType.php @@ -0,0 +1,97 @@ +. + */ + +declare(strict_types=1); + +namespace App\Doctrine\Types; + +use DateTime; +use DateTimeInterface; +use DateTimeZone; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Types\ConversionException; +use Doctrine\DBAL\Types\DateTimeImmutableType; +use Doctrine\DBAL\Types\DateTimeType; +use Doctrine\DBAL\Types\Exception\InvalidFormat; + +/** + * This DateTimeImmutableType all dates to UTC, so it can be later used with the timezones. + * Taken (and adapted) from here: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/cookbook/working-with-datetime.html. + */ +class UTCDateTimeImmutableType extends DateTimeImmutableType +{ + private static ?DateTimeZone $utc_timezone = null; + + /** + * {@inheritdoc} + * + * @param T $value + * + * @return (T is null ? null : string) + * + * @template T + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string + { + if (!self::$utc_timezone instanceof \DateTimeZone) { + self::$utc_timezone = new DateTimeZone('UTC'); + } + + if ($value instanceof \DateTimeImmutable) { + $value = $value->setTimezone(self::$utc_timezone); + } + + return parent::convertToDatabaseValue($value, $platform); + } + + /** + * {@inheritDoc} + * + * @param T $value + * + * @template T + */ + public function convertToPHPValue($value, AbstractPlatform $platform): ?\DateTimeImmutable + { + if (!self::$utc_timezone instanceof \DateTimeZone) { + self::$utc_timezone = new DateTimeZone('UTC'); + } + + if (null === $value || $value instanceof \DateTimeImmutable) { + return $value; + } + + $converted = \DateTimeImmutable::createFromFormat( + $platform->getDateTimeFormatString(), + $value, + self::$utc_timezone + ); + + if (!$converted) { + throw InvalidFormat::new( + $value, + static::class, + $platform->getDateTimeFormatString(), + ); + } + + return $converted; + } +} diff --git a/src/Doctrine/Types/UTCDateTimeType.php b/src/Doctrine/Types/UTCDateTimeType.php index c7140252..a6fda747 100644 --- a/src/Doctrine/Types/UTCDateTimeType.php +++ b/src/Doctrine/Types/UTCDateTimeType.php @@ -28,6 +28,7 @@ use DateTimeZone; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\DateTimeType; +use Doctrine\DBAL\Types\Exception\InvalidFormat; /** * This DateTimeType all dates to UTC, so it can be later used with the timezones. @@ -64,11 +65,9 @@ class UTCDateTimeType extends DateTimeType * * @param T $value * - * @return (T is null ? null : DateTimeInterface) - * * @template T */ - public function convertToPHPValue($value, AbstractPlatform $platform): ?\DateTimeInterface + public function convertToPHPValue($value, AbstractPlatform $platform): ?DateTime { if (!self::$utc_timezone instanceof \DateTimeZone) { self::$utc_timezone = new DateTimeZone('UTC'); @@ -85,7 +84,11 @@ class UTCDateTimeType extends DateTimeType ); if (!$converted) { - throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateTimeFormatString()); + throw InvalidFormat::new( + $value, + static::class, + $platform->getDateTimeFormatString(), + ); } return $converted; diff --git a/src/Entity/Attachments/Attachment.php b/src/Entity/Attachments/Attachment.php index f27b0e70..00cf581a 100644 --- a/src/Entity/Attachments/Attachment.php +++ b/src/Entity/Attachments/Attachment.php @@ -22,17 +22,35 @@ declare(strict_types=1); namespace App\Entity\Attachments; -use App\Repository\AttachmentRepository; -use App\EntityListeners\AttachmentDeleteListener; -use Doctrine\DBAL\Types\Types; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use App\ApiPlatform\DocumentedAPIProperties\DocumentedAPIProperty; +use App\ApiPlatform\Filter\EntityFilter; +use App\ApiPlatform\Filter\LikeFilter; +use App\ApiPlatform\HandleAttachmentsUploadsProcessor; use App\Entity\Base\AbstractNamedDBElement; +use App\EntityListeners\AttachmentDeleteListener; +use App\Repository\AttachmentRepository; use App\Validator\Constraints\Selectable; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; -use Symfony\Component\Serializer\Annotation\Groups; -use Symfony\Component\Validator\Constraints as Assert; -use function in_array; use InvalidArgumentException; use LogicException; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Annotation\SerializedName; +use Symfony\Component\Serializer\Attribute\DiscriminatorMap; +use Symfony\Component\Validator\Constraints as Assert; + +use function in_array; /** * Class Attachment. @@ -42,15 +60,58 @@ use LogicException; #[ORM\Entity(repositoryClass: AttachmentRepository::class)] #[ORM\InheritanceType('SINGLE_TABLE')] #[ORM\DiscriminatorColumn(name: 'class_name', type: 'string')] -#[ORM\DiscriminatorMap(['PartDB\Part' => 'PartAttachment', 'Part' => 'PartAttachment', 'PartDB\Device' => 'ProjectAttachment', 'Device' => 'ProjectAttachment', 'AttachmentType' => 'AttachmentTypeAttachment', 'Category' => 'CategoryAttachment', 'Footprint' => 'FootprintAttachment', 'Manufacturer' => 'ManufacturerAttachment', 'Currency' => 'CurrencyAttachment', 'Group' => 'GroupAttachment', 'MeasurementUnit' => 'MeasurementUnitAttachment', 'Storelocation' => 'StorelocationAttachment', 'Supplier' => 'SupplierAttachment', 'User' => 'UserAttachment', 'LabelProfile' => 'LabelAttachment'])] +#[ORM\DiscriminatorMap(self::ORM_DISCRIMINATOR_MAP)] #[ORM\EntityListeners([AttachmentDeleteListener::class])] #[ORM\Table(name: '`attachments`')] -#[ORM\Index(name: 'attachments_idx_id_element_id_class_name', columns: ['id', 'element_id', 'class_name'])] -#[ORM\Index(name: 'attachments_idx_class_name_id', columns: ['class_name', 'id'])] -#[ORM\Index(name: 'attachment_name_idx', columns: ['name'])] -#[ORM\Index(name: 'attachment_element_idx', columns: ['class_name', 'element_id'])] +#[ORM\Index(columns: ['id', 'element_id', 'class_name'], name: 'attachments_idx_id_element_id_class_name')] +#[ORM\Index(columns: ['class_name', 'id'], name: 'attachments_idx_class_name_id')] +#[ORM\Index(columns: ['name'], name: 'attachment_name_idx')] +#[ORM\Index(columns: ['class_name', 'element_id'], name: 'attachment_element_idx')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@attachments.list_attachments")'), + new Post(securityPostDenormalize: 'is_granted("create", object)', ), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['attachment:read', 'attachment:read:standalone', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['attachment:write', 'attachment:write:standalone', 'api:basic:write'], 'openapi_definition_name' => 'Write'], + processor: HandleAttachmentsUploadsProcessor::class, +)] +//This property is added by the denormalizer in order to resolve the placeholder +#[DocumentedAPIProperty( + schemaName: 'Attachment-Read', property: 'internal_path', type: 'string', nullable: false, + description: 'The URL to the internally saved copy of the file, if one exists', + example: '/media/part/2/bc547-6508afa5a79c8.pdf' +)] +#[DocumentedAPIProperty( + schemaName: 'Attachment-Read', property: 'thumbnail_url', type: 'string', nullable: true, + description: 'The URL to a thumbnail version of this file. This only exists for internal picture attachments.' +)] +#[ApiFilter(LikeFilter::class, properties: ["name"])] +#[ApiFilter(EntityFilter::class, properties: ["attachment_type"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] +//This discriminator map is required for API platform to know which class to use for deserialization, when creating a new attachment. +#[DiscriminatorMap(typeProperty: '_type', mapping: self::API_DISCRIMINATOR_MAP)] abstract class Attachment extends AbstractNamedDBElement { + private const ORM_DISCRIMINATOR_MAP = ['Part' => PartAttachment::class, 'Device' => ProjectAttachment::class, + 'AttachmentType' => AttachmentTypeAttachment::class, + 'Category' => CategoryAttachment::class, 'Footprint' => FootprintAttachment::class, 'Manufacturer' => ManufacturerAttachment::class, + 'Currency' => CurrencyAttachment::class, 'Group' => GroupAttachment::class, 'MeasurementUnit' => MeasurementUnitAttachment::class, + 'Storelocation' => StorageLocationAttachment::class, 'Supplier' => SupplierAttachment::class, + 'User' => UserAttachment::class, 'LabelProfile' => LabelAttachment::class]; + + /* + * The discriminator map used for API platform. The key should be the same as the api platform short type (the @type JSONLD field). + */ + private const API_DISCRIMINATOR_MAP = ["Part" => PartAttachment::class, "Project" => ProjectAttachment::class, "AttachmentType" => AttachmentTypeAttachment::class, + "Category" => CategoryAttachment::class, "Footprint" => FootprintAttachment::class, "Manufacturer" => ManufacturerAttachment::class, + "Currency" => CurrencyAttachment::class, "Group" => GroupAttachment::class, "MeasurementUnit" => MeasurementUnitAttachment::class, + "StorageLocation" => StorageLocationAttachment::class, "Supplier" => SupplierAttachment::class, "User" => UserAttachment::class, "LabelProfile" => LabelAttachment::class]; + /** * A list of file extensions, that browsers can show directly as image. * Based on: https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types @@ -64,10 +125,6 @@ abstract class Attachment extends AbstractNamedDBElement */ final public const MODEL_EXTS = ['x3d']; - /** - * When the path begins with one of the placeholders. - */ - final public const INTERNAL_PLACEHOLDER = ['%BASE%', '%MEDIA%', '%SECURE%']; /** * @var array placeholders for attachments which using built in files @@ -80,41 +137,72 @@ abstract class Attachment extends AbstractNamedDBElement */ protected const ALLOWED_ELEMENT_CLASS = AttachmentContainingDBElement::class; + /** + * @var AttachmentUpload|null The options used for uploading a file to this attachment or modify it. + * This value is not persisted in the database, but is just used to pass options to the upload manager. + * If it is null, no upload process is started. + */ + #[Groups(['attachment:write'])] + protected ?AttachmentUpload $upload = null; + /** * @var string|null the original filename the file had, when the user uploaded it */ #[ORM\Column(type: Types::STRING, nullable: true)] + #[Groups(['attachment:read', 'import'])] + #[Assert\Length(max: 255)] protected ?string $original_filename = null; /** - * @var string The path to the file relative to a placeholder path like %MEDIA% + * @var string|null If a copy of the file is stored internally, the path to the file relative to a placeholder + * path like %MEDIA% */ - #[ORM\Column(type: Types::STRING, name: 'path')] - protected string $path = ''; + #[ORM\Column(type: Types::STRING, nullable: true)] + protected ?string $internal_path = null; + + + /** + * @var string|null The path to the external source if the file is stored externally or was downloaded from an + * external source. Null if there is no external source. + */ + #[ORM\Column(type: Types::STRING, nullable: true)] + #[Groups(['attachment:read'])] + #[ApiProperty(example: 'http://example.com/image.jpg')] + protected ?string $external_path = null; /** * @var string the name of this element */ #[Assert\NotBlank(message: 'validator.attachment.name_not_blank')] - #[Groups(['simple', 'extended', 'full'])] - #[ORM\Column(type: Types::STRING)] + #[Groups(['simple', 'extended', 'full', 'attachment:read', 'attachment:write', 'import'])] protected string $name = ''; /** * ORM mapping is done in subclasses (like PartAttachment). * @phpstan-param T|null $element */ + #[Groups(['attachment:read:standalone', 'attachment:write:standalone'])] + #[ApiProperty(writableLink: false)] protected ?AttachmentContainingDBElement $element = null; #[ORM\Column(type: Types::BOOLEAN)] + #[Groups(['attachment:read', 'attachment_write', 'full', 'import'])] protected bool $show_in_table = false; #[Assert\NotNull(message: 'validator.attachment.must_not_be_null')] #[ORM\ManyToOne(targetEntity: AttachmentType::class, inversedBy: 'attachments_with_type')] #[ORM\JoinColumn(name: 'type_id', nullable: false)] - #[Selectable()] + #[Selectable] + #[Groups(['attachment:read', 'attachment:write', 'import', 'full'])] + #[ApiProperty(readableLink: false)] protected ?AttachmentType $attachment_type = null; + #[Groups(['attachment:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['attachment:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + public function __construct() { //parent::__construct(); @@ -131,69 +219,106 @@ abstract class Attachment extends AbstractNamedDBElement } } + /** + * Gets the upload currently associated with this attachment. + * This is only temporary and not persisted directly in the database. + * @internal This function should only be used by the Attachment Submit handler service + * @return AttachmentUpload|null + */ + public function getUpload(): ?AttachmentUpload + { + return $this->upload; + } + + /** + * Sets the current upload for this attachment. + * It will be processed as the attachment is persisted/flushed. + * @param AttachmentUpload|null $upload + * @return $this + */ + public function setUpload(?AttachmentUpload $upload): Attachment + { + $this->upload = $upload; + return $this; + } + + + /*********************************************************** * Various function ***********************************************************/ /** * Check if this attachment is a picture (analyse the file's extension). - * If the link is external, it is assumed that this is true. + * If the link is only external and doesn't contain an extension, it is assumed that this is true. * * @return bool * true if the file extension is a picture extension * * otherwise false */ + #[Groups(['attachment:read'])] public function isPicture(): bool { - if ($this->isExternal()) { + if($this->hasInternal()){ + + $extension = pathinfo($this->getInternalPath(), PATHINFO_EXTENSION); + + return in_array(strtolower($extension), static::PICTURE_EXTS, true); + + } + if ($this->hasExternal()) { //Check if we can extract a file extension from the URL - $extension = pathinfo(parse_url($this->path, PHP_URL_PATH) ?? '', PATHINFO_EXTENSION); + $extension = pathinfo(parse_url($this->getExternalPath(), PHP_URL_PATH) ?? '', PATHINFO_EXTENSION); //If no extension is found or it is known picture extension, we assume that this is a picture extension - if ($extension === '' || in_array(strtolower($extension), static::PICTURE_EXTS, true)) { - return true; - } - - //Otherwise we assume that the file is not a picture - return false; + return $extension === '' || in_array(strtolower($extension), static::PICTURE_EXTS, true); } - - $extension = pathinfo($this->getPath(), PATHINFO_EXTENSION); - - return in_array(strtolower($extension), static::PICTURE_EXTS, true); + //File doesn't have an internal, nor an external copy. This shouldn't happen, but it certainly isn't a picture... + return false; } /** * Check if this attachment is a 3D model and therefore can be directly shown to user. - * If the attachment is external, false is returned (3D Models must be internal). + * If no internal copy exists, false is returned (3D Models must be internal). */ + #[Groups(['attachment:read'])] + #[SerializedName('3d_model')] public function is3DModel(): bool { //We just assume that 3D Models are internally saved, otherwise we get problems loading them. - if ($this->isExternal()) { + if (!$this->hasInternal()) { return false; } - $extension = pathinfo($this->getPath(), PATHINFO_EXTENSION); + $extension = pathinfo($this->getInternalPath(), PATHINFO_EXTENSION); return in_array(strtolower($extension), static::MODEL_EXTS, true); } /** - * Checks if the attachment file is externally saved (the database saves an URL). + * Checks if this attachment has a path to an external file * - * @return bool true, if the file is saved externally + * @return bool true, if there is a path to an external file + * @phpstan-assert-if-true non-empty-string $this->external_path + * @phpstan-assert-if-true non-empty-string $this->getExternalPath()) */ - public function isExternal(): bool + #[Groups(['attachment:read'])] + public function hasExternal(): bool { - //When path is empty, this attachment can not be external - if ($this->path === '') { - return false; - } + return $this->external_path !== null && $this->external_path !== ''; + } - //After the %PLACEHOLDER% comes a slash, so we can check if we have a placeholder via explode - $tmp = explode('/', $this->path); - - return !in_array($tmp[0], array_merge(static::INTERNAL_PLACEHOLDER, static::BUILTIN_PLACEHOLDER), true); + /** + * Checks if this attachment has a path to an internal file. + * Does not check if the file exists. + * + * @return bool true, if there is a path to an internal file + * @phpstan-assert-if-true non-empty-string $this->internal_path + * @phpstan-assert-if-true non-empty-string $this->getInternalPath()) + */ + #[Groups(['attachment:read'])] + public function hasInternal(): bool + { + return $this->internal_path !== null && $this->internal_path !== ''; } /** @@ -202,10 +327,16 @@ abstract class Attachment extends AbstractNamedDBElement * * @return bool true, if the file is secure */ + #[Groups(['attachment:read'])] + #[SerializedName('private')] public function isSecure(): bool { + if ($this->internal_path === null) { + return false; + } + //After the %PLACEHOLDER% comes a slash, so we can check if we have a placeholder via explode - $tmp = explode('/', $this->path); + $tmp = explode('/', $this->internal_path); return '%SECURE%' === $tmp[0]; } @@ -216,9 +347,14 @@ abstract class Attachment extends AbstractNamedDBElement * * @return bool true if the attachment is using a builtin file */ + #[Groups(['attachment:read'])] public function isBuiltIn(): bool { - return static::checkIfBuiltin($this->path); + if ($this->internal_path === null) { + return false; + } + + return static::checkIfBuiltin($this->internal_path); } /******************************************************************************** @@ -230,13 +366,13 @@ abstract class Attachment extends AbstractNamedDBElement /** * Returns the extension of the file referenced via the attachment. * For a path like %BASE/path/foo.bar, bar will be returned. - * If this attachment is external null is returned. + * If this attachment is only external null is returned. * * @return string|null the file extension in lower case */ public function getExtension(): ?string { - if ($this->isExternal()) { + if (!$this->hasInternal()) { return null; } @@ -244,7 +380,7 @@ abstract class Attachment extends AbstractNamedDBElement return strtolower(pathinfo($this->original_filename, PATHINFO_EXTENSION)); } - return strtolower(pathinfo($this->getPath(), PATHINFO_EXTENSION)); + return strtolower(pathinfo($this->getInternalPath(), PATHINFO_EXTENSION)); } /** @@ -259,50 +395,54 @@ abstract class Attachment extends AbstractNamedDBElement } /** - * The URL to the external file, or the path to the built-in file. + * The URL to the external file, or the path to the built-in file, but not paths to uploaded files. * Returns null, if the file is not external (and not builtin). + * The output of this function is such, that no changes occur when it is fed back into setURL(). + * Required for the Attachment form field. */ public function getURL(): ?string { - if (!$this->isExternal() && !$this->isBuiltIn()) { - return null; + if($this->hasExternal()){ + return $this->getExternalPath(); } - - return $this->path; + if($this->isBuiltIn()){ + return $this->getInternalPath(); + } + return null; } /** * Returns the hostname where the external file is stored. - * Returns null, if the file is not external. + * Returns null, if there is no external path. */ public function getHost(): ?string { - if (!$this->isExternal()) { + if (!$this->hasExternal()) { return null; } - return parse_url($this->getURL(), PHP_URL_HOST); + return parse_url($this->getExternalPath(), PHP_URL_HOST); } - /** - * Get the filepath, relative to %BASE%. - * - * @return string A string like %BASE/path/foo.bar - */ - public function getPath(): string + public function getInternalPath(): ?string { - return $this->path; + return $this->internal_path; + } + + public function getExternalPath(): ?string + { + return $this->external_path; } /** * Returns the filename of the attachment. * For a path like %BASE/path/foo.bar, foo.bar will be returned. * - * If the path is a URL (can be checked via isExternal()), null will be returned. + * If there is no internal copy of the file, null will be returned. */ public function getFilename(): ?string { - if ($this->isExternal()) { + if (!$this->hasInternal()) { return null; } @@ -311,7 +451,7 @@ abstract class Attachment extends AbstractNamedDBElement return $this->original_filename; } - return pathinfo($this->getPath(), PATHINFO_BASENAME); + return pathinfo($this->getInternalPath(), PATHINFO_BASENAME); } /** @@ -373,7 +513,8 @@ abstract class Attachment extends AbstractNamedDBElement */ public function setElement(AttachmentContainingDBElement $element): self { - if (!is_a($element, static::ALLOWED_ELEMENT_CLASS)) { + //Do not allow Rector to replace this check with a instanceof. It will not work!! + if (!is_a($element, static::ALLOWED_ELEMENT_CLASS, true)) { throw new InvalidArgumentException(sprintf('The element associated with a %s must be a %s!', static::class, static::ALLOWED_ELEMENT_CLASS)); } @@ -383,15 +524,12 @@ abstract class Attachment extends AbstractNamedDBElement } /** - * Sets the filepath (with relative placeholder) for this attachment. - * - * @param string $path the new filepath of the attachment - * - * @return Attachment + * Sets the path to a file hosted internally. If you set this path to a file that was not downloaded from the + * external source in external_path, make sure to reset external_path. */ - public function setPath(string $path): self + public function setInternalPath(?string $internal_path): self { - $this->path = $path; + $this->internal_path = $internal_path; return $this; } @@ -407,24 +545,61 @@ abstract class Attachment extends AbstractNamedDBElement } /** - * Sets the url associated with this attachment. - * If the url is empty nothing is changed, to not override the file path. - * - * @return Attachment + * Sets up the paths using a user provided string which might contain an external path or a builtin path. Allows + * resetting the external path if an internal path exists. Resets any other paths if a (nonempty) new path is set. */ + #[Groups(['attachment:write'])] + #[SerializedName('url')] + #[ApiProperty(description: 'Set the path of the attachment here. + Provide either an external URL, a path to a builtin file (like %FOOTPRINTS%/Active/ICs/IC_DFS.png) or an empty + string if the attachment has an internal file associated and you\'d like to reset the external source. + If you set a new (nonempty) file path any associated internal file will be removed!')] public function setURL(?string $url): self { - //Only set if the URL is not empty - if ($url !== null && $url !== '') { - if (str_contains($url, '%BASE%') || str_contains($url, '%MEDIA%')) { - throw new InvalidArgumentException('You can not reference internal files via the url field! But nice try!'); - } - - $this->path = $url; - //Reset internal filename - $this->original_filename = null; + //Don't allow the user to set an empty external path if the internal path is empty already + if (($url === null || $url === "") && !$this->hasInternal()) { + return $this; } + //The URL field can also contain the special builtin internal paths, so we need to distinguish here + if ($this::checkIfBuiltin($url)) { + $this->setInternalPath($url); + //make sure the external path isn't still pointing to something unrelated + $this->setExternalPath(null); + } else { + $this->setExternalPath($url); + } + return $this; + } + + + /** + * Sets the path to a file hosted on an external server. Setting the external path to a (nonempty) value different + * from the the old one _clears_ the internal path, so that the external path reflects where any associated internal + * file came from. + */ + public function setExternalPath(?string $external_path): self + { + //If we only clear the external path, don't reset the internal path, since that could be confusing + if($external_path === null || $external_path === '') { + $this->external_path = null; + return $this; + } + + $external_path = trim($external_path); + //Escape spaces in URL + $external_path = str_replace(' ', '%20', $external_path); + + if($this->external_path === $external_path) { + //Nothing changed, nothing to do + return $this; + } + + $this->external_path = $external_path; + $this->internal_path = null; + //Reset internal filename + $this->original_filename = null; + return $this; } @@ -435,12 +610,17 @@ abstract class Attachment extends AbstractNamedDBElement /** * Checks if the given path is a path to a builtin resource. * - * @param string $path The path that should be checked + * @param string|null $path The path that should be checked * * @return bool true if the path is pointing to a builtin resource */ - public static function checkIfBuiltin(string $path): bool + public static function checkIfBuiltin(?string $path): bool { + //An empty path can't be a builtin + if ($path === null) { + return false; + } + //After the %PLACEHOLDER% comes a slash, so we can check if we have a placeholder via explode $tmp = explode('/', $path); //Builtins must have a %PLACEHOLDER% construction diff --git a/src/Entity/Attachments/AttachmentContainingDBElement.php b/src/Entity/Attachments/AttachmentContainingDBElement.php index f2dfd3ef..a78cb1f4 100644 --- a/src/Entity/Attachments/AttachmentContainingDBElement.php +++ b/src/Entity/Attachments/AttachmentContainingDBElement.php @@ -33,7 +33,7 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; /** - * @template-covariant AT of Attachment + * @template AT of Attachment */ #[ORM\MappedSuperclass(repositoryClass: AttachmentContainingDBElementRepository::class)] abstract class AttachmentContainingDBElement extends AbstractNamedDBElement implements HasMasterAttachmentInterface, HasAttachmentsInterface @@ -45,7 +45,7 @@ abstract class AttachmentContainingDBElement extends AbstractNamedDBElement impl * @phpstan-var Collection * ORM Mapping is done in subclasses (e.g. Part) */ - #[Groups(['full'])] + #[Groups(['full', 'import'])] protected Collection $attachments; public function __construct() diff --git a/src/Entity/Attachments/AttachmentType.php b/src/Entity/Attachments/AttachmentType.php index dc8de0a0..22333c16 100644 --- a/src/Entity/Attachments/AttachmentType.php +++ b/src/Entity/Attachments/AttachmentType.php @@ -22,6 +22,22 @@ declare(strict_types=1); namespace App\Entity\Attachments; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Repository\StructuralDBElementRepository; use Doctrine\DBAL\Types\Types; use App\Entity\Base\AbstractStructuralDBElement; @@ -30,6 +46,7 @@ use App\Validator\Constraints\ValidFileFilter; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; /** @@ -39,47 +56,90 @@ use Symfony\Component\Validator\Constraints as Assert; */ #[ORM\Entity(repositoryClass: StructuralDBElementRepository::class)] #[ORM\Table(name: '`attachment_types`')] -#[ORM\Index(name: 'attachment_types_idx_name', columns: ['name'])] -#[ORM\Index(name: 'attachment_types_idx_parent_name', columns: ['parent_id', 'name'])] +#[ORM\Index(columns: ['name'], name: 'attachment_types_idx_name')] +#[ORM\Index(columns: ['parent_id', 'name'], name: 'attachment_types_idx_parent_name')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@attachment_types.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['attachment_type:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['attachment_type:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/attachment_types/{id}/children.{_format}', + operations: [ + new GetCollection(openapi: new Operation(summary: 'Retrieves the children elements of an attachment type.'), + security: 'is_granted("@attachment_types.read")') + ], + uriVariables: [ + 'id' => new Link(fromProperty: 'children', fromClass: AttachmentType::class) + ], + normalizationContext: ['groups' => ['attachment_type:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] class AttachmentType extends AbstractStructuralDBElement { - #[ORM\OneToMany(targetEntity: AttachmentType::class, mappedBy: 'parent', cascade: ['persist'])] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: AttachmentType::class, cascade: ['persist'])] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; #[ORM\ManyToOne(targetEntity: AttachmentType::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id')] + #[Groups(['attachment_type:read', 'attachment_type:write'])] + #[ApiProperty(readableLink: true, writableLink: false)] protected ?AbstractStructuralDBElement $parent = null; + /** + * @var string A comma separated list of file types, which are allowed for attachment files. + * Must be in the format of
accept attribute + * (See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#Unique_file_type_specifiers). + */ #[ORM\Column(type: Types::TEXT)] #[ValidFileFilter] + #[Groups(['attachment_type:read', 'attachment_type:write', 'import', 'extended'])] protected string $filetype_filter = ''; /** * @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: AttachmentTypeAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: AttachmentTypeAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] + #[Groups(['attachment_type:read', 'attachment_type:write', 'import', 'full'])] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: AttachmentTypeAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['attachment_type:read', 'attachment_type:write', 'full'])] protected ?Attachment $master_picture_attachment = null; /** @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: AttachmentTypeParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: AttachmentTypeParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] + #[Groups(['attachment_type:read', 'attachment_type:write', 'import', 'full'])] protected Collection $parameters; /** * @var Collection */ - #[ORM\OneToMany(targetEntity: Attachment::class, mappedBy: 'attachment_type')] + #[ORM\OneToMany(mappedBy: 'attachment_type', targetEntity: Attachment::class)] protected Collection $attachments_with_type; + #[Groups(['attachment_type:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['attachment_type:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + public function __construct() { $this->children = new ArrayCollection(); diff --git a/src/Entity/Attachments/AttachmentTypeAttachment.php b/src/Entity/Attachments/AttachmentTypeAttachment.php index 31398595..1e677ff0 100644 --- a/src/Entity/Attachments/AttachmentTypeAttachment.php +++ b/src/Entity/Attachments/AttachmentTypeAttachment.php @@ -22,8 +22,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * A attachment attached to an attachmentType element. @@ -39,5 +41,6 @@ class AttachmentTypeAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: AttachmentType::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/AttachmentUpload.php b/src/Entity/Attachments/AttachmentUpload.php new file mode 100644 index 00000000..f2b042b7 --- /dev/null +++ b/src/Entity/Attachments/AttachmentUpload.php @@ -0,0 +1,77 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\Attachments; + +use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\Serializer\Attribute\Groups; + +/** + * This is a DTO representing a file upload for an attachment and which is used to pass data to the Attachment + * submit handler service. + */ +class AttachmentUpload +{ + public function __construct( + /** @var UploadedFile|null The file which was uploaded, or null if the file should not be changed */ + public readonly ?UploadedFile $file, + /** @var string|null The base64 encoded data of the file which should be uploaded. */ + #[Groups(['attachment:write'])] + public readonly ?string $data = null, + /** @vaar string|null The original filename of the file passed in data. */ + #[Groups(['attachment:write'])] + public readonly ?string $filename = null, + /** @var bool True, if the URL in the attachment should be downloaded by Part-DB */ + #[Groups(['attachment:write'])] + public readonly bool $downloadUrl = false, + /** @var bool If true the file will be moved to private attachment storage, + * if false it will be moved to public attachment storage. On null file is not moved + */ + #[Groups(['attachment:write'])] + public readonly ?bool $private = null, + /** @var bool If true and no preview image was set yet, the new uploaded file will become the preview image */ + #[Groups(['attachment:write'])] + public readonly ?bool $becomePreviewIfEmpty = true, + ) { + } + + /** + * Creates an AttachmentUpload object from an Attachment FormInterface + * @param FormInterface $form + * @return AttachmentUpload + */ + public static function fromAttachmentForm(FormInterface $form): AttachmentUpload + { + if (!$form->has('file')) { + throw new \InvalidArgumentException('The form does not have a file field. Is it an attachment form?'); + } + + return new self( + file: $form->get('file')->getData(), + downloadUrl: $form->get('downloadURL')->getData(), + private: $form->get('secureFile')->getData() + ); + + } +} \ No newline at end of file diff --git a/src/Entity/Attachments/CategoryAttachment.php b/src/Entity/Attachments/CategoryAttachment.php index 63b4178d..3bea265e 100644 --- a/src/Entity/Attachments/CategoryAttachment.php +++ b/src/Entity/Attachments/CategoryAttachment.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\Parts\Category; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * An attachment attached to a category element. @@ -40,5 +42,6 @@ class CategoryAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: Category::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/CurrencyAttachment.php b/src/Entity/Attachments/CurrencyAttachment.php index 292da013..a5d6e061 100644 --- a/src/Entity/Attachments/CurrencyAttachment.php +++ b/src/Entity/Attachments/CurrencyAttachment.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\PriceInformations\Currency; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * An attachment attached to a currency element. @@ -41,5 +43,6 @@ class CurrencyAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: Currency::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/FootprintAttachment.php b/src/Entity/Attachments/FootprintAttachment.php index 4d9b7caa..4a9b866c 100644 --- a/src/Entity/Attachments/FootprintAttachment.php +++ b/src/Entity/Attachments/FootprintAttachment.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\Parts\Footprint; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * An attachment attached to a footprint element. @@ -41,5 +43,6 @@ class FootprintAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: Footprint::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/GroupAttachment.php b/src/Entity/Attachments/GroupAttachment.php index 269e5b7d..e9bf947f 100644 --- a/src/Entity/Attachments/GroupAttachment.php +++ b/src/Entity/Attachments/GroupAttachment.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\UserSystem\Group; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * An attachment attached to a Group element. @@ -41,5 +43,6 @@ class GroupAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: Group::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/LabelAttachment.php b/src/Entity/Attachments/LabelAttachment.php index 5bf18969..b8891ced 100644 --- a/src/Entity/Attachments/LabelAttachment.php +++ b/src/Entity/Attachments/LabelAttachment.php @@ -42,8 +42,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\LabelSystem\LabelProfile; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * A attachment attached to a user element. @@ -60,5 +62,6 @@ class LabelAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: LabelProfile::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/ManufacturerAttachment.php b/src/Entity/Attachments/ManufacturerAttachment.php index cdbd7807..1b8891e5 100644 --- a/src/Entity/Attachments/ManufacturerAttachment.php +++ b/src/Entity/Attachments/ManufacturerAttachment.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\Parts\Manufacturer; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * An attachment attached to a manufacturer element. @@ -41,5 +43,6 @@ class ManufacturerAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: Manufacturer::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/MeasurementUnitAttachment.php b/src/Entity/Attachments/MeasurementUnitAttachment.php index 58467f86..dbc8829e 100644 --- a/src/Entity/Attachments/MeasurementUnitAttachment.php +++ b/src/Entity/Attachments/MeasurementUnitAttachment.php @@ -22,10 +22,11 @@ declare(strict_types=1); namespace App\Entity\Attachments; -use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * An attachment attached to a measurement unit element. @@ -36,10 +37,10 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; class MeasurementUnitAttachment extends Attachment { final public const ALLOWED_ELEMENT_CLASS = MeasurementUnit::class; - /** - * @var Manufacturer|null the element this attachment is associated with - */ + + #[ORM\ManyToOne(targetEntity: MeasurementUnit::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/PartAttachment.php b/src/Entity/Attachments/PartAttachment.php index f9ca43b3..0873b3c5 100644 --- a/src/Entity/Attachments/PartAttachment.php +++ b/src/Entity/Attachments/PartAttachment.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\Parts\Part; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * A attachment attached to a part element. @@ -40,5 +42,6 @@ class PartAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/ProjectAttachment.php b/src/Entity/Attachments/ProjectAttachment.php index 84b0ac4c..f3e96292 100644 --- a/src/Entity/Attachments/ProjectAttachment.php +++ b/src/Entity/Attachments/ProjectAttachment.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\ProjectSystem\Project; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * A attachment attached to a device element. @@ -40,5 +42,6 @@ class ProjectAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: Project::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/StorelocationAttachment.php b/src/Entity/Attachments/StorageLocationAttachment.php similarity index 68% rename from src/Entity/Attachments/StorelocationAttachment.php rename to src/Entity/Attachments/StorageLocationAttachment.php index 7772269d..3cd82d0c 100644 --- a/src/Entity/Attachments/StorelocationAttachment.php +++ b/src/Entity/Attachments/StorageLocationAttachment.php @@ -22,24 +22,27 @@ declare(strict_types=1); namespace App\Entity\Attachments; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * An attachment attached to a measurement unit element. - * @extends Attachment + * @extends Attachment */ #[UniqueEntity(['name', 'attachment_type', 'element'])] #[ORM\Entity] -class StorelocationAttachment extends Attachment +class StorageLocationAttachment extends Attachment { - final public const ALLOWED_ELEMENT_CLASS = Storelocation::class; + final public const ALLOWED_ELEMENT_CLASS = StorageLocation::class; /** - * @var Storelocation|null the element this attachment is associated with + * @var StorageLocation|null the element this attachment is associated with */ - #[ORM\ManyToOne(targetEntity: Storelocation::class, inversedBy: 'attachments')] + #[ORM\ManyToOne(targetEntity: StorageLocation::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/SupplierAttachment.php b/src/Entity/Attachments/SupplierAttachment.php index 7afa8282..c3adc438 100644 --- a/src/Entity/Attachments/SupplierAttachment.php +++ b/src/Entity/Attachments/SupplierAttachment.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\Parts\Supplier; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * A attachment attached to a supplier element. @@ -41,5 +43,6 @@ class SupplierAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: Supplier::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Attachments/UserAttachment.php b/src/Entity/Attachments/UserAttachment.php index fef36eb5..b031d419 100644 --- a/src/Entity/Attachments/UserAttachment.php +++ b/src/Entity/Attachments/UserAttachment.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace App\Entity\Attachments; use App\Entity\UserSystem\User; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * An attachment attached to a user element. @@ -41,5 +43,6 @@ class UserAttachment extends Attachment */ #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'attachments')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AttachmentContainingDBElement $element = null; } diff --git a/src/Entity/Base/AbstractCompany.php b/src/Entity/Base/AbstractCompany.php index ca6d1b88..947d1339 100644 --- a/src/Entity/Base/AbstractCompany.php +++ b/src/Entity/Base/AbstractCompany.php @@ -33,54 +33,69 @@ use Symfony\Component\Validator\Constraints as Assert; /** * This abstract class is used for companies like suppliers or manufacturers. * - * @template-covariant AT of Attachment - * @template-covariant PT of AbstractParameter + * @template AT of Attachment + * @template PT of AbstractParameter * @extends AbstractPartsContainingDBElement */ #[ORM\MappedSuperclass] abstract class AbstractCompany extends AbstractPartsContainingDBElement { + #[Groups(['company:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['company:read'])] + protected ?\DateTimeImmutable $lastModified = null; + /** * @var string The address of the company */ - #[Groups(['full'])] + #[Groups(['full', 'company:read', 'company:write', 'import', 'extended'])] #[ORM\Column(type: Types::STRING)] + #[Assert\Length(max: 255)] protected string $address = ''; /** * @var string The phone number of the company */ - #[Groups(['full'])] + #[Groups(['full', 'company:read', 'company:write', 'import', 'extended'])] #[ORM\Column(type: Types::STRING)] + #[Assert\Length(max: 255)] protected string $phone_number = ''; /** * @var string The fax number of the company */ - #[Groups(['full'])] + #[Groups(['full', 'company:read', 'company:write', 'import', 'extended'])] #[ORM\Column(type: Types::STRING)] + #[Assert\Length(max: 255)] protected string $fax_number = ''; /** * @var string The email address of the company */ #[Assert\Email] - #[Groups(['full'])] + #[Groups(['full', 'company:read', 'company:write', 'import', 'extended'])] #[ORM\Column(type: Types::STRING)] + #[Assert\Length(max: 255)] protected string $email_address = ''; /** * @var string The website of the company */ #[Assert\Url] - #[Groups(['full'])] + #[Groups(['full', 'company:read', 'company:write', 'import', 'extended'])] #[ORM\Column(type: Types::STRING)] + #[Assert\Length(max: 255)] protected string $website = ''; + #[Groups(['company:read', 'company:write', 'import', 'full', 'extended'])] + protected string $comment = ''; + /** - * @var string + * @var string The link to the website of an article. Use %PARTNUMBER% as placeholder for the part number. */ #[ORM\Column(type: Types::STRING)] + #[Assert\Length(max: 255)] + #[Groups(['full', 'company:read', 'company:write', 'import', 'extended'])] protected string $auto_product_url = ''; /******************************************************************************** @@ -147,7 +162,7 @@ abstract class AbstractCompany extends AbstractPartsContainingDBElement * * @return string the link to the article */ - public function getAutoProductUrl(string $partnr = null): string + public function getAutoProductUrl(?string $partnr = null): string { if (is_string($partnr)) { return str_replace('%PARTNUMBER%', $partnr, $this->auto_product_url); diff --git a/src/Entity/Base/AbstractDBElement.php b/src/Entity/Base/AbstractDBElement.php index 30fcab06..871a22d0 100644 --- a/src/Entity/Base/AbstractDBElement.php +++ b/src/Entity/Base/AbstractDBElement.php @@ -34,9 +34,10 @@ use App\Entity\Attachments\ManufacturerAttachment; use App\Entity\Attachments\MeasurementUnitAttachment; use App\Entity\Attachments\PartAttachment; use App\Entity\Attachments\ProjectAttachment; -use App\Entity\Attachments\StorelocationAttachment; +use App\Entity\Attachments\StorageLocationAttachment; use App\Entity\Attachments\SupplierAttachment; use App\Entity\Attachments\UserAttachment; +use App\Entity\Parameters\AbstractParameter; use App\Entity\Parts\Category; use App\Entity\ProjectSystem\Project; use App\Entity\ProjectSystem\ProjectBOMEntry; @@ -45,7 +46,7 @@ use App\Entity\UserSystem\Group; use App\Entity\Parts\Manufacturer; use App\Entity\PriceInformations\Orderdetail; use App\Entity\Parts\Part; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\PartLot; use App\Entity\PriceInformations\Currency; use App\Entity\Parts\MeasurementUnit; @@ -66,14 +67,14 @@ use Symfony\Component\Serializer\Annotation\Groups; * Every database table which are managed with this class (or a subclass of it) * must have the table row "id"!! The ID is the unique key to identify the elements. */ -#[DiscriminatorMap(typeProperty: 'type', mapping: ['attachment_type' => AttachmentType::class, 'attachment' => Attachment::class, 'attachment_type_attachment' => AttachmentTypeAttachment::class, 'category_attachment' => CategoryAttachment::class, 'currency_attachment' => CurrencyAttachment::class, 'footprint_attachment' => FootprintAttachment::class, 'group_attachment' => GroupAttachment::class, 'label_attachment' => LabelAttachment::class, 'manufacturer_attachment' => ManufacturerAttachment::class, 'measurement_unit_attachment' => MeasurementUnitAttachment::class, 'part_attachment' => PartAttachment::class, 'project_attachment' => ProjectAttachment::class, 'storelocation_attachment' => StorelocationAttachment::class, 'supplier_attachment' => SupplierAttachment::class, 'user_attachment' => UserAttachment::class, 'category' => Category::class, 'project' => Project::class, 'project_bom_entry' => ProjectBOMEntry::class, 'footprint' => Footprint::class, 'group' => Group::class, 'manufacturer' => Manufacturer::class, 'orderdetail' => Orderdetail::class, 'part' => Part::class, 'pricedetail' => 'App\Entity\PriceInformation\Pricedetail', 'storelocation' => Storelocation::class, 'part_lot' => PartLot::class, 'currency' => Currency::class, 'measurement_unit' => MeasurementUnit::class, 'parameter' => 'App\Entity\Parts\AbstractParameter', 'supplier' => Supplier::class, 'user' => User::class])] +#[DiscriminatorMap(typeProperty: 'type', mapping: ['attachment_type' => AttachmentType::class, 'attachment' => Attachment::class, 'attachment_type_attachment' => AttachmentTypeAttachment::class, 'category_attachment' => CategoryAttachment::class, 'currency_attachment' => CurrencyAttachment::class, 'footprint_attachment' => FootprintAttachment::class, 'group_attachment' => GroupAttachment::class, 'label_attachment' => LabelAttachment::class, 'manufacturer_attachment' => ManufacturerAttachment::class, 'measurement_unit_attachment' => MeasurementUnitAttachment::class, 'part_attachment' => PartAttachment::class, 'project_attachment' => ProjectAttachment::class, 'storelocation_attachment' => StorageLocationAttachment::class, 'supplier_attachment' => SupplierAttachment::class, 'user_attachment' => UserAttachment::class, 'category' => Category::class, 'project' => Project::class, 'project_bom_entry' => ProjectBOMEntry::class, 'footprint' => Footprint::class, 'group' => Group::class, 'manufacturer' => Manufacturer::class, 'orderdetail' => Orderdetail::class, 'part' => Part::class, 'pricedetail' => 'App\Entity\PriceInformation\Pricedetail', 'storelocation' => StorageLocation::class, 'part_lot' => PartLot::class, 'currency' => Currency::class, 'measurement_unit' => MeasurementUnit::class, 'parameter' => AbstractParameter::class, 'supplier' => Supplier::class, 'user' => User::class])] #[ORM\MappedSuperclass(repositoryClass: DBElementRepository::class)] abstract class AbstractDBElement implements JsonSerializable { /** @var int|null The Identification number for this part. This value is unique for the element in this table. * Null if the element is not saved to DB yet. */ - #[Groups(['full'])] + #[Groups(['full', 'api:basic:read'])] #[ORM\Column(type: Types::INTEGER)] #[ORM\Id] #[ORM\GeneratedValue] diff --git a/src/Entity/Base/AbstractNamedDBElement.php b/src/Entity/Base/AbstractNamedDBElement.php index e5e30441..f7939589 100644 --- a/src/Entity/Base/AbstractNamedDBElement.php +++ b/src/Entity/Base/AbstractNamedDBElement.php @@ -40,11 +40,12 @@ abstract class AbstractNamedDBElement extends AbstractDBElement implements Named use TimestampTrait; /** - * @var string the name of this element + * @var string The name of this element */ #[Assert\NotBlank] - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'api:basic:read', 'api:basic:write'])] #[ORM\Column(type: Types::STRING)] + #[Assert\Length(max: 255)] protected string $name = ''; /****************************************************************************** diff --git a/src/Entity/Base/AbstractPartsContainingDBElement.php b/src/Entity/Base/AbstractPartsContainingDBElement.php index 5d25283e..70d88fa9 100644 --- a/src/Entity/Base/AbstractPartsContainingDBElement.php +++ b/src/Entity/Base/AbstractPartsContainingDBElement.php @@ -23,9 +23,7 @@ declare(strict_types=1); namespace App\Entity\Base; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentContainingDBElement; use App\Entity\Parameters\AbstractParameter; -use App\Entity\Parameters\ParametersTrait; use App\Repository\AbstractPartsContainingRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; @@ -33,14 +31,14 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; /** - * @template-covariant AT of Attachment - * @template-covariant PT of AbstractParameter + * @template AT of Attachment + * @template PT of AbstractParameter * @extends AbstractStructuralDBElement */ #[ORM\MappedSuperclass(repositoryClass: AbstractPartsContainingRepository::class)] abstract class AbstractPartsContainingDBElement extends AbstractStructuralDBElement { - #[Groups(['full'])] + #[Groups(['full', 'import'])] protected Collection $parameters; public function __construct() diff --git a/src/Entity/Base/AbstractStructuralDBElement.php b/src/Entity/Base/AbstractStructuralDBElement.php index 5c4103d8..660710db 100644 --- a/src/Entity/Base/AbstractStructuralDBElement.php +++ b/src/Entity/Base/AbstractStructuralDBElement.php @@ -26,18 +26,17 @@ use App\Entity\Attachments\Attachment; use App\Entity\Parameters\AbstractParameter; use App\Repository\StructuralDBElementRepository; use App\EntityListeners\TreeCacheInvalidationListener; -use Doctrine\Common\Proxy\Proxy; +use App\Validator\Constraints\UniqueObjectCollection; use Doctrine\DBAL\Types\Types; use App\Entity\Attachments\AttachmentContainingDBElement; use App\Entity\Parameters\ParametersTrait; use App\Validator\Constraints\NoneOfItsChildren; +use Symfony\Component\Serializer\Annotation\SerializedName; use Symfony\Component\Validator\Constraints as Assert; -use Symfony\Component\Validator\Constraints\Valid; use function count; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -use function get_class; use InvalidArgumentException; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; @@ -54,13 +53,13 @@ use Symfony\Component\Serializer\Annotation\Groups; * * @see \App\Tests\Entity\Base\AbstractStructuralDBElementTest * - * @template-covariant AT of Attachment - * @template-covariant PT of AbstractParameter + * @template AT of Attachment + * @template PT of AbstractParameter * @template-use ParametersTrait * @extends AttachmentContainingDBElement * @uses ParametersTrait */ -#[UniqueEntity(fields: ['name', 'parent'], ignoreNull: false, message: 'structural.entity.unique_name')] +#[UniqueEntity(fields: ['name', 'parent'], message: 'structural.entity.unique_name', ignoreNull: false)] #[ORM\MappedSuperclass(repositoryClass: StructuralDBElementRepository::class)] #[ORM\EntityListeners([TreeCacheInvalidationListener::class])] abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement @@ -73,7 +72,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement final public const PATH_DELIMITER_ARROW = ' → '; /** - * @var string The comment info for this element + * @var string The comment info for this element as markdown */ #[Groups(['full', 'import'])] #[ORM\Column(type: Types::TEXT)] @@ -116,7 +115,8 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement * @var Collection * @phpstan-var Collection */ - #[Assert\Valid()] + #[Assert\Valid] + #[UniqueObjectCollection(fields: ['name', 'group', 'element'])] protected Collection $parameters; /** @var string[] all names of all parent elements as an array of strings, @@ -174,7 +174,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement throw new InvalidArgumentException('isChildOf() only works for objects of the same type!'); } - if (!$this->getParent() instanceof \App\Entity\Base\AbstractStructuralDBElement) { // this is the root node + if (!$this->getParent() instanceof self) { // this is the root node return false; } @@ -219,7 +219,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement } /** - * Get the comment of the element. + * Get the comment of the element as markdown encoded string. * * @return string the comment @@ -242,9 +242,9 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement /* * Only check for nodes that have a parent. In the other cases zero is correct. */ - if (0 === $this->level && $this->parent instanceof \App\Entity\Base\AbstractStructuralDBElement) { + if (0 === $this->level && $this->parent instanceof self) { $element = $this->parent; - while ($element instanceof \App\Entity\Base\AbstractStructuralDBElement) { + while ($element instanceof self) { /** @var AbstractStructuralDBElement $element */ $element = $element->parent; ++$this->level; @@ -261,6 +261,8 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement * * @return string the full path (incl. the name of this element), delimited by $delimiter */ + #[Groups(['api:basic:read'])] + #[SerializedName('full_path')] public function getFullPath(string $delimiter = self::PATH_DELIMITER_ARROW): string { if ($this->full_path_strings === []) { @@ -270,7 +272,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement $overflow = 20; //We only allow 20 levels depth - while ($element->parent instanceof \App\Entity\Base\AbstractStructuralDBElement && $overflow >= 0) { + while ($element->parent instanceof self && $overflow >= 0) { $element = $element->parent; $this->full_path_strings[] = $element->getName(); //Decrement to prevent mem overflow. @@ -316,6 +318,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement return new ArrayCollection(); } + //@phpstan-ignore-next-line return $this->children ?? new ArrayCollection(); } @@ -356,7 +359,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement $this->parent = $new_parent; //Add this element as child to the new parent - if ($new_parent instanceof \App\Entity\Base\AbstractStructuralDBElement) { + if ($new_parent instanceof self) { $new_parent->getChildren()->add($this); } @@ -441,7 +444,7 @@ abstract class AbstractStructuralDBElement extends AttachmentContainingDBElement public function setAlternativeNames(?string $new_value): self { //Add a trailing comma, if not already there (makes it easier to find in the database) - if (is_string($new_value) && substr($new_value, -1) !== ',') { + if (is_string($new_value) && !str_ends_with($new_value, ',')) { $new_value .= ','; } diff --git a/src/Entity/Base/MasterAttachmentTrait.php b/src/Entity/Base/MasterAttachmentTrait.php index aec15633..723bab07 100644 --- a/src/Entity/Base/MasterAttachmentTrait.php +++ b/src/Entity/Base/MasterAttachmentTrait.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace App\Entity\Base; use App\Entity\Attachments\Attachment; -use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; /** diff --git a/src/Entity/Base/PartsContainingRepositoryInterface.php b/src/Entity/Base/PartsContainingRepositoryInterface.php index f852bc35..89e7e5f6 100644 --- a/src/Entity/Base/PartsContainingRepositoryInterface.php +++ b/src/Entity/Base/PartsContainingRepositoryInterface.php @@ -30,11 +30,11 @@ interface PartsContainingRepositoryInterface * Returns all parts associated with this element. * * @param object $element the element for which the parts should be determined - * @param array $order_by The order of the parts. Format ['name' => 'ASC'] + * @param string $nameOrderDirection the direction in which the parts should be ordered by name, either ASC or DESC * * @return Part[] */ - public function getParts(object $element, array $order_by = ['name' => 'ASC']): array; + public function getParts(object $element, string $nameOrderDirection = "ASC"): array; /** * Gets the count of the parts associated with this element. diff --git a/src/Entity/Base/TimestampTrait.php b/src/Entity/Base/TimestampTrait.php index 93e58cb7..77506b18 100644 --- a/src/Entity/Base/TimestampTrait.php +++ b/src/Entity/Base/TimestampTrait.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace App\Entity\Base; +use ApiPlatform\Metadata\ApiProperty; use Doctrine\DBAL\Types\Types; use DateTime; use Doctrine\ORM\Mapping as ORM; @@ -33,26 +34,28 @@ use Symfony\Component\Serializer\Annotation\Groups; trait TimestampTrait { /** - * @var \DateTimeInterface|null the date when this element was modified the last time + * @var \DateTimeImmutable|null the date when this element was modified the last time */ #[Groups(['extended', 'full'])] - #[ORM\Column(name: 'last_modified', type: Types::DATETIME_MUTABLE, options: ['default' => 'CURRENT_TIMESTAMP'])] - protected ?\DateTimeInterface $lastModified = null; + #[ApiProperty(writable: false)] + #[ORM\Column(name: 'last_modified', type: Types::DATETIME_IMMUTABLE, options: ['default' => 'CURRENT_TIMESTAMP'])] + protected ?\DateTimeImmutable $lastModified = null; /** - * @var \DateTimeInterface|null the date when this element was created + * @var \DateTimeImmutable|null the date when this element was created */ #[Groups(['extended', 'full'])] - #[ORM\Column(name: 'datetime_added', type: Types::DATETIME_MUTABLE, options: ['default' => 'CURRENT_TIMESTAMP'])] - protected ?\DateTimeInterface $addedDate = null; + #[ApiProperty(writable: false)] + #[ORM\Column(name: 'datetime_added', type: Types::DATETIME_IMMUTABLE, options: ['default' => 'CURRENT_TIMESTAMP'])] + protected ?\DateTimeImmutable $addedDate = null; /** * Returns the last time when the element was modified. * Returns null if the element was not yet saved to DB yet. * - * @return \DateTimeInterface|null the time of the last edit + * @return \DateTimeImmutable|null the time of the last edit */ - public function getLastModified(): ?\DateTimeInterface + public function getLastModified(): ?\DateTimeImmutable { return $this->lastModified; } @@ -61,9 +64,9 @@ trait TimestampTrait * Returns the date/time when the element was created. * Returns null if the element was not yet saved to DB yet. * - * @return \DateTimeInterface|null the creation time of the part + * @return \DateTimeImmutable|null the creation time of the part */ - public function getAddedDate(): ?\DateTimeInterface + public function getAddedDate(): ?\DateTimeImmutable { return $this->addedDate; } @@ -75,9 +78,9 @@ trait TimestampTrait #[ORM\PreUpdate] public function updateTimestamps(): void { - $this->lastModified = new DateTime('now'); + $this->lastModified = new \DateTimeImmutable('now'); if (null === $this->addedDate) { - $this->addedDate = new DateTime('now'); + $this->addedDate = new \DateTimeImmutable('now'); } } } diff --git a/src/Entity/Contracts/TimeStampableInterface.php b/src/Entity/Contracts/TimeStampableInterface.php index 6393d629..c99c0a1c 100644 --- a/src/Entity/Contracts/TimeStampableInterface.php +++ b/src/Entity/Contracts/TimeStampableInterface.php @@ -22,8 +22,6 @@ declare(strict_types=1); namespace App\Entity\Contracts; -use DateTime; - interface TimeStampableInterface { /** diff --git a/src/Entity/Contracts/TimeTravelInterface.php b/src/Entity/Contracts/TimeTravelInterface.php index 064f4fec..2b0f4571 100644 --- a/src/Entity/Contracts/TimeTravelInterface.php +++ b/src/Entity/Contracts/TimeTravelInterface.php @@ -22,8 +22,6 @@ declare(strict_types=1); namespace App\Entity\Contracts; -use DateTime; - interface TimeTravelInterface { /** diff --git a/src/Entity/EDA/EDACategoryInfo.php b/src/Entity/EDA/EDACategoryInfo.php new file mode 100644 index 00000000..0163dfb3 --- /dev/null +++ b/src/Entity/EDA/EDACategoryInfo.php @@ -0,0 +1,135 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\EDA; + +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Embeddable; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints\Length; + +#[Embeddable] +class EDACategoryInfo +{ + /** + * @var string|null The reference prefix of the Part in the schematic. E.g. "R" for resistors, or "C" for capacitors. + */ + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['full', 'category:read', 'category:write', 'import'])] + #[Length(max: 255)] + private ?string $reference_prefix = null; + + /** @var bool|null Visibility of this part to EDA software in trinary logic. True=Visible, False=Invisible, Null=Auto */ + #[Column(name: 'invisible', type: Types::BOOLEAN, nullable: true)] //TODO: Rename column to visibility + #[Groups(['full', 'category:read', 'category:write', 'import'])] + private ?bool $visibility = null; + + /** @var bool|null If this is set to true, then this part will be excluded from the BOM */ + #[Column(type: Types::BOOLEAN, nullable: true)] + #[Groups(['full', 'category:read', 'category:write', 'import'])] + private ?bool $exclude_from_bom = null; + + /** @var bool|null If this is set to true, then this part will be excluded from the board/the PCB */ + #[Column(type: Types::BOOLEAN, nullable: true)] + #[Groups(['full', 'category:read', 'category:write', 'import'])] + private ?bool $exclude_from_board = null; + + /** @var bool|null If this is set to true, then this part will be excluded in the simulation */ + #[Column(type: Types::BOOLEAN, nullable: true)] + #[Groups(['full', 'category:read', 'category:write', 'import'])] + private ?bool $exclude_from_sim = true; + + /** @var string|null The KiCAD schematic symbol, which should be used (the path to the library) */ + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['full', 'category:read', 'category:write', 'import'])] + #[Length(max: 255)] + private ?string $kicad_symbol = null; + + public function getReferencePrefix(): ?string + { + return $this->reference_prefix; + } + + public function setReferencePrefix(?string $reference_prefix): EDACategoryInfo + { + $this->reference_prefix = $reference_prefix; + return $this; + } + + public function getVisibility(): ?bool + { + return $this->visibility; + } + + public function setVisibility(?bool $visibility): EDACategoryInfo + { + $this->visibility = $visibility; + return $this; + } + + public function getExcludeFromBom(): ?bool + { + return $this->exclude_from_bom; + } + + public function setExcludeFromBom(?bool $exclude_from_bom): EDACategoryInfo + { + $this->exclude_from_bom = $exclude_from_bom; + return $this; + } + + public function getExcludeFromBoard(): ?bool + { + return $this->exclude_from_board; + } + + public function setExcludeFromBoard(?bool $exclude_from_board): EDACategoryInfo + { + $this->exclude_from_board = $exclude_from_board; + return $this; + } + + public function getExcludeFromSim(): ?bool + { + return $this->exclude_from_sim; + } + + public function setExcludeFromSim(?bool $exclude_from_sim): EDACategoryInfo + { + $this->exclude_from_sim = $exclude_from_sim; + return $this; + } + + public function getKicadSymbol(): ?string + { + return $this->kicad_symbol; + } + + public function setKicadSymbol(?string $kicad_symbol): EDACategoryInfo + { + $this->kicad_symbol = $kicad_symbol; + return $this; + } + +} \ No newline at end of file diff --git a/src/Entity/EDA/EDAFootprintInfo.php b/src/Entity/EDA/EDAFootprintInfo.php new file mode 100644 index 00000000..9c5ef1c1 --- /dev/null +++ b/src/Entity/EDA/EDAFootprintInfo.php @@ -0,0 +1,51 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\EDA; + +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Embeddable; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints\Length; + +#[Embeddable] +class EDAFootprintInfo +{ + /** @var string|null The KiCAD footprint, which should be used (the path to the library) */ + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['full', 'footprint:read', 'footprint:write', 'import'])] + #[Length(max: 255)] + private ?string $kicad_footprint = null; + + public function getKicadFootprint(): ?string + { + return $this->kicad_footprint; + } + + public function setKicadFootprint(?string $kicad_footprint): EDAFootprintInfo + { + $this->kicad_footprint = $kicad_footprint; + return $this; + } +} \ No newline at end of file diff --git a/src/Entity/EDA/EDAPartInfo.php b/src/Entity/EDA/EDAPartInfo.php new file mode 100644 index 00000000..b4fc3588 --- /dev/null +++ b/src/Entity/EDA/EDAPartInfo.php @@ -0,0 +1,175 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\EDA; + +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Embeddable; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints\Length; + +#[Embeddable] +class EDAPartInfo +{ + /** + * @var string|null The reference prefix of the Part in the schematic. E.g. "R" for resistors, or "C" for capacitors. + */ + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['full', 'eda_info:read', 'eda_info:write', 'import'])] + #[Length(max: 255)] + private ?string $reference_prefix = null; + + /** @var string|null The value, which should be shown together with the part (e.g. 470 for a 470 Ohm resistor) */ + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['full', 'eda_info:read', 'eda_info:write', 'import'])] + #[Length(max: 255)] + private ?string $value = null; + + /** @var bool|null Visibility of this part to EDA software in trinary logic. True=Visible, False=Invisible, Null=Auto */ + #[Column(name: 'invisible', type: Types::BOOLEAN, nullable: true)] //TODO: Rename column to visibility + #[Groups(['full', 'eda_info:read', 'eda_info:write', 'import'])] + private ?bool $visibility = null; + + /** @var bool|null If this is set to true, then this part will be excluded from the BOM */ + #[Column(type: Types::BOOLEAN, nullable: true)] + #[Groups(['full', 'eda_info:read', 'eda_info:write', 'import'])] + private ?bool $exclude_from_bom = null; + + /** @var bool|null If this is set to true, then this part will be excluded from the board/the PCB */ + #[Column(type: Types::BOOLEAN, nullable: true)] + #[Groups(['full', 'eda_info:read', 'eda_info:write', 'import'])] + private ?bool $exclude_from_board = null; + + /** @var bool|null If this is set to true, then this part will be excluded in the simulation */ + #[Column(type: Types::BOOLEAN, nullable: true)] + #[Groups(['full', 'eda_info:read', 'eda_info:write', 'import'])] + private ?bool $exclude_from_sim = null; + + /** @var string|null The KiCAD schematic symbol, which should be used (the path to the library) */ + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['full', 'eda_info:read', 'eda_info:write', 'import'])] + #[Length(max: 255)] + private ?string $kicad_symbol = null; + + /** @var string|null The KiCAD footprint, which should be used (the path to the library) */ + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['full', 'eda_info:read', 'eda_info:write', 'import'])] + #[Length(max: 255)] + private ?string $kicad_footprint = null; + + public function __construct() + { + + } + + public function getReferencePrefix(): ?string + { + return $this->reference_prefix; + } + + public function setReferencePrefix(?string $reference_prefix): EDAPartInfo + { + $this->reference_prefix = $reference_prefix; + return $this; + } + + public function getValue(): ?string + { + return $this->value; + } + + public function setValue(?string $value): EDAPartInfo + { + $this->value = $value; + return $this; + } + + public function getVisibility(): ?bool + { + return $this->visibility; + } + + public function setVisibility(?bool $visibility): EDAPartInfo + { + $this->visibility = $visibility; + return $this; + } + + public function getExcludeFromBom(): ?bool + { + return $this->exclude_from_bom; + } + + public function setExcludeFromBom(?bool $exclude_from_bom): EDAPartInfo + { + $this->exclude_from_bom = $exclude_from_bom; + return $this; + } + + public function getExcludeFromBoard(): ?bool + { + return $this->exclude_from_board; + } + + public function setExcludeFromBoard(?bool $exclude_from_board): EDAPartInfo + { + $this->exclude_from_board = $exclude_from_board; + return $this; + } + + public function getExcludeFromSim(): ?bool + { + return $this->exclude_from_sim; + } + + public function setExcludeFromSim(?bool $exclude_from_sim): EDAPartInfo + { + $this->exclude_from_sim = $exclude_from_sim; + return $this; + } + + public function getKicadSymbol(): ?string + { + return $this->kicad_symbol; + } + + public function setKicadSymbol(?string $kicad_symbol): EDAPartInfo + { + $this->kicad_symbol = $kicad_symbol; + return $this; + } + + public function getKicadFootprint(): ?string + { + return $this->kicad_footprint; + } + + public function setKicadFootprint(?string $kicad_footprint): EDAPartInfo + { + $this->kicad_footprint = $kicad_footprint; + return $this; + } + + +} \ No newline at end of file diff --git a/src/Entity/LabelSystem/BarcodeType.php b/src/Entity/LabelSystem/BarcodeType.php index 0794b606..daf7d401 100644 --- a/src/Entity/LabelSystem/BarcodeType.php +++ b/src/Entity/LabelSystem/BarcodeType.php @@ -1,4 +1,7 @@ . */ - namespace App\Entity\LabelSystem; enum BarcodeType: string diff --git a/src/Entity/LabelSystem/LabelOptions.php b/src/Entity/LabelSystem/LabelOptions.php index 1d15d0f5..ee1a5414 100644 --- a/src/Entity/LabelSystem/LabelOptions.php +++ b/src/Entity/LabelSystem/LabelOptions.php @@ -43,6 +43,7 @@ namespace App\Entity\LabelSystem; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Validator\Constraints as Assert; #[ORM\Embeddable] @@ -53,6 +54,7 @@ class LabelOptions */ #[Assert\Positive] #[ORM\Column(type: Types::FLOAT)] + #[Groups(["extended", "full", "import"])] protected float $width = 50.0; /** @@ -60,38 +62,45 @@ class LabelOptions */ #[Assert\Positive] #[ORM\Column(type: Types::FLOAT)] + #[Groups(["extended", "full", "import"])] protected float $height = 30.0; /** * @var BarcodeType The type of the barcode that should be used in the label (e.g. 'qr') */ #[ORM\Column(type: Types::STRING, enumType: BarcodeType::class)] + #[Groups(["extended", "full", "import"])] protected BarcodeType $barcode_type = BarcodeType::NONE; /** * @var LabelPictureType What image should be shown along the label */ #[ORM\Column(type: Types::STRING, enumType: LabelPictureType::class)] + #[Groups(["extended", "full", "import"])] protected LabelPictureType $picture_type = LabelPictureType::NONE; #[ORM\Column(type: Types::STRING, enumType: LabelSupportedElement::class)] + #[Groups(["extended", "full", "import"])] protected LabelSupportedElement $supported_element = LabelSupportedElement::PART; /** * @var string any additional CSS for the label */ #[ORM\Column(type: Types::TEXT)] + #[Groups([ "full", "import"])] protected string $additional_css = ''; /** @var LabelProcessMode The mode that will be used to interpret the lines */ - #[ORM\Column(type: Types::STRING, enumType: LabelProcessMode::class, name: 'lines_mode')] + #[ORM\Column(name: 'lines_mode', type: Types::STRING, enumType: LabelProcessMode::class)] + #[Groups(["extended", "full", "import"])] protected LabelProcessMode $process_mode = LabelProcessMode::PLACEHOLDER; /** * @var string */ #[ORM\Column(type: Types::TEXT)] + #[Groups(["extended", "full", "import"])] protected string $lines = ''; public function getWidth(): float diff --git a/src/Entity/LabelSystem/LabelPictureType.php b/src/Entity/LabelSystem/LabelPictureType.php index c9183ca6..c1f90fe2 100644 --- a/src/Entity/LabelSystem/LabelPictureType.php +++ b/src/Entity/LabelSystem/LabelPictureType.php @@ -1,4 +1,7 @@ . */ - namespace App\Entity\LabelSystem; enum LabelPictureType: string @@ -34,4 +36,4 @@ enum LabelPictureType: string * Show the main attachment of the element on the label */ case MAIN_ATTACHMENT = 'main_attachment'; -} \ No newline at end of file +} diff --git a/src/Entity/LabelSystem/LabelProcessMode.php b/src/Entity/LabelSystem/LabelProcessMode.php index 76bf175f..d5967b49 100644 --- a/src/Entity/LabelSystem/LabelProcessMode.php +++ b/src/Entity/LabelSystem/LabelProcessMode.php @@ -1,4 +1,7 @@ . */ - namespace App\Entity\LabelSystem; enum LabelProcessMode: string @@ -26,4 +28,4 @@ enum LabelProcessMode: string case PLACEHOLDER = 'html'; /** Interpret the given lines as twig template */ case TWIG = 'twig'; -} \ No newline at end of file +} diff --git a/src/Entity/LabelSystem/LabelProfile.php b/src/Entity/LabelSystem/LabelProfile.php index a504ee0f..d3616c34 100644 --- a/src/Entity/LabelSystem/LabelProfile.php +++ b/src/Entity/LabelSystem/LabelProfile.php @@ -41,8 +41,8 @@ declare(strict_types=1); namespace App\Entity\LabelSystem; +use Doctrine\Common\Collections\Criteria; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; use App\Repository\LabelProfileRepository; use App\EntityListeners\TreeCacheInvalidationListener; use Doctrine\DBAL\Types\Types; @@ -52,6 +52,7 @@ use App\Entity\Attachments\LabelAttachment; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Validator\Constraints as Assert; /** @@ -66,11 +67,11 @@ class LabelProfile extends AttachmentContainingDBElement /** * @var Collection */ - #[ORM\OneToMany(targetEntity: LabelAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: LabelAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $attachments; - #[ORM\ManyToOne(targetEntity: AttachmentTypeAttachment::class)] + #[ORM\ManyToOne(targetEntity: LabelAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] protected ?Attachment $master_picture_attachment = null; @@ -79,6 +80,7 @@ class LabelProfile extends AttachmentContainingDBElement */ #[Assert\Valid] #[ORM\Embedded(class: 'LabelOptions')] + #[Groups(["extended", "full", "import"])] protected LabelOptions $options; /** @@ -91,6 +93,7 @@ class LabelProfile extends AttachmentContainingDBElement * @var bool determines, if this label profile should be shown in the dropdown quick menu */ #[ORM\Column(type: Types::BOOLEAN)] + #[Groups(["extended", "full", "import"])] protected bool $show_in_dropdown = true; public function __construct() diff --git a/src/Entity/LabelSystem/LabelSupportedElement.php b/src/Entity/LabelSystem/LabelSupportedElement.php index 99bac6c9..7649e586 100644 --- a/src/Entity/LabelSystem/LabelSupportedElement.php +++ b/src/Entity/LabelSystem/LabelSupportedElement.php @@ -1,4 +1,7 @@ . */ - namespace App\Entity\LabelSystem; +use App\Entity\Base\AbstractDBElement; +use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; enum LabelSupportedElement: string { @@ -32,14 +36,14 @@ enum LabelSupportedElement: string /** * Returns the entity class for the given element type - * @return string + * @return class-string */ public function getEntityClass(): string { return match ($this) { self::PART => Part::class, self::PART_LOT => PartLot::class, - self::STORELOCATION => Storelocation::class, + self::STORELOCATION => StorageLocation::class, }; } -} \ No newline at end of file +} diff --git a/src/Entity/LogSystem/AbstractLogEntry.php b/src/Entity/LogSystem/AbstractLogEntry.php index 1041cd6d..aa795613 100644 --- a/src/Entity/LogSystem/AbstractLogEntry.php +++ b/src/Entity/LogSystem/AbstractLogEntry.php @@ -23,30 +23,10 @@ declare(strict_types=1); namespace App\Entity\LogSystem; use Doctrine\DBAL\Types\Types; -use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentType; use App\Entity\Base\AbstractDBElement; -use App\Entity\ProjectSystem\Project; -use App\Entity\ProjectSystem\ProjectBOMEntry; -use App\Entity\LabelSystem\LabelProfile; -use App\Entity\Parameters\AbstractParameter; -use App\Entity\Parts\Category; -use App\Entity\Parts\Footprint; -use App\Entity\Parts\Manufacturer; -use App\Entity\Parts\MeasurementUnit; -use App\Entity\Parts\Part; -use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; -use App\Entity\Parts\Supplier; -use App\Entity\PriceInformations\Currency; -use App\Entity\PriceInformations\Orderdetail; -use App\Entity\PriceInformations\Pricedetail; -use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; -use DateTime; + use Doctrine\ORM\Mapping as ORM; -use InvalidArgumentException; -use Psr\Log\LogLevel as PsrLogLevel; use App\Repository\LogEntryRepository; /** @@ -75,10 +55,11 @@ abstract class AbstractLogEntry extends AbstractDBElement #[ORM\Column(type: Types::STRING)] protected string $username = ''; - /** @var \DateTimeInterface The datetime the event associated with this log entry has occured + /** + * @var \DateTimeImmutable The datetime the event associated with this log entry has occured */ - #[ORM\Column(name: 'datetime', type: Types::DATETIME_MUTABLE)] - protected \DateTimeInterface $timestamp; + #[ORM\Column(name: 'datetime', type: Types::DATETIME_IMMUTABLE)] + protected \DateTimeImmutable $timestamp; /** * @var LogLevel The priority level of the associated level. 0 is highest, 7 lowest @@ -109,7 +90,7 @@ abstract class AbstractLogEntry extends AbstractDBElement public function __construct() { - $this->timestamp = new DateTime(); + $this->timestamp = new \DateTimeImmutable(); } /** @@ -184,7 +165,7 @@ abstract class AbstractLogEntry extends AbstractDBElement /** * Returns the timestamp when the event that caused this log entry happened. */ - public function getTimestamp(): \DateTimeInterface + public function getTimestamp(): \DateTimeImmutable { return $this->timestamp; } @@ -194,7 +175,7 @@ abstract class AbstractLogEntry extends AbstractDBElement * * @return $this */ - public function setTimestamp(\DateTimeInterface $timestamp): self + public function setTimestamp(\DateTimeImmutable $timestamp): self { $this->timestamp = $timestamp; diff --git a/src/Entity/LogSystem/CollectionElementDeleted.php b/src/Entity/LogSystem/CollectionElementDeleted.php index c3980a40..16bf33f5 100644 --- a/src/Entity/LogSystem/CollectionElementDeleted.php +++ b/src/Entity/LogSystem/CollectionElementDeleted.php @@ -52,7 +52,7 @@ use App\Entity\Attachments\GroupAttachment; use App\Entity\Attachments\ManufacturerAttachment; use App\Entity\Attachments\MeasurementUnitAttachment; use App\Entity\Attachments\PartAttachment; -use App\Entity\Attachments\StorelocationAttachment; +use App\Entity\Attachments\StorageLocationAttachment; use App\Entity\Attachments\SupplierAttachment; use App\Entity\Attachments\UserAttachment; use App\Entity\Base\AbstractDBElement; @@ -69,20 +69,19 @@ use App\Entity\Parameters\GroupParameter; use App\Entity\Parameters\ManufacturerParameter; use App\Entity\Parameters\MeasurementUnitParameter; use App\Entity\Parameters\PartParameter; -use App\Entity\Parameters\StorelocationParameter; +use App\Entity\Parameters\StorageLocationParameter; use App\Entity\Parameters\SupplierParameter; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; use Doctrine\ORM\Mapping as ORM; -use InvalidArgumentException; #[ORM\Entity] class CollectionElementDeleted extends AbstractLogEntry implements LogWithEventUndoInterface @@ -147,65 +146,38 @@ class CollectionElementDeleted extends AbstractLogEntry implements LogWithEventU private function resolveAbstractClassToInstantiableClass(string $abstract_class): string { if (is_a($abstract_class, AbstractParameter::class, true)) { - switch ($this->getTargetClass()) { - case AttachmentType::class: - return AttachmentTypeParameter::class; - case Category::class: - return CategoryParameter::class; - case Currency::class: - return CurrencyParameter::class; - case Project::class: - return ProjectParameter::class; - case Footprint::class: - return FootprintParameter::class; - case Group::class: - return GroupParameter::class; - case Manufacturer::class: - return ManufacturerParameter::class; - case MeasurementUnit::class: - return MeasurementUnitParameter::class; - case Part::class: - return PartParameter::class; - case Storelocation::class: - return StorelocationParameter::class; - case Supplier::class: - return SupplierParameter::class; - - default: - throw new \RuntimeException('Unknown target class for parameter: '.$this->getTargetClass()); - } + return match ($this->getTargetClass()) { + AttachmentType::class => AttachmentTypeParameter::class, + Category::class => CategoryParameter::class, + Currency::class => CurrencyParameter::class, + Project::class => ProjectParameter::class, + Footprint::class => FootprintParameter::class, + Group::class => GroupParameter::class, + Manufacturer::class => ManufacturerParameter::class, + MeasurementUnit::class => MeasurementUnitParameter::class, + Part::class => PartParameter::class, + StorageLocation::class => StorageLocationParameter::class, + Supplier::class => SupplierParameter::class, + default => throw new \RuntimeException('Unknown target class for parameter: '.$this->getTargetClass()), + }; } if (is_a($abstract_class, Attachment::class, true)) { - switch ($this->getTargetClass()) { - case AttachmentType::class: - return AttachmentTypeAttachment::class; - case Category::class: - return CategoryAttachment::class; - case Currency::class: - return CurrencyAttachment::class; - case Project::class: - return ProjectAttachment::class; - case Footprint::class: - return FootprintAttachment::class; - case Group::class: - return GroupAttachment::class; - case Manufacturer::class: - return ManufacturerAttachment::class; - case MeasurementUnit::class: - return MeasurementUnitAttachment::class; - case Part::class: - return PartAttachment::class; - case Storelocation::class: - return StorelocationAttachment::class; - case Supplier::class: - return SupplierAttachment::class; - case User::class: - return UserAttachment::class; - - default: - throw new \RuntimeException('Unknown target class for parameter: '.$this->getTargetClass()); - } + return match ($this->getTargetClass()) { + AttachmentType::class => AttachmentTypeAttachment::class, + Category::class => CategoryAttachment::class, + Currency::class => CurrencyAttachment::class, + Project::class => ProjectAttachment::class, + Footprint::class => FootprintAttachment::class, + Group::class => GroupAttachment::class, + Manufacturer::class => ManufacturerAttachment::class, + MeasurementUnit::class => MeasurementUnitAttachment::class, + Part::class => PartAttachment::class, + StorageLocation::class => StorageLocationAttachment::class, + Supplier::class => SupplierAttachment::class, + User::class => UserAttachment::class, + default => throw new \RuntimeException('Unknown target class for parameter: '.$this->getTargetClass()), + }; } throw new \RuntimeException('The class '.$abstract_class.' is abstract and no explicit resolving to an concrete type is defined!'); diff --git a/src/Entity/LogSystem/ElementCreatedLogEntry.php b/src/Entity/LogSystem/ElementCreatedLogEntry.php index 7d5968a8..8364974c 100644 --- a/src/Entity/LogSystem/ElementCreatedLogEntry.php +++ b/src/Entity/LogSystem/ElementCreatedLogEntry.php @@ -27,9 +27,7 @@ use App\Entity\Contracts\LogWithCommentInterface; use App\Entity\Contracts\LogWithEventUndoInterface; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; -use App\Services\LogSystem\EventUndoMode; use Doctrine\ORM\Mapping as ORM; -use InvalidArgumentException; #[ORM\Entity] class ElementCreatedLogEntry extends AbstractLogEntry implements LogWithCommentInterface, LogWithEventUndoInterface diff --git a/src/Entity/LogSystem/ElementDeletedLogEntry.php b/src/Entity/LogSystem/ElementDeletedLogEntry.php index 836e8d60..e3dd2ac7 100644 --- a/src/Entity/LogSystem/ElementDeletedLogEntry.php +++ b/src/Entity/LogSystem/ElementDeletedLogEntry.php @@ -29,9 +29,7 @@ use App\Entity\Contracts\NamedElementInterface; use App\Entity\Contracts\TimeTravelInterface; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; -use App\Services\LogSystem\EventUndoMode; use Doctrine\ORM\Mapping as ORM; -use InvalidArgumentException; #[ORM\Entity] class ElementDeletedLogEntry extends AbstractLogEntry implements TimeTravelInterface, LogWithCommentInterface, LogWithEventUndoInterface diff --git a/src/Entity/LogSystem/ElementEditedLogEntry.php b/src/Entity/LogSystem/ElementEditedLogEntry.php index 4279ac63..8d4b7b9d 100644 --- a/src/Entity/LogSystem/ElementEditedLogEntry.php +++ b/src/Entity/LogSystem/ElementEditedLogEntry.php @@ -28,7 +28,6 @@ use App\Entity\Contracts\LogWithEventUndoInterface; use App\Entity\Contracts\LogWithNewDataInterface; use App\Entity\Contracts\TimeTravelInterface; use Doctrine\ORM\Mapping as ORM; -use InvalidArgumentException; #[ORM\Entity] class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterface, LogWithCommentInterface, LogWithEventUndoInterface, LogWithNewDataInterface diff --git a/src/Entity/LogSystem/LogLevel.php b/src/Entity/LogSystem/LogLevel.php index 98fb3649..435c5468 100644 --- a/src/Entity/LogSystem/LogLevel.php +++ b/src/Entity/LogSystem/LogLevel.php @@ -1,4 +1,7 @@ . */ - namespace App\Entity\LogSystem; -use \Psr\Log\LogLevel as PSRLogLevel; +use Psr\Log\LogLevel as PSRLogLevel; enum LogLevel: int { diff --git a/src/Entity/LogSystem/LogTargetType.php b/src/Entity/LogSystem/LogTargetType.php index 38d1f1ed..1c6e4f8c 100644 --- a/src/Entity/LogSystem/LogTargetType.php +++ b/src/Entity/LogSystem/LogTargetType.php @@ -1,4 +1,7 @@ . */ - namespace App\Entity\LogSystem; use App\Entity\Attachments\Attachment; @@ -29,8 +31,9 @@ use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; +use App\Entity\Parts\PartAssociation; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; use App\Entity\PriceInformations\Orderdetail; @@ -63,6 +66,8 @@ enum LogTargetType: int case PARAMETER = 18; case LABEL_PROFILE = 19; + case PART_ASSOCIATION = 20; + /** * Returns the class name of the target type or null if the target type is NONE. * @return string|null @@ -81,7 +86,7 @@ enum LogTargetType: int self::GROUP => Group::class, self::MANUFACTURER => Manufacturer::class, self::PART => Part::class, - self::STORELOCATION => Storelocation::class, + self::STORELOCATION => StorageLocation::class, self::SUPPLIER => Supplier::class, self::PART_LOT => PartLot::class, self::CURRENCY => Currency::class, @@ -90,6 +95,7 @@ enum LogTargetType: int self::MEASUREMENT_UNIT => MeasurementUnit::class, self::PARAMETER => AbstractParameter::class, self::LABEL_PROFILE => LabelProfile::class, + self::PART_ASSOCIATION => PartAssociation::class, }; } @@ -116,7 +122,7 @@ enum LogTargetType: int } } - $elementClass = is_object($element) ? get_class($element) : $element; + $elementClass = is_object($element) ? $element::class : $element; //If no matching type was found, throw an exception throw new \InvalidArgumentException("The given class $elementClass is not a valid log target type."); } diff --git a/src/Entity/LogSystem/LogWithEventUndoTrait.php b/src/Entity/LogSystem/LogWithEventUndoTrait.php index 16568241..ed8629dc 100644 --- a/src/Entity/LogSystem/LogWithEventUndoTrait.php +++ b/src/Entity/LogSystem/LogWithEventUndoTrait.php @@ -1,4 +1,7 @@ . */ - namespace App\Entity\LogSystem; use App\Entity\Contracts\LogWithEventUndoInterface; @@ -48,4 +50,4 @@ trait LogWithEventUndoTrait $mode_int = $this->extra['um'] ?? 1; return EventUndoMode::fromExtraInt($mode_int); } -} \ No newline at end of file +} diff --git a/src/Entity/LogSystem/PartStockChangeType.php b/src/Entity/LogSystem/PartStockChangeType.php index bbd574a7..f69fe95f 100644 --- a/src/Entity/LogSystem/PartStockChangeType.php +++ b/src/Entity/LogSystem/PartStockChangeType.php @@ -1,4 +1,7 @@ . */ - namespace App\Entity\LogSystem; enum PartStockChangeType: string @@ -39,6 +41,11 @@ enum PartStockChangeType: string }; } + public function toTranslationKey(): string + { + return 'log.part_stock_changed.' . $this->value; + } + public static function fromExtraShortType(string $value): self { return match ($value) { @@ -48,4 +55,4 @@ enum PartStockChangeType: string default => throw new \InvalidArgumentException("Invalid short type: $value"), }; } -} \ No newline at end of file +} diff --git a/src/Entity/LogSystem/PartStockChangedLogEntry.php b/src/Entity/LogSystem/PartStockChangedLogEntry.php index 63288d0d..1bac9e9f 100644 --- a/src/Entity/LogSystem/PartStockChangedLogEntry.php +++ b/src/Entity/LogSystem/PartStockChangedLogEntry.php @@ -41,8 +41,10 @@ class PartStockChangedLogEntry extends AbstractLogEntry * @param float $new_total_part_instock The new total instock of the part. * @param string $comment The comment associated with the change. * @param PartLot|null $move_to_target The target lot if the type is TYPE_MOVE. + * @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards. */ - protected function __construct(PartStockChangeType $type, PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, ?PartLot $move_to_target = null) + protected function __construct(PartStockChangeType $type, PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, ?PartLot $move_to_target = null, + ?\DateTimeInterface $action_timestamp = null) { parent::__construct(); @@ -50,8 +52,6 @@ class PartStockChangedLogEntry extends AbstractLogEntry $this->level = LogLevel::INFO; $this->setTargetElement($lot); - - $this->typeString = 'part_stock_changed'; $this->extra = array_merge($this->extra, [ 't' => $type->toExtraShortType(), 'o' => $old_stock, @@ -62,6 +62,11 @@ class PartStockChangedLogEntry extends AbstractLogEntry $this->extra['c'] = mb_strimwidth($comment, 0, self::COMMENT_MAX_LENGTH, '...'); } + if ($action_timestamp instanceof \DateTimeInterface) { + //The action timestamp is saved as an ISO 8601 string + $this->extra['a'] = $action_timestamp->format(\DateTimeInterface::ATOM); + } + if ($move_to_target instanceof PartLot) { if ($type !== PartStockChangeType::MOVE) { throw new \InvalidArgumentException('The move_to_target parameter can only be set if the type is "move"!'); @@ -78,11 +83,12 @@ class PartStockChangedLogEntry extends AbstractLogEntry * @param float $new_stock The new stock of the lot. * @param float $new_total_part_instock The new total instock of the part. * @param string $comment The comment associated with the change. + * @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards. * @return self */ - public static function add(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment): self + public static function add(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, ?\DateTimeInterface $action_timestamp = null): self { - return new self(PartStockChangeType::ADD, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment); + return new self(PartStockChangeType::ADD, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment, action_timestamp: $action_timestamp); } /** @@ -92,11 +98,12 @@ class PartStockChangedLogEntry extends AbstractLogEntry * @param float $new_stock The new stock of the lot. * @param float $new_total_part_instock The new total instock of the part. * @param string $comment The comment associated with the change. + * @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards. * @return self */ - public static function withdraw(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment): self + public static function withdraw(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, ?\DateTimeInterface $action_timestamp = null): self { - return new self(PartStockChangeType::WITHDRAW, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment); + return new self(PartStockChangeType::WITHDRAW, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment, action_timestamp: $action_timestamp); } /** @@ -107,10 +114,12 @@ class PartStockChangedLogEntry extends AbstractLogEntry * @param float $new_total_part_instock The new total instock of the part. * @param string $comment The comment associated with the change. * @param PartLot $move_to_target The target lot. + * @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards. + * @return self */ - public static function move(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, PartLot $move_to_target): self + public static function move(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, PartLot $move_to_target, ?\DateTimeInterface $action_timestamp = null): self { - return new self(PartStockChangeType::MOVE, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment, $move_to_target); + return new self(PartStockChangeType::MOVE, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment, $move_to_target, action_timestamp: $action_timestamp); } /** @@ -169,4 +178,18 @@ class PartStockChangedLogEntry extends AbstractLogEntry { return $this->extra['m'] ?? null; } + + /** + * Returns the timestamp when this action was performed and not when the log entry was created. + * This is useful if the action happened in the past, and the log entry is created afterwards. + * If the timestamp is not set, null is returned. + * @return \DateTimeInterface|null + */ + public function getActionTimestamp(): ?\DateTimeInterface + { + if (!empty($this->extra['a'])) { + return \DateTimeImmutable::createFromFormat(\DateTimeInterface::ATOM, $this->extra['a']); + } + return null; + } } diff --git a/src/Entity/LogSystem/SecurityEventLogEntry.php b/src/Entity/LogSystem/SecurityEventLogEntry.php index ffcfd6a5..12e8e65e 100644 --- a/src/Entity/LogSystem/SecurityEventLogEntry.php +++ b/src/Entity/LogSystem/SecurityEventLogEntry.php @@ -44,9 +44,9 @@ namespace App\Entity\LogSystem; use App\Entity\Base\AbstractDBElement; use App\Entity\UserSystem\User; use App\Events\SecurityEvents; +use App\Helpers\IPAnonymizer; use Doctrine\ORM\Mapping as ORM; use InvalidArgumentException; -use Symfony\Component\HttpFoundation\IpUtils; /** * This log entry is created when something security related to a user happens. @@ -127,14 +127,14 @@ class SecurityEventLogEntry extends AbstractLogEntry * Sets the IP address used to log in the user. * * @param string $ip the IP address used to log in the user - * @param bool $anonymize Anonymize the IP address (remove last block) to be GPDR compliant + * @param bool $anonymize Anonymize the IP address (remove last block) to be GDPR compliant * * @return $this */ public function setIPAddress(string $ip, bool $anonymize = true): self { if ($anonymize) { - $ip = IpUtils::anonymize($ip); + $ip = IPAnonymizer::anonymize($ip); } $this->extra['i'] = $ip; diff --git a/src/Entity/LogSystem/UserLoginLogEntry.php b/src/Entity/LogSystem/UserLoginLogEntry.php index c9e6bc21..0719a740 100644 --- a/src/Entity/LogSystem/UserLoginLogEntry.php +++ b/src/Entity/LogSystem/UserLoginLogEntry.php @@ -22,8 +22,9 @@ declare(strict_types=1); namespace App\Entity\LogSystem; +use App\Helpers\IPAnonymizer; use Doctrine\ORM\Mapping as ORM; -use Symfony\Component\HttpFoundation\IpUtils; + /** * This log entry is created when a user logs in. @@ -52,14 +53,14 @@ class UserLoginLogEntry extends AbstractLogEntry * Sets the IP address used to log in the user. * * @param string $ip the IP address used to log in the user - * @param bool $anonymize Anonymize the IP address (remove last block) to be GPDR compliant + * @param bool $anonymize Anonymize the IP address (remove last block) to be GDPR compliant * * @return $this */ public function setIPAddress(string $ip, bool $anonymize = true): self { if ($anonymize) { - $ip = IpUtils::anonymize($ip); + $ip = IPAnonymizer::anonymize($ip); } $this->extra['i'] = $ip; diff --git a/src/Entity/LogSystem/UserLogoutLogEntry.php b/src/Entity/LogSystem/UserLogoutLogEntry.php index ba52de87..f9f9a3dc 100644 --- a/src/Entity/LogSystem/UserLogoutLogEntry.php +++ b/src/Entity/LogSystem/UserLogoutLogEntry.php @@ -22,8 +22,8 @@ declare(strict_types=1); namespace App\Entity\LogSystem; +use App\Helpers\IPAnonymizer; use Doctrine\ORM\Mapping as ORM; -use Symfony\Component\HttpFoundation\IpUtils; #[ORM\Entity] class UserLogoutLogEntry extends AbstractLogEntry @@ -49,14 +49,14 @@ class UserLogoutLogEntry extends AbstractLogEntry * Sets the IP address used to log in the user. * * @param string $ip the IP address used to log in the user - * @param bool $anonymize Anonymize the IP address (remove last block) to be GPDR compliant + * @param bool $anonymize Anonymize the IP address (remove last block) to be GDPR compliant * * @return $this */ public function setIPAddress(string $ip, bool $anonymize = true): self { if ($anonymize) { - $ip = IpUtils::anonymize($ip); + $ip = IPAnonymizer::anonymize($ip); } $this->extra['i'] = $ip; diff --git a/src/Entity/OAuthToken.php b/src/Entity/OAuthToken.php index b1534a4d..bc692369 100644 --- a/src/Entity/OAuthToken.php +++ b/src/Entity/OAuthToken.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace App\Entity; -use App\Entity\Base\AbstractDBElement; use App\Entity\Base\AbstractNamedDBElement; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; @@ -32,22 +31,22 @@ use League\OAuth2\Client\Token\AccessTokenInterface; /** * This entity represents a OAuth token pair (access and refresh token), for an application */ -#[ORM\Entity()] +#[ORM\Entity] #[ORM\Table(name: 'oauth_tokens')] #[ORM\UniqueConstraint(name: 'oauth_tokens_unique_name', columns: ['name'])] #[ORM\Index(columns: ['name'], name: 'oauth_tokens_name_idx')] class OAuthToken extends AbstractNamedDBElement implements AccessTokenInterface { /** @var string|null The short-term usable OAuth2 token */ - #[ORM\Column(type: 'text', nullable: true)] + #[ORM\Column(type: Types::TEXT, nullable: true)] private ?string $token = null; - /** @var \DateTimeInterface The date when the token expires */ + /** @var \DateTimeImmutable|null The date when the token expires */ #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)] - private ?\DateTimeInterface $expires_at = null; + private ?\DateTimeImmutable $expires_at = null; /** @var string|null The refresh token for the OAuth2 auth */ - #[ORM\Column(type: 'text', nullable: true)] + #[ORM\Column(type: Types::TEXT, nullable: true)] private ?string $refresh_token = null; /** @@ -55,7 +54,7 @@ class OAuthToken extends AbstractNamedDBElement implements AccessTokenInterface */ private const DEFAULT_EXPIRATION_TIME = 3600; - public function __construct(string $name, ?string $refresh_token, ?string $token = null, \DateTimeInterface $expires_at = null) + public function __construct(string $name, ?string $refresh_token, ?string $token = null, ?\DateTimeImmutable $expires_at = null) { //If token is given, you also have to give the expires_at date if ($token !== null && $expires_at === null) { @@ -83,7 +82,7 @@ class OAuthToken extends AbstractNamedDBElement implements AccessTokenInterface ); } - private static function unixTimestampToDatetime(int $timestamp): \DateTimeInterface + private static function unixTimestampToDatetime(int $timestamp): \DateTimeImmutable { return \DateTimeImmutable::createFromFormat('U', (string)$timestamp); } @@ -93,7 +92,7 @@ class OAuthToken extends AbstractNamedDBElement implements AccessTokenInterface return $this->token; } - public function getExpirationDate(): ?\DateTimeInterface + public function getExpirationDate(): ?\DateTimeImmutable { return $this->expires_at; } @@ -135,17 +134,17 @@ class OAuthToken extends AbstractNamedDBElement implements AccessTokenInterface $this->expires_at = self::unixTimestampToDatetime($accessToken->getExpires() ?? time() + self::DEFAULT_EXPIRATION_TIME); } - public function getExpires() + public function getExpires(): ?int { return $this->expires_at->getTimestamp(); } - public function hasExpired() + public function hasExpired(): bool { return $this->isExpired(); } - public function getValues() + public function getValues(): array { return []; } diff --git a/src/Entity/Parameters/AbstractParameter.php b/src/Entity/Parameters/AbstractParameter.php index 4a5cb40a..edcedc3e 100644 --- a/src/Entity/Parameters/AbstractParameter.php +++ b/src/Entity/Parameters/AbstractParameter.php @@ -41,7 +41,19 @@ declare(strict_types=1); namespace App\Entity\Parameters; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Doctrine\Orm\Filter\RangeFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use App\ApiPlatform\Filter\LikeFilter; use App\Repository\ParameterRepository; +use App\Validator\UniqueValidatableInterface; use Doctrine\DBAL\Types\Types; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\AbstractNamedDBElement; @@ -49,6 +61,8 @@ use Doctrine\ORM\Mapping as ORM; use InvalidArgumentException; use LogicException; use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Annotation\SerializedName; +use Symfony\Component\Serializer\Attribute\DiscriminatorMap; use Symfony\Component\Validator\Constraints as Assert; use function sprintf; @@ -56,13 +70,43 @@ use function sprintf; #[ORM\Entity(repositoryClass: ParameterRepository::class)] #[ORM\InheritanceType('SINGLE_TABLE')] #[ORM\DiscriminatorColumn(name: 'type', type: 'smallint')] -#[ORM\DiscriminatorMap([0 => 'CategoryParameter', 1 => 'CurrencyParameter', 2 => 'ProjectParameter', 3 => 'FootprintParameter', 4 => 'GroupParameter', 5 => 'ManufacturerParameter', 6 => 'MeasurementUnitParameter', 7 => 'PartParameter', 8 => 'StorelocationParameter', 9 => 'SupplierParameter', 10 => 'AttachmentTypeParameter'])] +#[ORM\DiscriminatorMap([0 => CategoryParameter::class, 1 => CurrencyParameter::class, 2 => ProjectParameter::class, + 3 => FootprintParameter::class, 4 => GroupParameter::class, 5 => ManufacturerParameter::class, + 6 => MeasurementUnitParameter::class, 7 => PartParameter::class, 8 => StorageLocationParameter::class, + 9 => SupplierParameter::class, 10 => AttachmentTypeParameter::class])] #[ORM\Table('parameters')] -#[ORM\Index(name: 'parameter_name_idx', columns: ['name'])] -#[ORM\Index(name: 'parameter_group_idx', columns: ['param_group'])] -#[ORM\Index(name: 'parameter_type_element_idx', columns: ['type', 'element_id'])] -abstract class AbstractParameter extends AbstractNamedDBElement +#[ORM\Index(columns: ['name'], name: 'parameter_name_idx')] +#[ORM\Index(columns: ['param_group'], name: 'parameter_group_idx')] +#[ORM\Index(columns: ['type', 'element_id'], name: 'parameter_type_element_idx')] +#[ApiResource( + shortName: 'Parameter', + operations: [ + new Get(security: 'is_granted("read", object)'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['parameter:read', 'parameter:read:standalone', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['parameter:write', 'parameter:write:standalone', 'api:basic:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiFilter(LikeFilter::class, properties: ["name", "symbol", "unit", "group", "value_text"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(RangeFilter::class, properties: ["value_min", "value_typical", "value_max"])] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] +//This discriminator map is required for API platform to know which class to use for deserialization, when creating a new parameter. +#[DiscriminatorMap(typeProperty: '_type', mapping: self::API_DISCRIMINATOR_MAP)] +abstract class AbstractParameter extends AbstractNamedDBElement implements UniqueValidatableInterface { + + /* + * The discriminator map used for API platform. The key should be the same as the api platform short type (the @type JSONLD field). + */ + private const API_DISCRIMINATOR_MAP = ["Part" => PartParameter::class, + "AttachmentType" => AttachmentTypeParameter::class, "Category" => CategoryParameter::class, "Currency" => CurrencyParameter::class, + "Project" => ProjectParameter::class, "Footprint" => FootprintParameter::class, "Group" => GroupParameter::class, + "Manufacturer" => ManufacturerParameter::class, "MeasurementUnit" => MeasurementUnitParameter::class, + "StorageLocation" => StorageLocationParameter::class, "Supplier" => SupplierParameter::class]; + /** * @var string The class of the element that can be passed to this attachment. Must be overridden in subclasses. */ @@ -72,7 +116,7 @@ abstract class AbstractParameter extends AbstractNamedDBElement * @var string The mathematical symbol for this specification. Can be rendered pretty later. Should be short */ #[Assert\Length(max: 20)] - #[Groups(['full'])] + #[Groups(['full', 'parameter:read', 'parameter:write', 'import'])] #[ORM\Column(type: Types::STRING)] protected string $symbol = ''; @@ -82,7 +126,7 @@ abstract class AbstractParameter extends AbstractNamedDBElement #[Assert\Type(['float', null])] #[Assert\LessThanOrEqual(propertyPath: 'value_typical', message: 'parameters.validator.min_lesser_typical')] #[Assert\LessThan(propertyPath: 'value_max', message: 'parameters.validator.min_lesser_max')] - #[Groups(['full'])] + #[Groups(['full', 'parameter:read', 'parameter:write', 'import'])] #[ORM\Column(type: Types::FLOAT, nullable: true)] protected ?float $value_min = null; @@ -90,7 +134,7 @@ abstract class AbstractParameter extends AbstractNamedDBElement * @var float|null the typical value of this property */ #[Assert\Type([null, 'float'])] - #[Groups(['full'])] + #[Groups(['full', 'parameter:read', 'parameter:write', 'import'])] #[ORM\Column(type: Types::FLOAT, nullable: true)] protected ?float $value_typical = null; @@ -99,29 +143,32 @@ abstract class AbstractParameter extends AbstractNamedDBElement */ #[Assert\Type(['float', null])] #[Assert\GreaterThanOrEqual(propertyPath: 'value_typical', message: 'parameters.validator.max_greater_typical')] - #[Groups(['full'])] + #[Groups(['full', 'parameter:read', 'parameter:write', 'import'])] #[ORM\Column(type: Types::FLOAT, nullable: true)] protected ?float $value_max = null; /** * @var string The unit in which the value values are given (e.g. V) */ - #[Groups(['full'])] + #[Groups(['full', 'parameter:read', 'parameter:write', 'import'])] #[ORM\Column(type: Types::STRING)] + #[Assert\Length(max: 50)] protected string $unit = ''; /** * @var string a text value for the given property */ - #[Groups(['full'])] + #[Groups(['full', 'parameter:read', 'parameter:write', 'import'])] #[ORM\Column(type: Types::STRING)] + #[Assert\Length(max: 255)] protected string $value_text = ''; /** * @var string the group this parameter belongs to */ - #[Groups(['full'])] - #[ORM\Column(type: Types::STRING, name: 'param_group')] + #[Groups(['full', 'parameter:read', 'parameter:write', 'import'])] + #[ORM\Column(name: 'param_group', type: Types::STRING)] + #[Assert\Length(max: 255)] protected string $group = ''; /** @@ -129,6 +176,7 @@ abstract class AbstractParameter extends AbstractNamedDBElement * * @var AbstractDBElement|null the element to which this parameter belongs to */ + #[Groups(['parameter:read:standalone', 'parameter:write:standalone'])] protected ?AbstractDBElement $element = null; public function __construct() @@ -158,7 +206,9 @@ abstract class AbstractParameter extends AbstractNamedDBElement * Return a formatted string version of the values of the string. * Based on the set values it can return something like this: 34 V (12 V ... 50 V) [Text]. */ - public function getFormattedValue(): string + #[Groups(['parameter:read', 'full'])] + #[SerializedName('formatted')] + public function getFormattedValue(bool $latex_formatted = false): string { //If we just only have text value, return early if (null === $this->value_typical && null === $this->value_min && null === $this->value_max) { @@ -168,7 +218,7 @@ abstract class AbstractParameter extends AbstractNamedDBElement $str = ''; $bracket_opened = false; if ($this->value_typical) { - $str .= $this->getValueTypicalWithUnit(); + $str .= $this->getValueTypicalWithUnit($latex_formatted); if ($this->value_min || $this->value_max) { $bracket_opened = true; $str .= ' ('; @@ -176,11 +226,11 @@ abstract class AbstractParameter extends AbstractNamedDBElement } if ($this->value_max && $this->value_min) { - $str .= $this->getValueMinWithUnit().' ... '.$this->getValueMaxWithUnit(); + $str .= $this->getValueMinWithUnit($latex_formatted).' ... '.$this->getValueMaxWithUnit($latex_formatted); } elseif ($this->value_max) { - $str .= 'max. '.$this->getValueMaxWithUnit(); + $str .= 'max. '.$this->getValueMaxWithUnit($latex_formatted); } elseif ($this->value_min) { - $str .= 'min. '.$this->getValueMinWithUnit(); + $str .= 'min. '.$this->getValueMinWithUnit($latex_formatted); } //Add closing bracket @@ -294,25 +344,25 @@ abstract class AbstractParameter extends AbstractNamedDBElement /** * Return a formatted version with the minimum value with the unit of this parameter. */ - public function getValueTypicalWithUnit(): string + public function getValueTypicalWithUnit(bool $with_latex = false): string { - return $this->formatWithUnit($this->value_typical); + return $this->formatWithUnit($this->value_typical, with_latex: $with_latex); } /** * Return a formatted version with the maximum value with the unit of this parameter. */ - public function getValueMaxWithUnit(): string + public function getValueMaxWithUnit(bool $with_latex = false): string { - return $this->formatWithUnit($this->value_max); + return $this->formatWithUnit($this->value_max, with_latex: $with_latex); } /** * Return a formatted version with the typical value with the unit of this parameter. */ - public function getValueMinWithUnit(): string + public function getValueMinWithUnit(bool $with_latex = false): string { - return $this->formatWithUnit($this->value_min); + return $this->formatWithUnit($this->value_min, with_latex: $with_latex); } /** @@ -391,11 +441,18 @@ abstract class AbstractParameter extends AbstractNamedDBElement /** * Return a string representation and (if possible) with its unit. */ - protected function formatWithUnit(float $value, string $format = '%g'): string + protected function formatWithUnit(float $value, string $format = '%g', bool $with_latex = false): string { $str = sprintf($format, $value); if ($this->unit !== '') { - return $str.' '.$this->unit; + + if (!$with_latex) { + $unit = $this->unit; + } else { + $unit = '$\mathrm{'.$this->unit.'}$'; + } + + return $str.' '.$unit; } return $str; @@ -409,4 +466,9 @@ abstract class AbstractParameter extends AbstractNamedDBElement { return static::ALLOWED_ELEMENT_CLASS; } + + public function getComparableFields(): array + { + return ['name' => $this->name, 'group' => $this->group, 'element' => $this->element?->getId()]; + } } diff --git a/src/Entity/Parameters/AttachmentTypeParameter.php b/src/Entity/Parameters/AttachmentTypeParameter.php index 2ac9dc09..9a272a7d 100644 --- a/src/Entity/Parameters/AttachmentTypeParameter.php +++ b/src/Entity/Parameters/AttachmentTypeParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Attachments\AttachmentType; use App\Entity\Base\AbstractDBElement; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; #[UniqueEntity(fields: ['name', 'group', 'element'])] #[ORM\Entity(repositoryClass: ParameterRepository::class)] @@ -57,5 +59,6 @@ class AttachmentTypeParameter extends AbstractParameter */ #[ORM\ManyToOne(targetEntity: AttachmentType::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/CategoryParameter.php b/src/Entity/Parameters/CategoryParameter.php index 8aa4f29c..ecab1740 100644 --- a/src/Entity/Parameters/CategoryParameter.php +++ b/src/Entity/Parameters/CategoryParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; use App\Entity\Parts\Category; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; #[UniqueEntity(fields: ['name', 'group', 'element'])] #[ORM\Entity(repositoryClass: ParameterRepository::class)] @@ -57,5 +59,6 @@ class CategoryParameter extends AbstractParameter */ #[ORM\ManyToOne(targetEntity: Category::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/CurrencyParameter.php b/src/Entity/Parameters/CurrencyParameter.php index 3540f5cb..9ab09bed 100644 --- a/src/Entity/Parameters/CurrencyParameter.php +++ b/src/Entity/Parameters/CurrencyParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; use App\Entity\PriceInformations\Currency; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * An attachment attached to a category element. @@ -61,5 +63,6 @@ class CurrencyParameter extends AbstractParameter */ #[ORM\ManyToOne(targetEntity: Currency::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/FootprintParameter.php b/src/Entity/Parameters/FootprintParameter.php index 2a978b04..578ddef3 100644 --- a/src/Entity/Parameters/FootprintParameter.php +++ b/src/Entity/Parameters/FootprintParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; use App\Entity\Parts\Footprint; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; #[UniqueEntity(fields: ['name', 'group', 'element'])] #[ORM\Entity(repositoryClass: ParameterRepository::class)] @@ -58,5 +60,6 @@ class FootprintParameter extends AbstractParameter */ #[ORM\ManyToOne(targetEntity: Footprint::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/GroupParameter.php b/src/Entity/Parameters/GroupParameter.php index 1bc23ea8..7fb5540f 100644 --- a/src/Entity/Parameters/GroupParameter.php +++ b/src/Entity/Parameters/GroupParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; use App\Entity\UserSystem\Group; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; #[UniqueEntity(fields: ['name', 'group', 'element'])] #[ORM\Entity(repositoryClass: ParameterRepository::class)] @@ -58,5 +60,6 @@ class GroupParameter extends AbstractParameter */ #[ORM\ManyToOne(targetEntity: Group::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/ManufacturerParameter.php b/src/Entity/Parameters/ManufacturerParameter.php index 6f33dce8..883a78f4 100644 --- a/src/Entity/Parameters/ManufacturerParameter.php +++ b/src/Entity/Parameters/ManufacturerParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; use App\Entity\Parts\Manufacturer; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; #[UniqueEntity(fields: ['name', 'group', 'element'])] #[ORM\Entity(repositoryClass: ParameterRepository::class)] @@ -58,5 +60,6 @@ class ManufacturerParameter extends AbstractParameter */ #[ORM\ManyToOne(targetEntity: Manufacturer::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/MeasurementUnitParameter.php b/src/Entity/Parameters/MeasurementUnitParameter.php index 7332474e..09ff81ec 100644 --- a/src/Entity/Parameters/MeasurementUnitParameter.php +++ b/src/Entity/Parameters/MeasurementUnitParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; use App\Entity\Parts\MeasurementUnit; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; #[UniqueEntity(fields: ['name', 'group', 'element'])] #[ORM\Entity(repositoryClass: ParameterRepository::class)] @@ -58,5 +60,6 @@ class MeasurementUnitParameter extends AbstractParameter */ #[ORM\ManyToOne(targetEntity: MeasurementUnit::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/PartParameter.php b/src/Entity/Parameters/PartParameter.php index 6c150e6b..91b51c00 100644 --- a/src/Entity/Parameters/PartParameter.php +++ b/src/Entity/Parameters/PartParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; use App\Entity\Parts\Part; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; /** * @see \App\Tests\Entity\Parameters\PartParameterTest @@ -61,5 +63,6 @@ class PartParameter extends AbstractParameter */ #[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/ProjectParameter.php b/src/Entity/Parameters/ProjectParameter.php index 7413ca8a..7c3907cd 100644 --- a/src/Entity/Parameters/ProjectParameter.php +++ b/src/Entity/Parameters/ProjectParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; use App\Entity\ProjectSystem\Project; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; #[UniqueEntity(fields: ['name', 'group', 'element'])] #[ORM\Entity(repositoryClass: ParameterRepository::class)] @@ -58,5 +60,6 @@ class ProjectParameter extends AbstractParameter */ #[ORM\ManyToOne(targetEntity: Project::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/StorelocationParameter.php b/src/Entity/Parameters/StorageLocationParameter.php similarity index 80% rename from src/Entity/Parameters/StorelocationParameter.php rename to src/Entity/Parameters/StorageLocationParameter.php index 098d3a5e..f5cc6415 100644 --- a/src/Entity/Parameters/StorelocationParameter.php +++ b/src/Entity/Parameters/StorageLocationParameter.php @@ -41,22 +41,25 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; #[UniqueEntity(fields: ['name', 'group', 'element'])] #[ORM\Entity(repositoryClass: ParameterRepository::class)] -class StorelocationParameter extends AbstractParameter +class StorageLocationParameter extends AbstractParameter { - final public const ALLOWED_ELEMENT_CLASS = Storelocation::class; + final public const ALLOWED_ELEMENT_CLASS = StorageLocation::class; /** - * @var Storelocation the element this para is associated with + * @var StorageLocation the element this para is associated with */ - #[ORM\ManyToOne(targetEntity: Storelocation::class, inversedBy: 'parameters')] + #[ORM\ManyToOne(targetEntity: StorageLocation::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parameters/SupplierParameter.php b/src/Entity/Parameters/SupplierParameter.php index 5c87ac08..6e42206f 100644 --- a/src/Entity/Parameters/SupplierParameter.php +++ b/src/Entity/Parameters/SupplierParameter.php @@ -41,11 +41,13 @@ declare(strict_types=1); namespace App\Entity\Parameters; -use App\Repository\ParameterRepository; use App\Entity\Base\AbstractDBElement; use App\Entity\Parts\Supplier; +use App\Repository\ParameterRepository; +use App\Serializer\APIPlatform\OverrideClassDenormalizer; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Attribute\Context; #[UniqueEntity(fields: ['name', 'group', 'element'])] #[ORM\Entity(repositoryClass: ParameterRepository::class)] @@ -54,9 +56,10 @@ class SupplierParameter extends AbstractParameter final public const ALLOWED_ELEMENT_CLASS = Supplier::class; /** - * @var Supplier the element this para is associated with + * @var Supplier the element this parameter is associated with */ #[ORM\ManyToOne(targetEntity: Supplier::class, inversedBy: 'parameters')] #[ORM\JoinColumn(name: 'element_id', nullable: false, onDelete: 'CASCADE')] + #[Context(denormalizationContext: [OverrideClassDenormalizer::CONTEXT_KEY => self::ALLOWED_ELEMENT_CLASS])] protected ?AbstractDBElement $element = null; } diff --git a/src/Entity/Parts/AssociationType.php b/src/Entity/Parts/AssociationType.php new file mode 100644 index 00000000..52a56af2 --- /dev/null +++ b/src/Entity/Parts/AssociationType.php @@ -0,0 +1,46 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\Parts; + +/** + * The values of this enums are used to describe how two parts are associated with each other. + */ +enum AssociationType: int +{ + /** A user definable association type, which can be described in the comment field */ + case OTHER = 0; + /** The owning part is compatible with the other part */ + case COMPATIBLE = 1; + /** The owning part supersedes the other part (owner is newer version) */ + case SUPERSEDES = 2; + + /** + * Returns the translation key for this association type. + * @return string + */ + public function getTranslationKey(): string + { + return 'part_association.type.' . strtolower($this->name); + } +} diff --git a/src/Entity/Parts/Category.php b/src/Entity/Parts/Category.php index ac810cf8..99ed3c6d 100644 --- a/src/Entity/Parts/Category.php +++ b/src/Entity/Parts/Category.php @@ -22,8 +22,24 @@ declare(strict_types=1); namespace App\Entity\Parts; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; +use App\Entity\EDA\EDACategoryInfo; use App\Repository\Parts\CategoryRepository; use Doctrine\DBAL\Types\Types; use Doctrine\Common\Collections\ArrayCollection; @@ -43,71 +59,104 @@ use Symfony\Component\Validator\Constraints as Assert; */ #[ORM\Entity(repositoryClass: CategoryRepository::class)] #[ORM\Table(name: '`categories`')] -#[ORM\Index(name: 'category_idx_name', columns: ['name'])] -#[ORM\Index(name: 'category_idx_parent_name', columns: ['parent_id', 'name'])] +#[ORM\Index(columns: ['name'], name: 'category_idx_name')] +#[ORM\Index(columns: ['parent_id', 'name'], name: 'category_idx_parent_name')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@categories.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['category:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['category:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/categories/{id}/children.{_format}', + operations: [ + new GetCollection( + openapi: new Operation(summary: 'Retrieves the children elements of a category.'), + security: 'is_granted("@categories.read")' + ) + ], + uriVariables: [ + 'id' => new Link(fromProperty: 'children', fromClass: Category::class) + ], + normalizationContext: ['groups' => ['category:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] class Category extends AbstractPartsContainingDBElement { - #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id')] + #[Groups(['category:read', 'category:write'])] + #[ApiProperty(readableLink: false, writableLink: false)] protected ?AbstractStructuralDBElement $parent = null; + #[Groups(['category:read', 'category:write'])] + protected string $comment = ''; + /** - * @var string + * @var string The hint which is shown as hint under the partname field, when a part is created in this category. */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'category:read', 'category:write'])] #[ORM\Column(type: Types::TEXT)] protected string $partname_hint = ''; /** - * @var string + * @var string The regular expression which is used to validate the partname of a part in this category. */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'category:read', 'category:write'])] #[ORM\Column(type: Types::TEXT)] protected string $partname_regex = ''; /** - * @var bool + * @var bool Set to true, if the footprints should be disabled for parts this category (not implemented yet). */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'category:read', 'category:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $disable_footprints = false; /** - * @var bool + * @var bool Set to true, if the manufacturers should be disabled for parts this category (not implemented yet). */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'category:read', 'category:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $disable_manufacturers = false; /** - * @var bool + * @var bool Set to true, if the autodatasheets should be disabled for parts this category (not implemented yet). */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'category:read', 'category:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $disable_autodatasheets = false; /** - * @var bool + * @var bool Set to true, if the properties should be disabled for parts this category (not implemented yet). */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'category:read', 'category:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $disable_properties = false; /** - * @var string + * @var string The default description for parts in this category. */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'category:read', 'category:write'])] #[ORM\Column(type: Types::TEXT)] protected string $default_description = ''; /** - * @var string + * @var string The default comment for parts in this category. */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'category:read', 'category:write'])] #[ORM\Column(type: Types::TEXT)] protected string $default_comment = ''; @@ -115,23 +164,43 @@ class Category extends AbstractPartsContainingDBElement * @var Collection */ #[Assert\Valid] - #[Groups(['full'])] - #[ORM\OneToMany(targetEntity: CategoryAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[Groups(['full', 'category:read', 'category:write'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: CategoryAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: CategoryAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['category:read', 'category:write'])] protected ?Attachment $master_picture_attachment = null; /** @var Collection */ #[Assert\Valid] - #[Groups(['full'])] - #[ORM\OneToMany(targetEntity: CategoryParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[Groups(['full', 'category:read', 'category:write'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: CategoryParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] protected Collection $parameters; + #[Groups(['category:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['category:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + #[Assert\Valid] + #[ORM\Embedded(class: EDACategoryInfo::class)] + #[Groups(['full', 'category:read', 'category:write'])] + protected EDACategoryInfo $eda_info; + + public function __construct() + { + parent::__construct(); + $this->children = new ArrayCollection(); + $this->attachments = new ArrayCollection(); + $this->parameters = new ArrayCollection(); + $this->eda_info = new EDACategoryInfo(); + } + public function getPartnameHint(): string { return $this->partname_hint; @@ -224,14 +293,17 @@ class Category extends AbstractPartsContainingDBElement public function setDefaultComment(string $default_comment): self { $this->default_comment = $default_comment; - return $this; } - public function __construct() + + public function getEdaInfo(): EDACategoryInfo { - parent::__construct(); - $this->children = new ArrayCollection(); - $this->attachments = new ArrayCollection(); - $this->parameters = new ArrayCollection(); + return $this->eda_info; + } + + public function setEdaInfo(EDACategoryInfo $eda_info): Category + { + $this->eda_info = $eda_info; + return $this; } } diff --git a/src/Entity/Parts/Footprint.php b/src/Entity/Parts/Footprint.php index 4126a63b..6b043562 100644 --- a/src/Entity/Parts/Footprint.php +++ b/src/Entity/Parts/Footprint.php @@ -22,8 +22,24 @@ declare(strict_types=1); namespace App\Entity\Parts; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; +use App\Entity\EDA\EDAFootprintInfo; use App\Repository\Parts\FootprintRepository; use App\Entity\Base\AbstractStructuralDBElement; use Doctrine\Common\Collections\ArrayCollection; @@ -32,6 +48,7 @@ use App\Entity\Base\AbstractPartsContainingDBElement; use App\Entity\Parameters\FootprintParameter; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; /** @@ -41,28 +58,63 @@ use Symfony\Component\Validator\Constraints as Assert; */ #[ORM\Entity(repositoryClass: FootprintRepository::class)] #[ORM\Table('`footprints`')] -#[ORM\Index(name: 'footprint_idx_name', columns: ['name'])] -#[ORM\Index(name: 'footprint_idx_parent_name', columns: ['parent_id', 'name'])] +#[ORM\Index(columns: ['name'], name: 'footprint_idx_name')] +#[ORM\Index(columns: ['parent_id', 'name'], name: 'footprint_idx_parent_name')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@footprints.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['footprint:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['footprint:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/footprints/{id}/children.{_format}', + operations: [ + new GetCollection( + openapi: new Operation(summary: 'Retrieves the children elements of a footprint.'), + security: 'is_granted("@footprints.read")' + ) + ], + uriVariables: [ + 'id' => new Link(fromProperty: 'children', fromClass: Footprint::class) + ], + normalizationContext: ['groups' => ['footprint:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] class Footprint extends AbstractPartsContainingDBElement { #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id')] + #[Groups(['footprint:read', 'footprint:write'])] + #[ApiProperty(readableLink: false, writableLink: false)] protected ?AbstractStructuralDBElement $parent = null; - #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; + #[Groups(['footprint:read', 'footprint:write'])] + protected string $comment = ''; + /** * @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: FootprintAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: FootprintAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] + #[Groups(['footprint:read', 'footprint:write'])] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: FootprintAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['footprint:read', 'footprint:write'])] protected ?Attachment $master_picture_attachment = null; /** @@ -70,15 +122,36 @@ class Footprint extends AbstractPartsContainingDBElement */ #[ORM\ManyToOne(targetEntity: FootprintAttachment::class)] #[ORM\JoinColumn(name: 'id_footprint_3d')] + #[Groups(['footprint:read', 'footprint:write'])] protected ?FootprintAttachment $footprint_3d = null; /** @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: FootprintParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: FootprintParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] + #[Groups(['footprint:read', 'footprint:write'])] protected Collection $parameters; + #[Groups(['footprint:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['footprint:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + #[Assert\Valid] + #[ORM\Embedded(class: EDAFootprintInfo::class)] + #[Groups(['full', 'footprint:read', 'footprint:write'])] + protected EDAFootprintInfo $eda_info; + + public function __construct() + { + parent::__construct(); + $this->children = new ArrayCollection(); + $this->attachments = new ArrayCollection(); + $this->parameters = new ArrayCollection(); + $this->eda_info = new EDAFootprintInfo(); + } + /**************************************** * Getters ****************************************/ @@ -107,11 +180,15 @@ class Footprint extends AbstractPartsContainingDBElement return $this; } - public function __construct() + + public function getEdaInfo(): EDAFootprintInfo { - parent::__construct(); - $this->children = new ArrayCollection(); - $this->attachments = new ArrayCollection(); - $this->parameters = new ArrayCollection(); + return $this->eda_info; + } + + public function setEdaInfo(EDAFootprintInfo $eda_info): Footprint + { + $this->eda_info = $eda_info; + return $this; } } diff --git a/src/Entity/Parts/InfoProviderReference.php b/src/Entity/Parts/InfoProviderReference.php index 53b81a0a..bfa62f32 100644 --- a/src/Entity/Parts/InfoProviderReference.php +++ b/src/Entity/Parts/InfoProviderReference.php @@ -27,30 +27,36 @@ use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Embeddable; +use Symfony\Component\Serializer\Annotation\Groups; /** * This class represents a reference to a info provider inside a part. + * @see \App\Tests\Entity\Parts\InfoProviderReferenceTest */ #[Embeddable] class InfoProviderReference { /** @var string|null The key referencing the provider used to get this part, or null if it was not provided by a data provider */ - #[Column(type: 'string', nullable: true)] + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['provider_reference:read', 'full'])] private ?string $provider_key = null; /** @var string|null The id of this part inside the provider system or null if the part was not provided by a data provider */ - #[Column(type: 'string', nullable: true)] + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['provider_reference:read', 'full'])] private ?string $provider_id = null; /** * @var string|null The url of this part inside the provider system or null if this info is not existing */ - #[Column(type: 'string', nullable: true)] + #[Column(type: Types::STRING, nullable: true)] + #[Groups(['provider_reference:read', 'full'])] private ?string $provider_url = null; - #[Column(type: Types::DATETIME_MUTABLE, nullable: true, options: ['default' => null])] - private ?\DateTimeInterface $last_updated = null; + #[Column(type: Types::DATETIME_IMMUTABLE, nullable: true, options: ['default' => null])] + #[Groups(['provider_reference:read', 'full'])] + private ?\DateTimeImmutable $last_updated = null; /** * Constructing is forbidden from outside. @@ -89,9 +95,8 @@ class InfoProviderReference /** * Gets the time, when the part was last time updated by the provider. - * @return \DateTimeInterface|null */ - public function getLastUpdated(): ?\DateTimeInterface + public function getLastUpdated(): ?\DateTimeImmutable { return $this->last_updated; } diff --git a/src/Entity/Parts/Manufacturer.php b/src/Entity/Parts/Manufacturer.php index 418b4084..0edf8232 100644 --- a/src/Entity/Parts/Manufacturer.php +++ b/src/Entity/Parts/Manufacturer.php @@ -22,8 +22,23 @@ declare(strict_types=1); namespace App\Entity\Parts; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; use App\Repository\Parts\ManufacturerRepository; use App\Entity\Base\AbstractStructuralDBElement; use Doctrine\Common\Collections\ArrayCollection; @@ -32,6 +47,7 @@ use App\Entity\Base\AbstractCompany; use App\Entity\Parameters\ManufacturerParameter; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; /** @@ -41,35 +57,71 @@ use Symfony\Component\Validator\Constraints as Assert; */ #[ORM\Entity(repositoryClass: ManufacturerRepository::class)] #[ORM\Table('`manufacturers`')] -#[ORM\Index(name: 'manufacturer_name', columns: ['name'])] -#[ORM\Index(name: 'manufacturer_idx_parent_name', columns: ['parent_id', 'name'])] +#[ORM\Index(columns: ['name'], name: 'manufacturer_name')] +#[ORM\Index(columns: ['parent_id', 'name'], name: 'manufacturer_idx_parent_name')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@manufacturers.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['manufacturer:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['manufacturer:write', 'company:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/manufacturers/{id}/children.{_format}', + operations: [ + new GetCollection( + openapi: new Operation(summary: 'Retrieves the children elements of a manufacturer.'), + security: 'is_granted("@manufacturers.read")' + ) + ], + uriVariables: [ + 'id' => new Link(fromProperty: 'children', fromClass: Manufacturer::class) + ], + normalizationContext: ['groups' => ['manufacturer:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] class Manufacturer extends AbstractCompany { #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id')] + #[Groups(['manufacturer:read', 'manufacturer:write'])] + #[ApiProperty(readableLink: false, writableLink: false)] protected ?AbstractStructuralDBElement $parent = null; - #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; /** * @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: ManufacturerAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: ManufacturerAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] + #[Groups(['manufacturer:read', 'manufacturer:write'])] + #[ApiProperty(readableLink: false, writableLink: true)] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: ManufacturerAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['manufacturer:read', 'manufacturer:write'])] + #[ApiProperty(readableLink: false, writableLink: true)] protected ?Attachment $master_picture_attachment = null; /** @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: ManufacturerParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: ManufacturerParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] + #[Groups(['manufacturer:read', 'manufacturer:write'])] + #[ApiProperty(readableLink: false, writableLink: true)] protected Collection $parameters; public function __construct() { diff --git a/src/Entity/Parts/MeasurementUnit.php b/src/Entity/Parts/MeasurementUnit.php index 538d4c57..6dd0b9f2 100644 --- a/src/Entity/Parts/MeasurementUnit.php +++ b/src/Entity/Parts/MeasurementUnit.php @@ -22,8 +22,23 @@ declare(strict_types=1); namespace App\Entity\Parts; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; use App\Repository\Parts\MeasurementUnitRepository; use Doctrine\DBAL\Types\Types; use App\Entity\Base\AbstractStructuralDBElement; @@ -36,6 +51,7 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Constraints\Length; /** * This unit represents the unit in which the amount of parts in stock are measured. @@ -46,8 +62,36 @@ use Symfony\Component\Validator\Constraints as Assert; #[UniqueEntity('unit')] #[ORM\Entity(repositoryClass: MeasurementUnitRepository::class)] #[ORM\Table(name: '`measurement_units`')] -#[ORM\Index(name: 'unit_idx_name', columns: ['name'])] -#[ORM\Index(name: 'unit_idx_parent_name', columns: ['parent_id', 'name'])] +#[ORM\Index(columns: ['name'], name: 'unit_idx_name')] +#[ORM\Index(columns: ['parent_id', 'name'], name: 'unit_idx_parent_name')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@measurement_units.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['measurement_unit:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['measurement_unit:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/measurement_units/{id}/children.{_format}', + operations: [ + new GetCollection( + openapi: new Operation(summary: 'Retrieves the children elements of a MeasurementUnit.'), + security: 'is_granted("@measurement_units.read")' + ) + ], + uriVariables: [ + 'id' => new Link(fromProperty: 'children', fromClass: MeasurementUnit::class) + ], + normalizationContext: ['groups' => ['measurement_unit:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "unit"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] class MeasurementUnit extends AbstractPartsContainingDBElement { /** @@ -55,16 +99,19 @@ class MeasurementUnit extends AbstractPartsContainingDBElement * or m (for meters). */ #[Assert\Length(max: 10)] - #[Groups(['extended', 'full', 'import'])] - #[ORM\Column(type: Types::STRING, name: 'unit', nullable: true)] + #[Groups(['simple', 'extended', 'full', 'import', 'measurement_unit:read', 'measurement_unit:write'])] + #[ORM\Column(name: 'unit', type: Types::STRING, nullable: true)] protected ?string $unit = null; + #[Groups(['measurement_unit:read', 'measurement_unit:write'])] + protected string $comment = ''; + /** * @var bool Determines if the amount value associated with this unit should be treated as integer. * Set to false, to measure continuous sizes likes masses or lengths. */ - #[Groups(['extended', 'full', 'import'])] - #[ORM\Column(type: Types::BOOLEAN, name: 'is_integer')] + #[Groups(['simple', 'extended', 'full', 'import', 'measurement_unit:read', 'measurement_unit:write'])] + #[ORM\Column(name: 'is_integer', type: Types::BOOLEAN)] protected bool $is_integer = false; /** @@ -72,37 +119,48 @@ class MeasurementUnit extends AbstractPartsContainingDBElement * Useful for sizes like meters. For this the unit must be set */ #[Assert\Expression('this.isUseSIPrefix() == false or this.getUnit() != null', message: 'validator.measurement_unit.use_si_prefix_needs_unit')] - #[Groups(['full', 'import'])] - #[ORM\Column(type: Types::BOOLEAN, name: 'use_si_prefix')] + #[Groups(['simple', 'full', 'import', 'measurement_unit:read', 'measurement_unit:write'])] + #[ORM\Column(name: 'use_si_prefix', type: Types::BOOLEAN)] protected bool $use_si_prefix = false; - #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent', cascade: ['persist'])] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class, cascade: ['persist'])] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id')] + #[Groups(['measurement_unit:read', 'measurement_unit:write'])] + #[ApiProperty(readableLink: false, writableLink: false)] protected ?AbstractStructuralDBElement $parent = null; /** * @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: MeasurementUnitAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: MeasurementUnitAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] + #[Groups(['measurement_unit:read', 'measurement_unit:write'])] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: MeasurementUnitAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['measurement_unit:read', 'measurement_unit:write'])] protected ?Attachment $master_picture_attachment = null; /** @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: MeasurementUnitParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: MeasurementUnitParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] + #[Groups(['measurement_unit:read', 'measurement_unit:write'])] protected Collection $parameters; + #[Groups(['measurement_unit:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['measurement_unit:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + /** * @return string */ diff --git a/src/Entity/Parts/Part.php b/src/Entity/Parts/Part.php index e425e145..14a7903f 100644 --- a/src/Entity/Parts/Part.php +++ b/src/Entity/Parts/Part.php @@ -22,21 +22,41 @@ declare(strict_types=1); namespace App\Entity\Parts; -use App\Entity\Attachments\AttachmentTypeAttachment; -use App\Repository\PartRepository; -use Doctrine\DBAL\Types\Types; +use App\ApiPlatform\Filter\TagFilter; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Doctrine\Orm\Filter\RangeFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\EntityFilter; +use App\ApiPlatform\Filter\LikeFilter; +use App\ApiPlatform\Filter\PartStoragelocationFilter; use App\Entity\Attachments\Attachment; use App\Entity\Attachments\AttachmentContainingDBElement; use App\Entity\Attachments\PartAttachment; -use App\Entity\Parts\PartTraits\ProjectTrait; +use App\Entity\EDA\EDAPartInfo; use App\Entity\Parameters\ParametersTrait; use App\Entity\Parameters\PartParameter; use App\Entity\Parts\PartTraits\AdvancedPropertyTrait; +use App\Entity\Parts\PartTraits\AssociationTrait; use App\Entity\Parts\PartTraits\BasicPropertyTrait; +use App\Entity\Parts\PartTraits\EDATrait; use App\Entity\Parts\PartTraits\InstockTrait; use App\Entity\Parts\PartTraits\ManufacturerTrait; use App\Entity\Parts\PartTraits\OrderTrait; -use DateTime; +use App\Entity\Parts\PartTraits\ProjectTrait; +use App\EntityListeners\TreeCacheInvalidationListener; +use App\Repository\PartRepository; +use App\Validator\Constraints\UniqueObjectCollection; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; @@ -56,10 +76,34 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; */ #[UniqueEntity(fields: ['ipn'], message: 'part.ipn.must_be_unique')] #[ORM\Entity(repositoryClass: PartRepository::class)] +#[ORM\EntityListeners([TreeCacheInvalidationListener::class])] #[ORM\Table('`parts`')] -#[ORM\Index(name: 'parts_idx_datet_name_last_id_needs', columns: ['datetime_added', 'name', 'last_modified', 'id', 'needs_review'])] -#[ORM\Index(name: 'parts_idx_name', columns: ['name'])] -#[ORM\Index(name: 'parts_idx_ipn', columns: ['ipn'])] +#[ORM\Index(columns: ['datetime_added', 'name', 'last_modified', 'id', 'needs_review'], name: 'parts_idx_datet_name_last_id_needs')] +#[ORM\Index(columns: ['name'], name: 'parts_idx_name')] +#[ORM\Index(columns: ['ipn'], name: 'parts_idx_ipn')] +#[ApiResource( + operations: [ + new Get(normalizationContext: ['groups' => ['part:read', 'provider_reference:read', 'api:basic:read', 'part_lot:read', + 'orderdetail:read', 'pricedetail:read', 'parameter:read', 'attachment:read', 'eda_info:read'], + 'openapi_definition_name' => 'Read', + ], security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@parts.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['part:read', 'provider_reference:read', 'api:basic:read', 'part_lot:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['part:write', 'api:basic:write', 'eda_info:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(EntityFilter::class, properties: ["category", "footprint", "manufacturer", "partUnit"])] +#[ApiFilter(PartStoragelocationFilter::class, properties: ["storage_location"])] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "description", "ipn", "manufacturer_product_number"])] +#[ApiFilter(TagFilter::class, properties: ["tags"])] +#[ApiFilter(BooleanFilter::class, properties: ["favorite" , "needs_review"])] +#[ApiFilter(RangeFilter::class, properties: ["mass", "minamount"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] class Part extends AttachmentContainingDBElement { use AdvancedPropertyTrait; @@ -70,13 +114,16 @@ class Part extends AttachmentContainingDBElement use OrderTrait; use ParametersTrait; use ProjectTrait; + use AssociationTrait; + use EDATrait; /** @var Collection */ #[Assert\Valid] - #[Groups(['full'])] - #[ORM\OneToMany(targetEntity: PartParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[Groups(['full', 'part:read', 'part:write', 'import'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: PartParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] + #[UniqueObjectCollection(fields: ['name', 'group', 'element'])] protected Collection $parameters; @@ -84,19 +131,19 @@ class Part extends AttachmentContainingDBElement * Overridden properties * (They are defined here and not in a trait, to avoid conflicts). ****************************************************************/ + /** * @var string The name of this part */ - #[ORM\Column(type: Types::STRING)] protected string $name = ''; /** * @var Collection */ #[Assert\Valid] - #[Groups(['full'])] - #[ORM\OneToMany(targetEntity: PartAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[Groups(['full', 'part:read', 'part:write'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: PartAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $attachments; /** @@ -105,8 +152,15 @@ class Part extends AttachmentContainingDBElement #[Assert\Expression('value == null or value.isPicture()', message: 'part.master_attachment.must_be_picture')] #[ORM\ManyToOne(targetEntity: PartAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['part:read', 'part:write'])] protected ?Attachment $master_picture_attachment = null; + #[Groups(['part:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['part:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + public function __construct() { $this->attachments = new ArrayCollection(); @@ -116,8 +170,12 @@ class Part extends AttachmentContainingDBElement $this->parameters = new ArrayCollection(); $this->project_bom_entries = new ArrayCollection(); + $this->associated_parts_as_owner = new ArrayCollection(); + $this->associated_parts_as_other = new ArrayCollection(); + //By default, the part has no provider $this->providerReference = InfoProviderReference::noProvider(); + $this->eda_info = new EDAPartInfo(); } public function __clone() @@ -144,8 +202,16 @@ class Part extends AttachmentContainingDBElement $this->addParameter(clone $parameter); } + //Deep clone the owned part associations (the owned ones make not much sense without the owner) + $ownedAssociations = $this->associated_parts_as_owner; + $this->associated_parts_as_owner = new ArrayCollection(); + foreach ($ownedAssociations as $association) { + $this->addAssociatedPartsAsOwner(clone $association); + } + //Deep clone info provider $this->providerReference = clone $this->providerReference; + $this->eda_info = clone $this->eda_info; } parent::__clone(); } diff --git a/src/Entity/Parts/PartAssociation.php b/src/Entity/Parts/PartAssociation.php new file mode 100644 index 00000000..32017488 --- /dev/null +++ b/src/Entity/Parts/PartAssociation.php @@ -0,0 +1,235 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\Parts; + +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; +use App\Entity\Contracts\TimeStampableInterface; +use App\Repository\DBElementRepository; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; +use App\Entity\Base\AbstractDBElement; +use App\Entity\Base\TimestampTrait; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Constraints\Length; + +/** + * This entity describes a part association, which is a semantic connection between two parts. + * For example, a part association can be used to describe that a part is a replacement for another part. + * @see \App\Tests\Entity\Parts\PartAssociationTest + */ +#[ORM\Entity(repositoryClass: DBElementRepository::class)] +#[ORM\HasLifecycleCallbacks] +#[UniqueEntity(fields: ['other', 'owner', 'type'], message: 'validator.part_association.already_exists')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@parts.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['part_assoc:read', 'part_assoc:read:standalone', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['part_assoc:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["other_type", "comment"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['comment', 'addedDate', 'lastModified'])] +class PartAssociation extends AbstractDBElement implements TimeStampableInterface +{ + use TimestampTrait; + + /** + * @var AssociationType The type of this association (how the two parts are related) + */ + #[ORM\Column(type: Types::SMALLINT, enumType: AssociationType::class)] + #[Groups(['part_assoc:read', 'part_assoc:write'])] + protected AssociationType $type = AssociationType::OTHER; + + /** + * @var string|null A user definable association type, which can be described in the comment field, which + * is used if the type is OTHER + */ + #[ORM\Column(type: Types::STRING, length: 255, nullable: true)] + #[Assert\Expression("this.getType().value !== 0 or this.getOtherType() !== null", + message: 'validator.part_association.must_set_an_value_if_type_is_other')] + #[Groups(['part_assoc:read', 'part_assoc:write'])] + #[Length(max: 255)] + protected ?string $other_type = null; + + /** + * @var string|null A comment describing this association further. + */ + #[ORM\Column(type: Types::TEXT, nullable: true)] + #[Groups(['part_assoc:read', 'part_assoc:write'])] + protected ?string $comment = null; + + /** + * @var Part|null The part which "owns" this association, e.g. the part which is a replacement for another part + */ + #[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'associated_parts_as_owner')] + #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] + #[Assert\NotNull] + #[Groups(['part_assoc:read:standalone', 'part_assoc:write'])] + protected ?Part $owner = null; + + /** + * @var Part|null The part which is "owned" by this association, e.g. the part which is replaced by another part + */ + #[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'associated_parts_as_other')] + #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] + #[Assert\NotNull] + #[Assert\Expression("this.getOwner() !== this.getOther()", + message: 'validator.part_association.part_cannot_be_associated_with_itself')] + #[Groups(['part_assoc:read', 'part_assoc:write'])] + protected ?Part $other = null; + + /** + * Returns the (semantic) relation type of this association as an AssociationType enum value. + * If the type is set to OTHER, then the other_type field value is used for the user defined type. + * @return AssociationType + */ + public function getType(): AssociationType + { + return $this->type; + } + + /** + * Sets the (semantic) relation type of this association as an AssociationType enum value. + * @param AssociationType $type + * @return $this + */ + public function setType(AssociationType $type): PartAssociation + { + $this->type = $type; + return $this; + } + + /** + * Returns a comment, which describes this association further. + * @return string|null + */ + public function getComment(): ?string + { + return $this->comment; + } + + /** + * Sets a comment, which describes this association further. + * @param string|null $comment + * @return $this + */ + public function setComment(?string $comment): PartAssociation + { + $this->comment = $comment; + return $this; + } + + /** + * Returns the part which "owns" this association, e.g. the part which is a replacement for another part. + * @return Part|null + */ + public function getOwner(): ?Part + { + return $this->owner; + } + + /** + * Sets the part which "owns" this association, e.g. the part which is a replacement for another part. + * @param Part|null $owner + * @return $this + */ + public function setOwner(?Part $owner): PartAssociation + { + $this->owner = $owner; + return $this; + } + + /** + * Returns the part which is "owned" by this association, e.g. the part which is replaced by another part. + * @return Part|null + */ + public function getOther(): ?Part + { + return $this->other; + } + + /** + * Sets the part which is "owned" by this association, e.g. the part which is replaced by another part. + * @param Part|null $other + * @return $this + */ + public function setOther(?Part $other): PartAssociation + { + $this->other = $other; + return $this; + } + + /** + * Returns the user defined association type, which is used if the type is set to OTHER. + * @return string|null + */ + public function getOtherType(): ?string + { + return $this->other_type; + } + + /** + * Sets the user defined association type, which is used if the type is set to OTHER. + * @param string|null $other_type + * @return $this + */ + public function setOtherType(?string $other_type): PartAssociation + { + $this->other_type = $other_type; + return $this; + } + + /** + * Returns the translation key for the type of this association. + * If the type is set to OTHER, then the other_type field value is used. + * @return string + */ + public function getTypeTranslationKey(): string + { + if ($this->type === AssociationType::OTHER) { + return $this->other_type ?? 'Unknown'; + } + return $this->type->getTranslationKey(); + } + +} \ No newline at end of file diff --git a/src/Entity/Parts/PartLot.php b/src/Entity/Parts/PartLot.php index e552c06a..d893e6de 100644 --- a/src/Entity/Parts/PartLot.php +++ b/src/Entity/Parts/PartLot.php @@ -22,7 +22,22 @@ declare(strict_types=1); namespace App\Entity\Parts; -use App\Repository\PartLotRepository; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Doctrine\Orm\Filter\RangeFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; +use App\Validator\Constraints\Year2038BugWorkaround; use Doctrine\DBAL\Types\Types; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\TimestampTrait; @@ -34,8 +49,10 @@ use App\Validator\Constraints\ValidPartLot; use DateTime; use Doctrine\ORM\Mapping as ORM; use Exception; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Context\ExecutionContextInterface; /** @@ -47,9 +64,28 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; #[ORM\Entity] #[ORM\HasLifecycleCallbacks] #[ORM\Table(name: 'part_lots')] -#[ORM\Index(name: 'part_lots_idx_instock_un_expiration_id_part', columns: ['instock_unknown', 'expiration_date', 'id_part'])] -#[ORM\Index(name: 'part_lots_idx_needs_refill', columns: ['needs_refill'])] +#[ORM\Index(columns: ['instock_unknown', 'expiration_date', 'id_part'], name: 'part_lots_idx_instock_un_expiration_id_part')] +#[ORM\Index(columns: ['needs_refill'], name: 'part_lots_idx_needs_refill')] +#[ORM\Index(columns: ['vendor_barcode'], name: 'part_lots_idx_barcode')] #[ValidPartLot] +#[UniqueEntity(['user_barcode'], message: 'validator.part_lot.vendor_barcode_must_be_unique')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@parts.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['part_lot:read', 'part_lot:read:standalone', 'api:basic:read', 'pricedetail:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['part_lot:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["description", "comment"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(BooleanFilter::class, properties: ['instock_unknown', 'needs_refill'])] +#[ApiFilter(RangeFilter::class, properties: ['amount'])] +#[ApiFilter(OrderFilter::class, properties: ['description', 'comment', 'addedDate', 'lastModified'])] class PartLot extends AbstractDBElement implements TimeStampableInterface, NamedElementInterface { use TimestampTrait; @@ -57,53 +93,54 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named /** * @var string A short description about this lot, shown in table */ - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])] #[ORM\Column(type: Types::TEXT)] protected string $description = ''; /** * @var string a comment stored with this lot */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'part_lot:read', 'part_lot:write'])] #[ORM\Column(type: Types::TEXT)] protected string $comment = ''; /** - * @var \DateTimeInterface|null Set a time until when the lot must be used. + * @var \DateTimeImmutable|null Set a time until when the lot must be used. * Set to null, if the lot can be used indefinitely. */ - #[Groups(['extended', 'full', 'import'])] - #[ORM\Column(type: Types::DATETIME_MUTABLE, name: 'expiration_date', nullable: true)] - protected ?\DateTimeInterface $expiration_date = null; + #[Groups(['extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])] + #[ORM\Column(name: 'expiration_date', type: Types::DATETIME_IMMUTABLE, nullable: true)] + #[Year2038BugWorkaround] + protected ?\DateTimeImmutable $expiration_date = null; /** - * @var Storelocation|null The storelocation of this lot + * @var StorageLocation|null The storelocation of this lot */ - #[Groups(['simple', 'extended', 'full', 'import'])] - #[ORM\ManyToOne(targetEntity: Storelocation::class, fetch: 'EAGER')] + #[Groups(['simple', 'extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])] + #[ORM\ManyToOne(targetEntity: StorageLocation::class, fetch: 'EAGER')] #[ORM\JoinColumn(name: 'id_store_location')] - #[Selectable()] - protected ?Storelocation $storage_location = null; + #[Selectable] + protected ?StorageLocation $storage_location = null; /** * @var bool If this is set to true, the instock amount is marked as not known */ - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $instock_unknown = false; /** - * @var float For continuous sizes (length, volume, etc.) the instock is saved here. + * @var float The amount of parts in this lot. For integer-quantities this value is rounded to the next integer. */ #[Assert\PositiveOrZero] - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])] #[ORM\Column(type: Types::FLOAT)] protected float $amount = 0.0; /** * @var bool determines if this lot was manually marked for refilling */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $needs_refill = false; @@ -113,6 +150,8 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named #[Assert\NotNull] #[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'partLots')] #[ORM\JoinColumn(name: 'id_part', nullable: false, onDelete: 'CASCADE')] + #[Groups(['part_lot:read:standalone', 'part_lot:write'])] + #[ApiProperty(writableLink: false)] protected ?Part $part = null; /** @@ -120,8 +159,18 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named */ #[ORM\ManyToOne(targetEntity: User::class)] #[ORM\JoinColumn(name: 'id_owner', onDelete: 'SET NULL')] + #[Groups(['part_lot:read', 'part_lot:write'])] + #[ApiProperty(writableLink: false)] protected ?User $owner = null; + /** + * @var string|null The content of the barcode of this part lot (e.g. a barcode on the package put by the vendor) + */ + #[ORM\Column(name: "vendor_barcode", type: Types::STRING, nullable: true)] + #[Groups(['part_lot:read', 'part_lot:write'])] + #[Length(max: 255)] + protected ?string $user_barcode = null; + public function __clone() { if ($this->id) { @@ -136,7 +185,6 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named * * @return bool|null True, if the part lot is expired. Returns null, if no expiration date was set. * - * @throws Exception If an error with the DateTime occurs */ public function isExpired(): ?bool { @@ -145,7 +193,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named } //Check if the expiration date is bigger then current time - return $this->expiration_date < new DateTime('now'); + return $this->expiration_date < new \DateTimeImmutable('now'); } /** @@ -187,7 +235,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named /** * Gets the expiration date for the part lot. Returns null, if no expiration date was set. */ - public function getExpirationDate(): ?\DateTimeInterface + public function getExpirationDate(): ?\DateTimeImmutable { return $this->expiration_date; } @@ -197,7 +245,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named * * */ - public function setExpirationDate(?\DateTimeInterface $expiration_date): self + public function setExpirationDate(?\DateTimeImmutable $expiration_date): self { $this->expiration_date = $expiration_date; @@ -207,9 +255,9 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named /** * Gets the storage location, where this part lot is stored. * - * @return Storelocation|null The store location where this part is stored + * @return StorageLocation|null The store location where this part is stored */ - public function getStorageLocation(): ?Storelocation + public function getStorageLocation(): ?StorageLocation { return $this->storage_location; } @@ -217,7 +265,7 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named /** * Sets the storage location, where this part lot is stored. */ - public function setStorageLocation(?Storelocation $storage_location): self + public function setStorageLocation(?StorageLocation $storage_location): self { $this->storage_location = $storage_location; @@ -322,6 +370,29 @@ class PartLot extends AbstractDBElement implements TimeStampableInterface, Named return $this->description; } + /** + * The content of the barcode of this part lot (e.g. a barcode on the package put by the vendor), or + * null if no barcode is set. + * @return string|null + */ + public function getUserBarcode(): ?string + { + return $this->user_barcode; + } + + /** + * Set the content of the barcode of this part lot (e.g. a barcode on the package put by the vendor). + * @param string|null $user_barcode + * @return $this + */ + public function setUserBarcode(?string $user_barcode): PartLot + { + $this->user_barcode = $user_barcode; + return $this; + } + + + #[Assert\Callback] public function validate(ExecutionContextInterface $context, $payload): void { diff --git a/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php b/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php index 648cf2a5..230ba7b7 100644 --- a/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php +++ b/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php @@ -28,6 +28,7 @@ use App\Entity\Parts\Part; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Constraints\Length; /** * Advanced properties of a part, not related to a more specific group. @@ -37,22 +38,22 @@ trait AdvancedPropertyTrait /** * @var bool Determines if this part entry needs review (for example, because it is work in progress) */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $needs_review = false; /** - * @var string a comma separated list of tags, associated with the part + * @var string A comma separated list of tags, associated with the part */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::TEXT)] protected string $tags = ''; /** - * @var float|null how much a single part unit weighs in grams + * @var float|null How much a single part unit weighs in grams */ #[Assert\PositiveOrZero] - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::FLOAT, nullable: true)] protected ?float $mass = null; @@ -60,14 +61,16 @@ trait AdvancedPropertyTrait * @var string|null The internal part number of the part */ #[Assert\Length(max: 100)] - #[Groups(['extended', 'full', 'import'])] - #[ORM\Column(type: Types::STRING, length: 100, nullable: true, unique: true)] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] + #[ORM\Column(type: Types::STRING, length: 100, unique: true, nullable: true)] + #[Length(max: 100)] protected ?string $ipn = null; /** * @var InfoProviderReference The reference to the info provider, that provided the information about this part */ #[ORM\Embedded(class: InfoProviderReference::class, columnPrefix: 'provider_reference_')] + #[Groups(['full', 'part:read'])] protected InfoProviderReference $providerReference; /** diff --git a/src/Entity/Parts/PartTraits/AssociationTrait.php b/src/Entity/Parts/PartTraits/AssociationTrait.php new file mode 100644 index 00000000..bb80fc5a --- /dev/null +++ b/src/Entity/Parts/PartTraits/AssociationTrait.php @@ -0,0 +1,110 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\Parts\PartTraits; + +use App\Entity\Parts\PartAssociation; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints\Valid; +use Doctrine\ORM\Mapping as ORM; + +trait AssociationTrait +{ + /** + * @var Collection All associations where this part is the owner + */ + #[Valid] + #[ORM\OneToMany(mappedBy: 'owner', targetEntity: PartAssociation::class, + cascade: ['persist', 'remove'], orphanRemoval: true)] + #[Groups(['part:read', 'part:write', 'full'])] + protected Collection $associated_parts_as_owner; + + /** + * @var Collection All associations where this part is the owned/other part + */ + #[Valid] + #[ORM\OneToMany(mappedBy: 'other', targetEntity: PartAssociation::class, + cascade: ['persist', 'remove'], orphanRemoval: true)] + #[Groups(['part:read'])] + protected Collection $associated_parts_as_other; + + /** + * Returns all associations where this part is the owner. + * @return Collection + */ + public function getAssociatedPartsAsOwner(): Collection + { + return $this->associated_parts_as_owner; + } + + /** + * Add a new association where this part is the owner. + * @param PartAssociation $association + * @return $this + */ + public function addAssociatedPartsAsOwner(PartAssociation $association): self + { + //Ensure that the association is really owned by this part + $association->setOwner($this); + + $this->associated_parts_as_owner->add($association); + return $this; + } + + /** + * Remove an association where this part is the owner. + * @param PartAssociation $association + * @return $this + */ + public function removeAssociatedPartsAsOwner(PartAssociation $association): self + { + $this->associated_parts_as_owner->removeElement($association); + return $this; + } + + /** + * Returns all associations where this part is the owned/other part. + * If you want to modify the association, do it on the owning part + * @return Collection + */ + public function getAssociatedPartsAsOther(): Collection + { + return $this->associated_parts_as_other; + } + + /** + * Returns all associations where this part is the owned or other part. + * @return Collection + */ + public function getAssociatedPartsAll(): Collection + { + return new ArrayCollection( + array_merge( + $this->associated_parts_as_owner->toArray(), + $this->associated_parts_as_other->toArray() + ) + ); + } +} \ No newline at end of file diff --git a/src/Entity/Parts/PartTraits/BasicPropertyTrait.php b/src/Entity/Parts/PartTraits/BasicPropertyTrait.php index b0f593d6..7e483ed2 100644 --- a/src/Entity/Parts/PartTraits/BasicPropertyTrait.php +++ b/src/Entity/Parts/PartTraits/BasicPropertyTrait.php @@ -35,14 +35,14 @@ trait BasicPropertyTrait /** * @var string A text describing what this part does */ - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::TEXT)] protected string $description = ''; /** * @var string A comment/note related to this part */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::TEXT)] protected string $comment = ''; @@ -55,7 +55,7 @@ trait BasicPropertyTrait /** * @var bool true, if the part is marked as favorite */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $favorite = false; @@ -64,8 +64,8 @@ trait BasicPropertyTrait * Every part must have a category. */ #[Assert\NotNull(message: 'validator.select_valid_category')] - #[Selectable()] - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Selectable] + #[Groups(['simple', 'extended', 'full', 'import', "part:read", "part:write"])] #[ORM\ManyToOne(targetEntity: Category::class)] #[ORM\JoinColumn(name: 'id_category', nullable: false)] protected ?Category $category = null; @@ -73,10 +73,10 @@ trait BasicPropertyTrait /** * @var Footprint|null The footprint of this part (e.g. DIP8) */ - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\ManyToOne(targetEntity: Footprint::class)] #[ORM\JoinColumn(name: 'id_footprint')] - #[Selectable()] + #[Selectable] protected ?Footprint $footprint = null; /** diff --git a/src/Entity/Parts/PartTraits/EDATrait.php b/src/Entity/Parts/PartTraits/EDATrait.php new file mode 100644 index 00000000..313552e7 --- /dev/null +++ b/src/Entity/Parts/PartTraits/EDATrait.php @@ -0,0 +1,53 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\Parts\PartTraits; + +use App\Entity\EDA\EDAPartInfo; +use Doctrine\ORM\Mapping\Embedded; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints\Valid; + +trait EDATrait +{ + #[Valid] + #[Embedded(class: EDAPartInfo::class)] + #[Groups(['full', 'part:read', 'part:write', 'import'])] + protected EDAPartInfo $eda_info; + + public function getEdaInfo(): EDAPartInfo + { + return $this->eda_info; + } + + public function setEdaInfo(?EDAPartInfo $eda_info): self + { + if ($eda_info !== null) { + //Do a clone, to ensure that the property is updated in the database + $eda_info = clone $eda_info; + } + + $this->eda_info = $eda_info; + return $this; + } +} \ No newline at end of file diff --git a/src/Entity/Parts/PartTraits/InstockTrait.php b/src/Entity/Parts/PartTraits/InstockTrait.php index 068173a7..08b070f3 100644 --- a/src/Entity/Parts/PartTraits/InstockTrait.php +++ b/src/Entity/Parts/PartTraits/InstockTrait.php @@ -22,12 +22,14 @@ declare(strict_types=1); namespace App\Entity\Parts\PartTraits; +use Doctrine\Common\Collections\Criteria; use Doctrine\DBAL\Types\Types; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\PartLot; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Attribute\SerializedName; use Symfony\Component\Validator\Constraints as Assert; /** @@ -36,12 +38,12 @@ use Symfony\Component\Validator\Constraints as Assert; trait InstockTrait { /** - * @var Collection|PartLot[] A list of part lots where this part is stored + * @var Collection A list of part lots where this part is stored */ #[Assert\Valid] - #[Groups(['extended', 'full', 'import'])] - #[ORM\OneToMany(targetEntity: PartLot::class, mappedBy: 'part', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['amount' => 'DESC'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] + #[ORM\OneToMany(mappedBy: 'part', targetEntity: PartLot::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['amount' => Criteria::DESC])] protected Collection $partLots; /** @@ -49,14 +51,14 @@ trait InstockTrait * Given in the partUnit. */ #[Assert\PositiveOrZero] - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::FLOAT)] protected float $minamount = 0; /** * @var ?MeasurementUnit the unit in which the part's amount is measured */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\ManyToOne(targetEntity: MeasurementUnit::class)] #[ORM\JoinColumn(name: 'id_part_unit')] protected ?MeasurementUnit $partUnit = null; @@ -181,6 +183,8 @@ trait InstockTrait * * @return float The amount of parts given in partUnit */ + #[Groups(['simple', 'extended', 'full', 'part:read'])] + #[SerializedName('total_instock')] public function getAmountSum(): float { //TODO: Find a method to do this natively in SQL, the current method could be a bit slow diff --git a/src/Entity/Parts/PartTraits/ManufacturerTrait.php b/src/Entity/Parts/PartTraits/ManufacturerTrait.php index 97ef246b..5d7f8749 100644 --- a/src/Entity/Parts/PartTraits/ManufacturerTrait.php +++ b/src/Entity/Parts/PartTraits/ManufacturerTrait.php @@ -30,6 +30,7 @@ use App\Validator\Constraints\Selectable; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Constraints\Length; /** * In this trait all manufacturer related properties of a part are collected (like MPN, manufacturer URL). @@ -39,31 +40,32 @@ trait ManufacturerTrait /** * @var Manufacturer|null The manufacturer of this part */ - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\ManyToOne(targetEntity: Manufacturer::class)] #[ORM\JoinColumn(name: 'id_manufacturer')] - #[Selectable()] + #[Selectable] protected ?Manufacturer $manufacturer = null; /** - * @var string the url to the part on the manufacturer's homepage + * @var string The url to the part on the manufacturer's homepage */ #[Assert\Url] - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::TEXT)] protected string $manufacturer_product_url = ''; /** * @var string The product number used by the manufacturer. If this is set to "", the name field is used. */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::STRING)] + #[Length(max: 255)] protected string $manufacturer_product_number = ''; /** * @var ManufacturingStatus|null The production status of this part. Can be one of the specified ones. */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] #[ORM\Column(type: Types::STRING, length: 255, nullable: true, enumType: ManufacturingStatus::class)] protected ?ManufacturingStatus $manufacturing_status = ManufacturingStatus::NOT_SET; diff --git a/src/Entity/Parts/PartTraits/OrderTrait.php b/src/Entity/Parts/PartTraits/OrderTrait.php index a442298c..2c142016 100644 --- a/src/Entity/Parts/PartTraits/OrderTrait.php +++ b/src/Entity/Parts/PartTraits/OrderTrait.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace App\Entity\Parts\PartTraits; +use Doctrine\Common\Collections\Criteria; use Doctrine\DBAL\Types\Types; use App\Entity\PriceInformations\Orderdetail; use Symfony\Component\Serializer\Annotation\Groups; @@ -36,12 +37,12 @@ use Doctrine\ORM\Mapping as ORM; trait OrderTrait { /** - * @var Collection the details about how and where you can order this part + * @var Collection The details about how and where you can order this part */ #[Assert\Valid] - #[Groups(['extended', 'full', 'import'])] - #[ORM\OneToMany(targetEntity: Orderdetail::class, mappedBy: 'part', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['supplierpartnr' => 'ASC'])] + #[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])] + #[ORM\OneToMany(mappedBy: 'part', targetEntity: Orderdetail::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['supplierpartnr' => Criteria::ASC])] protected Collection $orderdetails; /** diff --git a/src/Entity/Parts/PartTraits/ProjectTrait.php b/src/Entity/Parts/PartTraits/ProjectTrait.php index 51208b6a..45719377 100644 --- a/src/Entity/Parts/PartTraits/ProjectTrait.php +++ b/src/Entity/Parts/PartTraits/ProjectTrait.php @@ -6,25 +6,22 @@ namespace App\Entity\Parts\PartTraits; use App\Entity\ProjectSystem\Project; use App\Entity\ProjectSystem\ProjectBOMEntry; -use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Serializer\Annotation\Groups; trait ProjectTrait { /** * @var Collection $project_bom_entries */ - /** - * @var Collection $project_bom_entries - */ - #[ORM\OneToMany(targetEntity: ProjectBOMEntry::class, mappedBy: 'part', cascade: ['remove'], orphanRemoval: true)] + #[ORM\OneToMany(mappedBy: 'part', targetEntity: ProjectBOMEntry::class, cascade: ['remove'], orphanRemoval: true)] protected Collection $project_bom_entries; /** * @var Project|null If a project is set here, then this part is special and represents the builds of a project. */ - #[ORM\OneToOne(targetEntity: Project::class, inversedBy: 'build_part')] + #[ORM\OneToOne(inversedBy: 'build_part', targetEntity: Project::class)] #[ORM\JoinColumn] protected ?Project $built_project = null; @@ -42,6 +39,7 @@ trait ProjectTrait * Checks whether this part represents the builds of a project * @return bool True if it represents the builds, false if not */ + #[Groups(['part:read'])] public function isProjectBuildPart(): bool { return $this->built_project !== null; diff --git a/src/Entity/Parts/Storelocation.php b/src/Entity/Parts/StorageLocation.php similarity index 60% rename from src/Entity/Parts/Storelocation.php rename to src/Entity/Parts/StorageLocation.php index f58f807d..6c455ae5 100644 --- a/src/Entity/Parts/Storelocation.php +++ b/src/Entity/Parts/StorageLocation.php @@ -22,14 +22,30 @@ declare(strict_types=1); namespace App\Entity\Parts; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Entity\Attachments\Attachment; use App\Repository\Parts\StorelocationRepository; use Doctrine\DBAL\Types\Types; use Doctrine\Common\Collections\ArrayCollection; -use App\Entity\Attachments\StorelocationAttachment; +use App\Entity\Attachments\StorageLocationAttachment; use App\Entity\Base\AbstractPartsContainingDBElement; use App\Entity\Base\AbstractStructuralDBElement; -use App\Entity\Parameters\StorelocationParameter; +use App\Entity\Parameters\StorageLocationParameter; use App\Entity\UserSystem\User; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; @@ -38,54 +54,89 @@ use Symfony\Component\Validator\Constraints as Assert; /** * This entity represents a storage location, where parts can be stored. - * @extends AbstractPartsContainingDBElement + * @extends AbstractPartsContainingDBElement */ #[ORM\Entity(repositoryClass: StorelocationRepository::class)] #[ORM\Table('`storelocations`')] -#[ORM\Index(name: 'location_idx_name', columns: ['name'])] -#[ORM\Index(name: 'location_idx_parent_name', columns: ['parent_id', 'name'])] -class Storelocation extends AbstractPartsContainingDBElement +#[ORM\Index(columns: ['name'], name: 'location_idx_name')] +#[ORM\Index(columns: ['parent_id', 'name'], name: 'location_idx_parent_name')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@storelocations.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['location:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['location:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/storage_locations/{id}/children.{_format}', + operations: [ + new GetCollection( + openapi: new Operation(summary: 'Retrieves the children elements of a storage location.'), + security: 'is_granted("@storelocations.read")' + ) + ], + uriVariables: [ + 'id' => new Link(fromProperty: 'children', fromClass: Manufacturer::class) + ], + normalizationContext: ['groups' => ['location:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] +class StorageLocation extends AbstractPartsContainingDBElement { - #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id')] + #[Groups(['location:read', 'location:write'])] + #[ApiProperty(readableLink: false, writableLink: false)] protected ?AbstractStructuralDBElement $parent = null; + #[Groups(['location:read', 'location:write'])] + protected string $comment = ''; + /** * @var MeasurementUnit|null The measurement unit, which parts can be stored in here */ #[ORM\ManyToOne(targetEntity: MeasurementUnit::class)] #[ORM\JoinColumn(name: 'storage_type_id')] + #[Groups(['location:read', 'location:write'])] protected ?MeasurementUnit $storage_type = null; - /** @var Collection + /** @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: StorelocationParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: StorageLocationParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] + #[Groups(['location:read', 'location:write'])] protected Collection $parameters; /** - * @var bool + * @var bool When this attribute is set, it is not possible to add additional parts or increase the instock of existing parts. */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'location:read', 'location:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $is_full = false; /** - * @var bool + * @var bool When this property is set, only one part (but many instock) is allowed to be stored in this store location. */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'location:read', 'location:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $only_single_part = false; /** - * @var bool + * @var bool When this property is set, it is only possible to increase the instock of parts, that are already stored here. */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'location:read', 'location:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $limit_to_existing_parts = false; @@ -95,25 +146,35 @@ class Storelocation extends AbstractPartsContainingDBElement #[Assert\Expression('this.getOwner() == null or this.getOwner().isAnonymousUser() === false', message: 'validator.part_lot.owner_must_not_be_anonymous')] #[ORM\ManyToOne(targetEntity: User::class)] #[ORM\JoinColumn(name: 'id_owner', onDelete: 'SET NULL')] + #[Groups(['location:read', 'location:write'])] protected ?User $owner = null; /** * @var bool If this is set to true, only parts lots, which are owned by the same user as the store location are allowed to be stored here. */ #[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])] + #[Groups(['location:read', 'location:write'])] protected bool $part_owner_must_match = false; /** - * @var Collection + * @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: StorelocationAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: StorageLocationAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[Groups(['location:read', 'location:write'])] protected Collection $attachments; - #[ORM\ManyToOne(targetEntity: StorelocationAttachment::class)] + #[ORM\ManyToOne(targetEntity: StorageLocationAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['location:read', 'location:write'])] protected ?Attachment $master_picture_attachment = null; + #[Groups(['location:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['location:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + /******************************************************************************** * * Getters @@ -186,7 +247,7 @@ class Storelocation extends AbstractPartsContainingDBElement /** * Sets the owner of this storage location */ - public function setOwner(?User $owner): Storelocation + public function setOwner(?User $owner): StorageLocation { $this->owner = $owner; return $this; @@ -203,7 +264,7 @@ class Storelocation extends AbstractPartsContainingDBElement /** * If this is set to true, only parts lots, which are owned by the same user as the store location are allowed to be stored here. */ - public function setPartOwnerMustMatch(bool $part_owner_must_match): Storelocation + public function setPartOwnerMustMatch(bool $part_owner_must_match): StorageLocation { $this->part_owner_must_match = $part_owner_must_match; return $this; diff --git a/src/Entity/Parts/Supplier.php b/src/Entity/Parts/Supplier.php index 4dca8f36..2c004e9e 100644 --- a/src/Entity/Parts/Supplier.php +++ b/src/Entity/Parts/Supplier.php @@ -22,8 +22,23 @@ declare(strict_types=1); namespace App\Entity\Parts; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; use App\Repository\Parts\SupplierRepository; use App\Entity\PriceInformations\Orderdetail; use Doctrine\Common\Collections\ArrayCollection; @@ -47,25 +62,50 @@ use Symfony\Component\Validator\Constraints as Assert; */ #[ORM\Entity(repositoryClass: SupplierRepository::class)] #[ORM\Table('`suppliers`')] -#[ORM\Index(name: 'supplier_idx_name', columns: ['name'])] -#[ORM\Index(name: 'supplier_idx_parent_name', columns: ['parent_id', 'name'])] +#[ORM\Index(columns: ['name'], name: 'supplier_idx_name')] +#[ORM\Index(columns: ['parent_id', 'name'], name: 'supplier_idx_parent_name')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@suppliers.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['supplier:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['supplier:write', 'company:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/suppliers/{id}/children.{_format}', + operations: [new GetCollection( + openapi: new Operation(summary: 'Retrieves the children elements of a supplier.'), + security: 'is_granted("@manufacturers.read")' + )], + uriVariables: [ + 'id' => new Link(fromProperty: 'children', fromClass: Supplier::class) + ], + normalizationContext: ['groups' => ['supplier:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] class Supplier extends AbstractCompany { - #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id')] + #[Groups(['supplier:read', 'supplier:write'])] + #[ApiProperty(readableLink: false, writableLink: false)] protected ?AbstractStructuralDBElement $parent = null; /** - * @var Collection|Orderdetail[] + * @var Collection */ - /** - * @var Collection|Orderdetail[] - */ - #[ORM\OneToMany(targetEntity: Orderdetail::class, mappedBy: 'supplier')] + #[ORM\OneToMany(mappedBy: 'supplier', targetEntity: Orderdetail::class)] protected Collection $orderdetails; /** @@ -74,34 +114,40 @@ class Supplier extends AbstractCompany */ #[ORM\ManyToOne(targetEntity: Currency::class)] #[ORM\JoinColumn(name: 'default_currency_id')] - #[Selectable()] + #[Selectable] protected ?Currency $default_currency = null; /** - * @var BigDecimal|null the shipping costs that have to be paid, when ordering via this supplier + * @var BigDecimal|null The shipping costs that have to be paid, when ordering via this supplier */ #[Groups(['extended', 'full', 'import'])] - #[ORM\Column(name: 'shipping_costs', nullable: true, type: 'big_decimal', precision: 11, scale: 5)] - #[BigDecimalPositiveOrZero()] + #[ORM\Column(name: 'shipping_costs', type: 'big_decimal', precision: 11, scale: 5, nullable: true)] + #[BigDecimalPositiveOrZero] protected ?BigDecimal $shipping_costs = null; /** * @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: SupplierAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: SupplierAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] + #[Groups(['supplier:read', 'supplier:write'])] + #[ApiProperty(readableLink: false, writableLink: true)] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: SupplierAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['supplier:read', 'supplier:write'])] + #[ApiProperty(readableLink: false, writableLink: true)] protected ?Attachment $master_picture_attachment = null; /** @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: SupplierParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: SupplierParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] + #[Groups(['supplier:read', 'supplier:write'])] + #[ApiProperty(readableLink: false, writableLink: true)] protected Collection $parameters; /** diff --git a/src/Entity/PriceInformations/Currency.php b/src/Entity/PriceInformations/Currency.php index 1aec8d8a..ce20caf8 100644 --- a/src/Entity/PriceInformations/Currency.php +++ b/src/Entity/PriceInformations/Currency.php @@ -22,8 +22,23 @@ declare(strict_types=1); namespace App\Entity\PriceInformations; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; use App\Repository\CurrencyRepository; use Doctrine\DBAL\Types\Types; use App\Entity\Attachments\CurrencyAttachment; @@ -47,8 +62,36 @@ use Symfony\Component\Validator\Constraints as Assert; #[UniqueEntity('iso_code')] #[ORM\Entity(repositoryClass: CurrencyRepository::class)] #[ORM\Table(name: 'currencies')] -#[ORM\Index(name: 'currency_idx_name', columns: ['name'])] -#[ORM\Index(name: 'currency_idx_parent_name', columns: ['parent_id', 'name'])] +#[ORM\Index(columns: ['name'], name: 'currency_idx_name')] +#[ORM\Index(columns: ['parent_id', 'name'], name: 'currency_idx_parent_name')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@currencies.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['currency:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['currency:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/currencies/{id}/children.{_format}', + operations: [ + new GetCollection( + openapi: new Operation(summary: 'Retrieves the children elements of a currency.'), + security: 'is_granted("@currencies.read")' + ) + ], + uriVariables: [ + 'id' => new Link(fromProperty: 'children', fromClass: Currency::class) + ], + normalizationContext: ['groups' => ['currency:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "iso_code"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] class Currency extends AbstractStructuralDBElement { final public const PRICE_SCALE = 5; @@ -58,50 +101,66 @@ class Currency extends AbstractStructuralDBElement * (how many base units the current currency is worth) */ #[ORM\Column(type: 'big_decimal', precision: 11, scale: 5, nullable: true)] - #[BigDecimalPositive()] + #[BigDecimalPositive] + #[Groups(['currency:read', 'currency:write', 'simple', 'extended', 'full', 'import'])] + #[ApiProperty(readableLink: false, writableLink: false)] protected ?BigDecimal $exchange_rate = null; + #[Groups(['currency:read', 'currency:write'])] + protected string $comment = ""; + /** * @var string the 3-letter ISO code of the currency */ #[Assert\Currency] #[Assert\NotBlank] - #[Groups(['extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'currency:read', 'currency:write'])] #[ORM\Column(type: Types::STRING)] protected string $iso_code = ""; - #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent', cascade: ['persist'])] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class, cascade: ['persist'])] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id')] + #[Groups(['currency:read', 'currency:write'])] + #[ApiProperty(readableLink: false, writableLink: false)] protected ?AbstractStructuralDBElement $parent = null; /** * @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: CurrencyAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: CurrencyAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] + #[Groups(['currency:read', 'currency:write'])] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: CurrencyAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['currency:read', 'currency:write'])] protected ?Attachment $master_picture_attachment = null; /** @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: CurrencyParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: CurrencyParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] + #[Groups(['currency:read', 'currency:write'])] protected Collection $parameters; /** @var Collection */ - #[ORM\OneToMany(targetEntity: Pricedetail::class, mappedBy: 'currency')] + #[ORM\OneToMany(mappedBy: 'currency', targetEntity: Pricedetail::class)] protected Collection $pricedetails; + #[Groups(['currency:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['currency:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + public function __construct() { $this->children = new ArrayCollection(); @@ -136,6 +195,7 @@ class Currency extends AbstractStructuralDBElement /** * Returns the inverse exchange rate (how many of the current currency the base unit is worth). */ + #[Groups(['currency:read'])] public function getInverseExchangeRate(): ?BigDecimal { $tmp = $this->getExchangeRate(); diff --git a/src/Entity/PriceInformations/Orderdetail.php b/src/Entity/PriceInformations/Orderdetail.php index d61eeb68..3709b37d 100644 --- a/src/Entity/PriceInformations/Orderdetail.php +++ b/src/Entity/PriceInformations/Orderdetail.php @@ -23,6 +23,22 @@ declare(strict_types=1); namespace App\Entity\PriceInformations; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use Doctrine\DBAL\Types\Types; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\TimestampTrait; @@ -30,13 +46,14 @@ use App\Entity\Contracts\NamedElementInterface; use App\Entity\Contracts\TimeStampableInterface; use App\Entity\Parts\Part; use App\Entity\Parts\Supplier; -use DateTime; +use DateTimeImmutable; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Constraints\Length; /** * Class Orderdetail. @@ -45,52 +62,87 @@ use Symfony\Component\Validator\Constraints as Assert; #[ORM\Entity] #[ORM\HasLifecycleCallbacks] #[ORM\Table('`orderdetails`')] -#[ORM\Index(name: 'orderdetails_supplier_part_nr', columns: ['supplierpartnr'])] +#[ORM\Index(columns: ['supplierpartnr'], name: 'orderdetails_supplier_part_nr')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@parts.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['orderdetail:read', 'orderdetail:read:standalone', 'api:basic:read', 'pricedetail:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['orderdetail:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/parts/{id}/orderdetails.{_format}', + operations: [ + new GetCollection( + openapi: new Operation(summary: 'Retrieves the orderdetails of a part.'), + security: 'is_granted("@parts.read")' + ) + ], + uriVariables: [ + 'id' => new Link(toProperty: 'part', fromClass: Part::class) + ], + normalizationContext: ['groups' => ['orderdetail:read', 'pricedetail:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["supplierpartnr", "supplier_product_url"])] +#[ApiFilter(BooleanFilter::class, properties: ["obsolete"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['supplierpartnr', 'id', 'addedDate', 'lastModified'])] class Orderdetail extends AbstractDBElement implements TimeStampableInterface, NamedElementInterface { use TimestampTrait; + /** + * @var Collection + */ #[Assert\Valid] - #[Groups(['extended', 'full', 'import'])] - #[ORM\OneToMany(targetEntity: Pricedetail::class, mappedBy: 'orderdetail', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['min_discount_quantity' => 'ASC'])] + #[Groups(['extended', 'full', 'import', 'orderdetail:read', 'orderdetail:write'])] + #[ORM\OneToMany(mappedBy: 'orderdetail', targetEntity: Pricedetail::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['min_discount_quantity' => Criteria::ASC])] protected Collection $pricedetails; /** - * @var string + * @var string The order number of the part at the supplier */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'orderdetail:read', 'orderdetail:write'])] #[ORM\Column(type: Types::STRING)] + #[Length(max: 255)] protected string $supplierpartnr = ''; /** - * @var bool + * @var bool True if this part is obsolete/not available anymore at the supplier */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'orderdetail:read', 'orderdetail:write'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $obsolete = false; /** - * @var string + * @var string The URL to the product on the supplier's website */ #[Assert\Url] - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'orderdetail:read', 'orderdetail:write'])] #[ORM\Column(type: Types::TEXT)] protected string $supplier_product_url = ''; /** - * @var Part|null + * @var Part|null The part with which this orderdetail is associated */ #[Assert\NotNull] #[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'orderdetails')] + #[Groups(['orderdetail:read:standalone', 'orderdetail:write'])] #[ORM\JoinColumn(name: 'part_id', nullable: false, onDelete: 'CASCADE')] protected ?Part $part = null; /** - * @var Supplier|null + * @var Supplier|null The supplier of this orderdetail */ #[Assert\NotNull(message: 'validator.orderdetail.supplier_must_not_be_null')] - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'orderdetail:read', 'orderdetail:write'])] #[ORM\ManyToOne(targetEntity: Supplier::class, inversedBy: 'orderdetails')] #[ORM\JoinColumn(name: 'id_supplier')] protected ?Supplier $supplier = null; @@ -121,9 +173,9 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N #[ORM\PreUpdate] public function updateTimestamps(): void { - $this->lastModified = new DateTime('now'); + $this->lastModified = new DateTimeImmutable('now'); if (!$this->addedDate instanceof \DateTimeInterface) { - $this->addedDate = new DateTime('now'); + $this->addedDate = new DateTimeImmutable('now'); } if ($this->part instanceof Part) { @@ -181,6 +233,11 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N return $this->obsolete; } + public function isObsolete(): bool + { + return $this->getObsolete(); + } + /** * Get the link to the website of the article on the supplier's website. * diff --git a/src/Entity/PriceInformations/Pricedetail.php b/src/Entity/PriceInformations/Pricedetail.php index 26afbb50..86a7bcd5 100644 --- a/src/Entity/PriceInformations/Pricedetail.php +++ b/src/Entity/PriceInformations/Pricedetail.php @@ -22,6 +22,14 @@ declare(strict_types=1); namespace App\Entity\PriceInformations; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\Serializer\Filter\PropertyFilter; use Doctrine\DBAL\Types\Types; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\TimestampTrait; @@ -30,10 +38,11 @@ use App\Validator\Constraints\BigDecimal\BigDecimalPositive; use App\Validator\Constraints\Selectable; use Brick\Math\BigDecimal; use Brick\Math\RoundingMode; -use DateTime; +use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Annotation\SerializedName; use Symfony\Component\Validator\Constraints as Assert; /** @@ -43,8 +52,20 @@ use Symfony\Component\Validator\Constraints as Assert; #[ORM\Entity] #[ORM\HasLifecycleCallbacks] #[ORM\Table('`pricedetails`')] -#[ORM\Index(name: 'pricedetails_idx_min_discount', columns: ['min_discount_quantity'])] -#[ORM\Index(name: 'pricedetails_idx_min_discount_price_qty', columns: ['min_discount_quantity', 'price_related_quantity'])] +#[ORM\Index(columns: ['min_discount_quantity'], name: 'pricedetails_idx_min_discount')] +#[ORM\Index(columns: ['min_discount_quantity', 'price_related_quantity'], name: 'pricedetails_idx_min_discount_price_qty')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@parts.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['pricedetail:read', 'pricedetail:read:standalone', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['pricedetail:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiFilter(PropertyFilter::class)] class Pricedetail extends AbstractDBElement implements TimeStampableInterface { use TimestampTrait; @@ -54,34 +75,34 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface /** * @var BigDecimal The price related to the detail. (Given in the selected currency) */ - #[Groups(['extended', 'full'])] + #[Groups(['extended', 'full', 'import', 'pricedetail:read', 'pricedetail:write'])] #[ORM\Column(type: 'big_decimal', precision: 11, scale: 5)] - #[BigDecimalPositive()] + #[BigDecimalPositive] protected BigDecimal $price; /** * @var ?Currency The currency used for the current price information. * If this is null, the global base unit is assumed */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'pricedetail:read', 'pricedetail:write'])] #[ORM\ManyToOne(targetEntity: Currency::class, inversedBy: 'pricedetails')] #[ORM\JoinColumn(name: 'id_currency')] - #[Selectable()] + #[Selectable] protected ?Currency $currency = null; /** - * @var float + * @var float The amount/quantity for which the price is for (in part unit) */ #[Assert\Positive] - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'pricedetail:read', 'pricedetail:write'])] #[ORM\Column(type: Types::FLOAT)] protected float $price_related_quantity = 1.0; /** - * @var float + * @var float The minimum amount/quantity, which is needed to get this discount (in part unit) */ #[Assert\Positive] - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'pricedetail:read', 'pricedetail:write'])] #[ORM\Column(type: Types::FLOAT)] protected float $min_discount_quantity = 1.0; @@ -97,6 +118,7 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface #[Assert\NotNull] #[ORM\ManyToOne(targetEntity: Orderdetail::class, inversedBy: 'pricedetails')] #[ORM\JoinColumn(name: 'orderdetails_id', nullable: false, onDelete: 'CASCADE')] + #[Groups(['pricedetail:read:standalone', 'pricedetail:write'])] protected ?Orderdetail $orderdetail = null; public function __construct() @@ -119,9 +141,9 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface #[ORM\PreUpdate] public function updateTimestamps(): void { - $this->lastModified = new DateTime('now'); + $this->lastModified = new DateTimeImmutable('now'); if (!$this->addedDate instanceof \DateTimeInterface) { - $this->addedDate = new DateTime('now'); + $this->addedDate = new DateTimeImmutable('now'); } if ($this->orderdetail instanceof Orderdetail) { @@ -167,6 +189,8 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface * * @return BigDecimal the price as a bcmath string */ + #[Groups(['pricedetail:read'])] + #[SerializedName('price_per_unit')] public function getPricePerUnit(float|string|BigDecimal $multiplier = 1.0): BigDecimal { $tmp = BigDecimal::of($multiplier); @@ -228,6 +252,18 @@ class Pricedetail extends AbstractDBElement implements TimeStampableInterface return $this->currency; } + /** + * Returns the ISO code of the currency associated with this price information, or null if no currency is selected. + * Then the global base currency should be assumed. + * @return string|null + */ + #[Groups(['pricedetail:read'])] + #[SerializedName('currency_iso_code')] + public function getCurrencyISOCode(): ?string + { + return $this->currency?->getIsoCode(); + } + /******************************************************************************** * * Setters diff --git a/src/Entity/ProjectSystem/Project.php b/src/Entity/ProjectSystem/Project.php index 4d79ee38..a103d694 100644 --- a/src/Entity/ProjectSystem/Project.php +++ b/src/Entity/ProjectSystem/Project.php @@ -22,8 +22,21 @@ declare(strict_types=1); namespace App\Entity\ProjectSystem; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; use App\Repository\Parts\DeviceRepository; use App\Validator\Constraints\UniqueObjectCollection; use Doctrine\DBAL\Types\Types; @@ -46,21 +59,56 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; */ #[ORM\Entity(repositoryClass: DeviceRepository::class)] #[ORM\Table(name: 'projects')] +#[ApiResource( + operations: [ + new Get(security: 'is_granted("read", object)'), + new GetCollection(security: 'is_granted("@projects.read")'), + new Post(securityPostDenormalize: 'is_granted("create", object)'), + new Patch(security: 'is_granted("edit", object)'), + new Delete(security: 'is_granted("delete", object)'), + ], + normalizationContext: ['groups' => ['project:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['project:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/projects/{id}/children.{_format}', + operations: [ + new GetCollection( + openapi: new Operation(summary: 'Retrieves the children elements of a project.'), + security: 'is_granted("@projects.read")' + ) + ], + uriVariables: [ + 'id' => new Link(fromProperty: 'children', fromClass: Project::class) + ], + normalizationContext: ['groups' => ['project:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] class Project extends AbstractStructuralDBElement { - #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] #[ORM\JoinColumn(name: 'parent_id')] + #[Groups(['project:read', 'project:write'])] + #[ApiProperty(readableLink: false, writableLink: false)] protected ?AbstractStructuralDBElement $parent = null; + #[Groups(['project:read', 'project:write'])] + protected string $comment = ''; + + /** + * @var Collection + */ #[Assert\Valid] - #[Groups(['extended', 'full'])] - #[ORM\OneToMany(targetEntity: ProjectBOMEntry::class, mappedBy: 'project', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[UniqueObjectCollection(fields: ['part'], message: 'project.bom_entry.part_already_in_bom')] - #[UniqueObjectCollection(fields: ['name'], message: 'project.bom_entry.name_already_in_bom')] + #[Groups(['extended', 'full', 'import'])] + #[ORM\OneToMany(mappedBy: 'project', targetEntity: ProjectBOMEntry::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[UniqueObjectCollection(message: 'project.bom_entry.part_already_in_bom', fields: ['part'])] + #[UniqueObjectCollection(message: 'project.bom_entry.name_already_in_bom', fields: ['name'])] protected Collection $bom_entries; #[ORM\Column(type: Types::INTEGER)] @@ -70,7 +118,7 @@ class Project extends AbstractStructuralDBElement * @var string|null The current status of the project */ #[Assert\Choice(['draft', 'planning', 'in_production', 'finished', 'archived'])] - #[Groups(['extended', 'full'])] + #[Groups(['extended', 'full', 'project:read', 'project:write', 'import'])] #[ORM\Column(type: Types::STRING, length: 64, nullable: true)] protected ?string $status = null; @@ -78,33 +126,43 @@ class Project extends AbstractStructuralDBElement /** * @var Part|null The (optional) part that represents the builds of this project in the stock */ - #[ORM\OneToOne(targetEntity: Part::class, mappedBy: 'built_project', cascade: ['persist'], orphanRemoval: true)] + #[ORM\OneToOne(mappedBy: 'built_project', targetEntity: Part::class, cascade: ['persist'], orphanRemoval: true)] + #[Groups(['project:read', 'project:write'])] protected ?Part $build_part = null; #[ORM\Column(type: Types::BOOLEAN)] protected bool $order_only_missing_parts = false; - #[Groups(['simple', 'extended', 'full'])] + #[Groups(['simple', 'extended', 'full', 'project:read', 'project:write'])] #[ORM\Column(type: Types::TEXT)] protected string $description = ''; /** * @var Collection */ - #[ORM\OneToMany(targetEntity: ProjectAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: ProjectAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] + #[Groups(['project:read', 'project:write'])] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: ProjectAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['project:read', 'project:write'])] protected ?Attachment $master_picture_attachment = null; /** @var Collection */ - #[ORM\OneToMany(targetEntity: ProjectParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: ProjectParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] + #[Groups(['project:read', 'project:write'])] protected Collection $parameters; + #[Groups(['project:read'])] + protected ?\DateTimeImmutable $addedDate = null; + #[Groups(['project:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + /******************************************************************************** * * Getters @@ -129,7 +187,7 @@ class Project extends AbstractStructuralDBElement //Set master attachment is needed foreach ($bom_entries as $bom_entry) { $clone = clone $bom_entry; - $this->bom_entries->add($clone); + $this->addBomEntry($clone); } } @@ -275,7 +333,6 @@ class Project extends AbstractStructuralDBElement { //If this project has subprojects, and these have builds part, they must be included in the BOM foreach ($this->getChildren() as $child) { - /** @var $child Project */ if (!$child->getBuildPart() instanceof Part) { continue; } diff --git a/src/Entity/ProjectSystem/ProjectBOMEntry.php b/src/Entity/ProjectSystem/ProjectBOMEntry.php index 8955b1cf..2a7862ec 100644 --- a/src/Entity/ProjectSystem/ProjectBOMEntry.php +++ b/src/Entity/ProjectSystem/ProjectBOMEntry.php @@ -22,6 +22,20 @@ declare(strict_types=1); namespace App\Entity\ProjectSystem; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Doctrine\Orm\Filter\RangeFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Link; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; +use App\Entity\Contracts\TimeStampableInterface; use App\Validator\UniqueValidatableInterface; use Doctrine\DBAL\Types\Types; use App\Entity\Base\AbstractDBElement; @@ -32,7 +46,7 @@ use App\Validator\Constraints\BigDecimal\BigDecimalPositive; use App\Validator\Constraints\Selectable; use Brick\Math\BigDecimal; use Doctrine\ORM\Mapping as ORM; -use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Context\ExecutionContextInterface; @@ -42,18 +56,48 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface; #[ORM\HasLifecycleCallbacks] #[ORM\Entity] #[ORM\Table('project_bom_entries')] -class ProjectBOMEntry extends AbstractDBElement implements UniqueValidatableInterface +#[ApiResource( + operations: [ + new Get(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("read", object)',), + new GetCollection(uriTemplate: '/project_bom_entries.{_format}', security: 'is_granted("@projects.read")',), + new Post(uriTemplate: '/project_bom_entries.{_format}', securityPostDenormalize: 'is_granted("create", object)',), + new Patch(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("edit", object)',), + new Delete(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("delete", object)',), + ], + normalizationContext: ['groups' => ['bom_entry:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + denormalizationContext: ['groups' => ['bom_entry:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'], +)] +#[ApiResource( + uriTemplate: '/projects/{id}/bom.{_format}', + operations: [ + new GetCollection( + openapi: new Operation(summary: 'Retrieves the BOM entries of the given project.'), + security: 'is_granted("@projects.read")' + ) + ], + uriVariables: [ + 'id' => new Link(fromProperty: 'bom_entries', fromClass: Project::class) + ], + normalizationContext: ['groups' => ['bom_entry:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "comment", 'mountnames'])] +#[ApiFilter(RangeFilter::class, properties: ['quantity'])] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified', 'quantity'])] +class ProjectBOMEntry extends AbstractDBElement implements UniqueValidatableInterface, TimeStampableInterface { use TimestampTrait; #[Assert\Positive] - #[ORM\Column(type: Types::FLOAT, name: 'quantity')] + #[ORM\Column(name: 'quantity', type: Types::FLOAT)] + #[Groups(['bom_entry:read', 'bom_entry:write', 'import', 'simple', 'extended', 'full'])] protected float $quantity = 1.0; /** * @var string A comma separated list of the names, where this parts should be placed */ - #[ORM\Column(type: Types::TEXT, name: 'mountnames')] + #[ORM\Column(name: 'mountnames', type: Types::TEXT)] + #[Groups(['bom_entry:read', 'bom_entry:write', 'import', 'simple', 'extended', 'full'])] protected string $mountnames = ''; /** @@ -61,12 +105,14 @@ class ProjectBOMEntry extends AbstractDBElement implements UniqueValidatableInte */ #[Assert\Expression('this.getPart() !== null or this.getName() !== null', message: 'validator.project.bom_entry.name_or_part_needed')] #[ORM\Column(type: Types::STRING, nullable: true)] + #[Groups(['bom_entry:read', 'bom_entry:write', 'import', 'simple', 'extended', 'full'])] protected ?string $name = null; /** * @var string An optional comment for this BOM entry */ #[ORM\Column(type: Types::TEXT)] + #[Groups(['bom_entry:read', 'bom_entry:write', 'import', 'extended', 'full'])] protected string $comment = ''; /** @@ -74,6 +120,7 @@ class ProjectBOMEntry extends AbstractDBElement implements UniqueValidatableInte */ #[ORM\ManyToOne(targetEntity: Project::class, inversedBy: 'bom_entries')] #[ORM\JoinColumn(name: 'id_device')] + #[Groups(['bom_entry:read', 'bom_entry:write', ])] protected ?Project $project = null; /** @@ -81,6 +128,7 @@ class ProjectBOMEntry extends AbstractDBElement implements UniqueValidatableInte */ #[ORM\ManyToOne(targetEntity: Part::class, inversedBy: 'project_bom_entries')] #[ORM\JoinColumn(name: 'id_part')] + #[Groups(['bom_entry:read', 'bom_entry:write', 'full'])] protected ?Part $part = null; /** @@ -88,6 +136,7 @@ class ProjectBOMEntry extends AbstractDBElement implements UniqueValidatableInte */ #[Assert\AtLeastOneOf([new BigDecimalPositive(), new Assert\IsNull()])] #[ORM\Column(type: 'big_decimal', precision: 11, scale: 5, nullable: true)] + #[Groups(['bom_entry:read', 'bom_entry:write', 'import', 'extended', 'full'])] protected ?BigDecimal $price = null; /** diff --git a/src/Entity/UserSystem/ApiToken.php b/src/Entity/UserSystem/ApiToken.php new file mode 100644 index 00000000..f5cbf541 --- /dev/null +++ b/src/Entity/UserSystem/ApiToken.php @@ -0,0 +1,199 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\UserSystem; + +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Get; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\Entity\Base\TimestampTrait; +use App\Entity\Contracts\TimeStampableInterface; +use App\Repository\UserSystem\ApiTokenRepository; +use App\State\CurrentApiTokenProvider; +use App\Validator\Constraints\Year2038BugWorkaround; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints\Length; +use Symfony\Component\Validator\Constraints\NotBlank; + +#[ORM\Entity(repositoryClass: ApiTokenRepository::class)] +#[ORM\Table(name: 'api_tokens')] +#[ORM\HasLifecycleCallbacks] +#[UniqueEntity(fields: ['name', 'user'])] + +#[ApiResource( + uriTemplate: '/tokens/current.{_format}', + description: 'A token used to authenticate API requests.', + operations: [new Get( + openapi: new Operation(summary: 'Get information about the API token that is currently used.'), + )], + normalizationContext: ['groups' => ['token:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'], + provider: CurrentApiTokenProvider::class, +)] +#[ApiFilter(PropertyFilter::class)] +class ApiToken implements TimeStampableInterface +{ + + use TimestampTrait; + + #[ORM\Id] + #[ORM\Column(type: Types::INTEGER)] + #[ORM\GeneratedValue] + protected int $id; + + #[ORM\Column(type: Types::STRING)] + #[Length(max: 255)] + #[NotBlank] + #[Groups('token:read')] + protected string $name = ''; + + #[ORM\ManyToOne(inversedBy: 'api_tokens')] + #[Groups('token:read')] + private ?User $user = null; + + #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)] + #[Groups('token:read')] + #[Year2038BugWorkaround] + private ?\DateTimeImmutable $valid_until; + + #[ORM\Column(length: 68, unique: true)] + private string $token; + + #[ORM\Column(type: Types::SMALLINT, enumType: ApiTokenLevel::class)] + #[Groups('token:read')] + private ApiTokenLevel $level = ApiTokenLevel::READ_ONLY; + + #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)] + #[Groups('token:read')] + private ?\DateTimeImmutable $last_time_used = null; + + public function __construct(ApiTokenType $tokenType = ApiTokenType::PERSONAL_ACCESS_TOKEN) + { + // Generate a rondom token on creation. The tokenType is 3 characters long (plus underscore), so the token is 68 characters long. + $this->token = $tokenType->getTokenPrefix() . bin2hex(random_bytes(32)); + + //By default, tokens are valid for 1 year. + $this->valid_until = new \DateTimeImmutable('+1 year'); + } + + public function getTokenType(): ApiTokenType + { + return ApiTokenType::getTypeFromToken($this->token); + } + + public function getUser(): ?User + { + return $this->user; + } + + public function setUser(?User $user): ApiToken + { + $this->user = $user; + return $this; + } + + public function getValidUntil(): ?\DateTimeImmutable + { + return $this->valid_until; + } + + /** + * Checks if the token is still valid. + * @return bool + */ + public function isValid(): bool + { + return $this->valid_until === null || $this->valid_until > new \DateTimeImmutable(); + } + + public function setValidUntil(?\DateTimeImmutable $valid_until): ApiToken + { + $this->valid_until = $valid_until; + return $this; + } + + public function getToken(): string + { + return $this->token; + } + + public function getId(): int + { + return $this->id; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): ApiToken + { + $this->name = $name; + return $this; + } + + /** + * Gets the last time the token was used to authenticate or null if it was never used. + */ + public function getLastTimeUsed(): ?\DateTimeImmutable + { + return $this->last_time_used; + } + + /** + * Sets the last time the token was used to authenticate. + * @return ApiToken + */ + public function setLastTimeUsed(?\DateTimeImmutable $last_time_used): ApiToken + { + $this->last_time_used = $last_time_used; + return $this; + } + + public function getLevel(): ApiTokenLevel + { + return $this->level; + } + + public function setLevel(ApiTokenLevel $level): ApiToken + { + $this->level = $level; + return $this; + } + + /** + * Returns the last 4 characters of the token secret, which can be used to identify the token. + * @return string + */ + public function getLastTokenChars(): string + { + return substr($this->token, -4); + } + + +} \ No newline at end of file diff --git a/src/Entity/UserSystem/ApiTokenLevel.php b/src/Entity/UserSystem/ApiTokenLevel.php new file mode 100644 index 00000000..3f997300 --- /dev/null +++ b/src/Entity/UserSystem/ApiTokenLevel.php @@ -0,0 +1,73 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\UserSystem; + +enum ApiTokenLevel: int +{ + private const ROLE_READ_ONLY = 'ROLE_API_READ_ONLY'; + private const ROLE_EDIT = 'ROLE_API_EDIT'; + private const ROLE_ADMIN = 'ROLE_API_ADMIN'; + private const ROLE_FULL = 'ROLE_API_FULL'; + + /** + * The token can only read (non-sensitive) data. + */ + case READ_ONLY = 1; + /** + * The token can read and edit (non-sensitive) data. + */ + case EDIT = 2; + /** + * The token can do some administrative tasks (like viewing all log entries), but can not change passwords and create new tokens. + */ + case ADMIN = 3; + /** + * The token can do everything the user can do. + */ + case FULL = 4; + + /** + * Returns the additional roles that the authenticated user should have when using this token. + * @return string[] + */ + public function getAdditionalRoles(): array + { + //The higher roles should always include the lower ones + return match ($this) { + self::READ_ONLY => [self::ROLE_READ_ONLY], + self::EDIT => [self::ROLE_READ_ONLY, self::ROLE_EDIT], + self::ADMIN => [self::ROLE_READ_ONLY, self::ROLE_EDIT, self::ROLE_ADMIN], + self::FULL => [self::ROLE_READ_ONLY, self::ROLE_EDIT, self::ROLE_ADMIN, self::ROLE_FULL], + }; + } + + /** + * Returns the translation key for the name of this token level. + * @return string + */ + public function getTranslationKey(): string + { + return 'api_token.level.' . strtolower($this->name); + } +} \ No newline at end of file diff --git a/src/Entity/UserSystem/ApiTokenType.php b/src/Entity/UserSystem/ApiTokenType.php new file mode 100644 index 00000000..f8beb378 --- /dev/null +++ b/src/Entity/UserSystem/ApiTokenType.php @@ -0,0 +1,56 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Entity\UserSystem; + +/** + * The type of ApiToken. + * The enum value is the prefix of the token. It must be 3 characters long. + */ +enum ApiTokenType: string +{ + case PERSONAL_ACCESS_TOKEN = 'tcp'; + + /** + * Get the prefix of the token including the underscore + * @return string + */ + public function getTokenPrefix(): string + { + return $this->value . '_'; + } + + /** + * Get the type from the token prefix + * @param string $api_token + * @return ApiTokenType + */ + public static function getTypeFromToken(string $api_token): ApiTokenType + { + $parts = explode('_', $api_token); + if (count($parts) !== 2) { + throw new \InvalidArgumentException('Invalid token format'); + } + return self::from($parts[0]); + } +} diff --git a/src/Entity/UserSystem/Group.php b/src/Entity/UserSystem/Group.php index 01e79498..6da9d35f 100644 --- a/src/Entity/UserSystem/Group.php +++ b/src/Entity/UserSystem/Group.php @@ -22,8 +22,8 @@ declare(strict_types=1); namespace App\Entity\UserSystem; +use Doctrine\Common\Collections\Criteria; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; use App\Validator\Constraints\NoLockout; use Doctrine\DBAL\Types\Types; use App\Entity\Attachments\GroupAttachment; @@ -44,13 +44,13 @@ use Symfony\Component\Validator\Constraints as Assert; */ #[ORM\Entity] #[ORM\Table('`groups`')] -#[ORM\Index(name: 'group_idx_name', columns: ['name'])] -#[ORM\Index(name: 'group_idx_parent_name', columns: ['parent_id', 'name'])] -#[NoLockout()] +#[ORM\Index(columns: ['name'], name: 'group_idx_name')] +#[ORM\Index(columns: ['parent_id', 'name'], name: 'group_idx_parent_name')] +#[NoLockout] class Group extends AbstractStructuralDBElement implements HasPermissionsInterface { - #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'parent')] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $children; #[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')] @@ -60,22 +60,22 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa /** * @var Collection */ - #[ORM\OneToMany(targetEntity: User::class, mappedBy: 'group')] + #[ORM\OneToMany(mappedBy: 'group', targetEntity: User::class)] protected Collection $users; /** * @var bool If true all users associated with this group must have enabled some kind of two-factor authentication */ #[Groups(['extended', 'full', 'import'])] - #[ORM\Column(type: Types::BOOLEAN, name: 'enforce_2fa')] + #[ORM\Column(name: 'enforce_2fa', type: Types::BOOLEAN)] protected bool $enforce2FA = false; /** * @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: GroupAttachment::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: GroupAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['name' => Criteria::ASC])] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: GroupAttachment::class)] @@ -84,15 +84,15 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa #[Groups(['full'])] #[ORM\Embedded(class: PermissionData::class, columnPrefix: 'permissions_')] - #[ValidPermission()] + #[ValidPermission] protected ?PermissionData $permissions = null; /** * @var Collection */ #[Assert\Valid] - #[ORM\OneToMany(targetEntity: GroupParameter::class, mappedBy: 'element', cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['group' => 'ASC', 'name' => 'ASC'])] + #[ORM\OneToMany(mappedBy: 'element', targetEntity: GroupParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)] + #[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])] protected Collection $parameters; public function __construct() diff --git a/src/Entity/UserSystem/PermissionData.php b/src/Entity/UserSystem/PermissionData.php index 01bb2416..9ebdc9c9 100644 --- a/src/Entity/UserSystem/PermissionData.php +++ b/src/Entity/UserSystem/PermissionData.php @@ -43,7 +43,7 @@ final class PermissionData implements \JsonSerializable /** * The current schema version of the permission data */ - public const CURRENT_SCHEMA_VERSION = 2; + public const CURRENT_SCHEMA_VERSION = 3; /** * Creates a new Permission Data Instance using the given data. @@ -57,7 +57,7 @@ final class PermissionData implements \JsonSerializable * operation => value, * ] */ - #[ORM\Column(type: Types::JSON, name: 'data')] + #[ORM\Column(name: 'data', type: Types::JSON)] protected array $data = [] ) { @@ -145,8 +145,8 @@ final class PermissionData implements \JsonSerializable */ public function setPermissionValue(string $permission, string $operation, ?bool $value): self { - if ($value === null) { - //If the value is null, unset the permission value (meaning implicit inherit) + //If the value is null, unset the permission value, if it was set befoere (meaning implicit inherit) + if ($value === null && isset($this->data[$permission][$operation])) { unset($this->data[$permission][$operation]); } else { //Otherwise, set the pemission value diff --git a/src/Entity/UserSystem/U2FKey.php b/src/Entity/UserSystem/U2FKey.php index f6a2a2e4..d1d864bc 100644 --- a/src/Entity/UserSystem/U2FKey.php +++ b/src/Entity/UserSystem/U2FKey.php @@ -22,16 +22,18 @@ declare(strict_types=1); namespace App\Entity\UserSystem; +use App\Entity\Contracts\TimeStampableInterface; use Doctrine\DBAL\Types\Types; use App\Entity\Base\TimestampTrait; use Doctrine\ORM\Mapping as ORM; use Jbtronics\TFAWebauthn\Model\LegacyU2FKeyInterface; +use Symfony\Component\Validator\Constraints\Length; #[ORM\Entity] #[ORM\HasLifecycleCallbacks] #[ORM\Table(name: 'u2f_keys')] #[ORM\UniqueConstraint(name: 'user_unique', columns: ['user_id', 'key_handle'])] -class U2FKey implements LegacyU2FKeyInterface +class U2FKey implements LegacyU2FKeyInterface, TimeStampableInterface { use TimestampTrait; @@ -43,6 +45,7 @@ class U2FKey implements LegacyU2FKeyInterface * @var string **/ #[ORM\Column(type: Types::STRING, length: 128)] + #[Length(max: 128)] public string $keyHandle = ''; /** diff --git a/src/Entity/UserSystem/User.php b/src/Entity/UserSystem/User.php index 54d57d7c..b39bea4f 100644 --- a/src/Entity/UserSystem/User.php +++ b/src/Entity/UserSystem/User.php @@ -22,8 +22,19 @@ declare(strict_types=1); namespace App\Entity\UserSystem; +use Doctrine\Common\Collections\Criteria; +use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface; +use ApiPlatform\Doctrine\Orm\Filter\DateFilter; +use ApiPlatform\Doctrine\Orm\Filter\OrderFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\OpenApi\Model\Operation; +use ApiPlatform\Serializer\Filter\PropertyFilter; +use App\ApiPlatform\Filter\LikeFilter; use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentTypeAttachment; use App\Repository\UserRepository; use App\EntityListeners\TreeCacheInvalidationListener; use App\Validator\Constraints\NoLockout; @@ -40,6 +51,7 @@ use Jbtronics\TFAWebauthn\Model\LegacyU2FKeyInterface; use Nbgrp\OneloginSamlBundle\Security\User\SamlUserInterface; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Validator\Constraints\Length; use Webauthn\PublicKeyCredentialUserEntity; use function count; use DateTime; @@ -68,8 +80,29 @@ use Jbtronics\TFAWebauthn\Model\TwoFactorInterface as WebauthnTwoFactorInterface #[ORM\Entity(repositoryClass: UserRepository::class)] #[ORM\EntityListeners([TreeCacheInvalidationListener::class])] #[ORM\Table('`users`')] -#[ORM\Index(name: 'user_idx_username', columns: ['name'])] -#[NoLockout()] +#[ORM\Index(columns: ['name'], name: 'user_idx_username')] +#[ORM\AttributeOverrides([ + new ORM\AttributeOverride(name: 'name', column: new ORM\Column(type: Types::STRING, length: 180, unique: true)) +])] +#[ApiResource( + shortName: 'User', + operations: [ + new Get( + openapi: new Operation(summary: 'Get information about the current user.'), + security: 'is_granted("read", object)' + ), + new GetCollection( + openapi: new Operation(summary: 'Get all users defined in the system.'), + security: 'is_granted("@users.read")' + ), + ], + normalizationContext: ['groups' => ['user:read'], 'openapi_definition_name' => 'Read'], +)] +#[ApiFilter(PropertyFilter::class)] +#[ApiFilter(LikeFilter::class, properties: ["name", "aboutMe"])] +#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)] +#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])] +#[NoLockout(groups: ['permissions:edit'])] class User extends AttachmentContainingDBElement implements UserInterface, HasPermissionsInterface, TwoFactorInterface, BackupCodeInterface, TrustedDeviceInterface, WebauthnTwoFactorInterface, PreferredProviderInterface, PasswordAuthenticatedUserInterface, SamlUserInterface { @@ -80,19 +113,28 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe */ final public const ID_ANONYMOUS = 1; + #[Groups(['user:read'])] + protected ?int $id = null; + + #[Groups(['user:read'])] + protected ?\DateTimeImmutable $lastModified = null; + + #[Groups(['user:read'])] + protected ?\DateTimeImmutable $addedDate = null; + /** * @var bool Determines if the user is disabled (user can not log in) */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'user:read'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $disabled = false; /** * @var string|null The theme */ - #[Groups(['full', 'import'])] - #[ORM\Column(type: Types::STRING, name: 'config_theme', nullable: true)] - #[ValidTheme()] + #[Groups(['full', 'import', 'user:read'])] + #[ORM\Column(name: 'config_theme', type: Types::STRING, nullable: true)] + #[ValidTheme] protected ?string $theme = null; /** @@ -101,16 +143,18 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe #[ORM\Column(type: Types::STRING, nullable: true)] protected ?string $pw_reset_token = null; - #[ORM\Column(type: Types::TEXT, name: 'config_instock_comment_a')] + #[ORM\Column(name: 'config_instock_comment_a', type: Types::TEXT)] + #[Groups(['extended', 'full', 'import'])] protected string $instock_comment_a = ''; - #[ORM\Column(type: Types::TEXT, name: 'config_instock_comment_w')] + #[ORM\Column(name: 'config_instock_comment_w', type: Types::TEXT)] + #[Groups(['extended', 'full', 'import'])] protected string $instock_comment_w = ''; /** - * @var string A self-description of the user + * @var string A self-description of the user as markdown text */ - #[Groups(['full', 'import'])] + #[Groups(['full', 'import', 'user:read'])] #[ORM\Column(type: Types::TEXT)] protected string $aboutMe = ''; @@ -125,19 +169,15 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe #[ORM\Column(type: Types::JSON)] protected ?array $backupCodes = []; - #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column(type: Types::INTEGER)] - protected ?int $id = null; - /** * @var Group|null the group this user belongs to * DO NOT PUT A fetch eager here! Otherwise, you can not unset the group of a user! This seems to be some kind of bug in doctrine. Maybe this is fixed in future versions. */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'user:read'])] #[ORM\ManyToOne(targetEntity: Group::class, inversedBy: 'users')] #[ORM\JoinColumn(name: 'group_id')] #[Selectable] + #[ApiProperty(readableLink: true, writableLink: false)] protected ?Group $group = null; /** @@ -150,57 +190,62 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe * @var string|null The timezone the user prefers */ #[Assert\Timezone] - #[Groups(['full', 'import'])] - #[ORM\Column(type: Types::STRING, name: 'config_timezone', nullable: true)] + #[Groups(['full', 'import', 'user:read'])] + #[ORM\Column(name: 'config_timezone', type: Types::STRING, nullable: true)] protected ?string $timezone = ''; /** * @var string|null The language/locale the user prefers */ #[Assert\Language] - #[Groups(['full', 'import'])] - #[ORM\Column(type: Types::STRING, name: 'config_language', nullable: true)] + #[Groups(['full', 'import', 'user:read'])] + #[ORM\Column(name: 'config_language', type: Types::STRING, nullable: true)] protected ?string $language = ''; /** * @var string|null The email address of the user */ #[Assert\Email] - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'user:read'])] #[ORM\Column(type: Types::STRING, length: 255, nullable: true)] + #[Length(max: 255)] protected ?string $email = ''; /** * @var bool True if the user wants to show his email address on his (public) profile */ #[ORM\Column(type: Types::BOOLEAN, options: ['default' => false])] + #[Groups(['full', 'import', 'user:read'])] protected bool $show_email_on_profile = false; /** * @var string|null The department the user is working */ - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'user:read'])] #[ORM\Column(type: Types::STRING, length: 255, nullable: true)] + #[Length(max: 255)] protected ?string $department = ''; /** * @var string|null The last name of the User */ - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'user:read'])] #[ORM\Column(type: Types::STRING, length: 255, nullable: true)] + #[Length(max: 255)] protected ?string $last_name = ''; /** * @var string|null The first name of the User */ - #[Groups(['simple', 'extended', 'full', 'import'])] + #[Groups(['simple', 'extended', 'full', 'import', 'user:read'])] #[ORM\Column(type: Types::STRING, length: 255, nullable: true)] + #[Length(max: 255)] protected ?string $first_name = ''; /** * @var bool True if the user needs to change password after log in */ - #[Groups(['extended', 'full', 'import'])] + #[Groups(['extended', 'full', 'import', 'user:read'])] #[ORM\Column(type: Types::BOOLEAN)] protected bool $need_pw_change = true; @@ -211,8 +256,8 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe protected ?string $password = null; #[Assert\NotBlank] - #[Assert\Regex('/^[\w\.\+\-\$]+$/', message: 'user.invalid_username')] - #[ORM\Column(type: Types::STRING, length: 180, unique: true)] + #[Assert\Regex('/^[\w\.\+\-\$]+[\w\.\+\-\$\@]*$/', message: 'user.invalid_username')] + #[Groups(['user:read'])] protected string $name = ''; /** @@ -225,18 +270,20 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe * @var Collection */ #[ORM\OneToMany(mappedBy: 'element', targetEntity: UserAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)] - #[ORM\OrderBy(['name' => 'ASC'])] + #[ORM\OrderBy(['name' => Criteria::ASC])] + #[Groups(['user:read', 'user:write'])] protected Collection $attachments; #[ORM\ManyToOne(targetEntity: UserAttachment::class)] #[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')] + #[Groups(['user:read', 'user:write'])] protected ?Attachment $master_picture_attachment = null; - /** @var \DateTimeInterface|null The time when the backup codes were generated + /** @var \DateTimeImmutable|null The time when the backup codes were generated */ #[Groups(['full'])] - #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)] - protected ?\DateTimeInterface $backupCodesGenerationDate = null; + #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)] + protected ?\DateTimeImmutable $backupCodesGenerationDate = null; /** @var Collection */ @@ -249,6 +296,12 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe #[ORM\OneToMany(mappedBy: 'user', targetEntity: WebauthnKey::class, cascade: ['REMOVE'], fetch: 'EXTRA_LAZY', orphanRemoval: true)] protected Collection $webauthn_keys; + /** + * @var Collection + */ + #[ORM\OneToMany(mappedBy: 'user', targetEntity: ApiToken::class, cascade: ['REMOVE'], fetch: 'EXTRA_LAZY', orphanRemoval: true)] + private Collection $api_tokens; + /** * @var Currency|null The currency the user wants to see prices in. * Dont use fetch=EAGER here, this will cause problems with setting the currency setting. @@ -263,14 +316,14 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe #[Groups(['simple', 'extended', 'full', 'import'])] #[ORM\Embedded(class: 'PermissionData', columnPrefix: 'permissions_')] - #[ValidPermission()] + #[ValidPermission] protected ?PermissionData $permissions = null; /** - * @var \DateTimeInterface|null the time until the password reset token is valid + * @var \DateTimeImmutable|null the time until the password reset token is valid */ - #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)] - protected ?\DateTimeInterface $pw_reset_expires = null; + #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)] + protected ?\DateTimeImmutable $pw_reset_expires = null; /** * @var bool True if the user was created by a SAML provider (and therefore cannot change its password) @@ -286,6 +339,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe $this->permissions = new PermissionData(); $this->u2fKeys = new ArrayCollection(); $this->webauthn_keys = new ArrayCollection(); + $this->api_tokens = new ArrayCollection(); } /** @@ -476,7 +530,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe /** * Gets the datetime when the password reset token expires. */ - public function getPwResetExpires(): \DateTimeInterface|null + public function getPwResetExpires(): \DateTimeImmutable|null { return $this->pw_reset_expires; } @@ -484,7 +538,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe /** * Sets the datetime when the password reset token expires. */ - public function setPwResetExpires(\DateTimeInterface $pw_reset_expires): self + public function setPwResetExpires(\DateTimeImmutable $pw_reset_expires): self { $this->pw_reset_expires = $pw_reset_expires; @@ -503,6 +557,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe * * @return string a string with the full name of this user */ + #[Groups(['user:read'])] public function getFullName(bool $including_username = false): string { $tmp = $this->getFirstName(); @@ -838,13 +893,11 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe * @param string[] $codes An array containing the backup codes * * @return $this - * - * @throws Exception If an error with the datetime occurs */ public function setBackupCodes(array $codes): self { $this->backupCodes = $codes; - $this->backupCodesGenerationDate = $codes === [] ? null : new DateTime(); + $this->backupCodesGenerationDate = $codes === [] ? null : new \DateTimeImmutable(); return $this; } @@ -852,7 +905,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe /** * Return the date when the backup codes were generated. */ - public function getBackupCodesGenerationDate(): ?\DateTimeInterface + public function getBackupCodesGenerationDate(): ?\DateTimeImmutable { return $this->backupCodesGenerationDate; } @@ -938,8 +991,6 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe return $this; } - - public function setSamlAttributes(array $attributes): void { //When mail attribute exists, set it @@ -969,4 +1020,34 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe $this->setEmail($attributes['urn:oid:1.2.840.113549.1.9.1'][0]); } } + + /** + * Return all API tokens of the user. + * @return Collection + */ + public function getApiTokens(): Collection + { + return $this->api_tokens; + } + + /** + * Add an API token to the user. + * @param ApiToken $apiToken + * @return void + */ + public function addApiToken(ApiToken $apiToken): void + { + $apiToken->setUser($this); + $this->api_tokens->add($apiToken); + } + + /** + * Remove an API token from the user. + * @param ApiToken $apiToken + * @return void + */ + public function removeApiToken(ApiToken $apiToken): void + { + $this->api_tokens->removeElement($apiToken); + } } diff --git a/src/Entity/UserSystem/WebauthnKey.php b/src/Entity/UserSystem/WebauthnKey.php index ee467bc3..b2716e07 100644 --- a/src/Entity/UserSystem/WebauthnKey.php +++ b/src/Entity/UserSystem/WebauthnKey.php @@ -22,16 +22,18 @@ declare(strict_types=1); */ namespace App\Entity\UserSystem; +use App\Entity\Contracts\TimeStampableInterface; use Doctrine\DBAL\Types\Types; use App\Entity\Base\TimestampTrait; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; use Webauthn\PublicKeyCredentialSource as BasePublicKeyCredentialSource; #[ORM\Entity] #[ORM\HasLifecycleCallbacks] #[ORM\Table(name: 'webauthn_keys')] -class WebauthnKey extends BasePublicKeyCredentialSource +class WebauthnKey extends BasePublicKeyCredentialSource implements TimeStampableInterface { use TimestampTrait; @@ -42,11 +44,15 @@ class WebauthnKey extends BasePublicKeyCredentialSource #[ORM\Column(type: Types::STRING)] #[NotBlank] + #[Length(max: 255)] protected string $name = ''; #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'webauthn_keys')] protected ?User $user = null; + #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)] + protected ?\DateTimeImmutable $last_time_used = null; + public function getName(): string { return $this->name; @@ -74,9 +80,22 @@ class WebauthnKey extends BasePublicKeyCredentialSource return $this->id; } + /** + * Retrieve the last time when the key was used. + */ + public function getLastTimeUsed(): ?\DateTimeImmutable + { + return $this->last_time_used; + } - - + /** + * Update the last time when the key was used. + * @return void + */ + public function updateLastTimeUsed(): void + { + $this->last_time_used = new \DateTimeImmutable('now'); + } public static function fromRegistration(BasePublicKeyCredentialSource $registration): self { diff --git a/src/EntityListeners/AttachmentDeleteListener.php b/src/EntityListeners/AttachmentDeleteListener.php index e9df5972..1f39b2d0 100644 --- a/src/EntityListeners/AttachmentDeleteListener.php +++ b/src/EntityListeners/AttachmentDeleteListener.php @@ -52,8 +52,8 @@ class AttachmentDeleteListener #[PreUpdate] public function preUpdateHandler(Attachment $attachment, PreUpdateEventArgs $event): void { - if ($event->hasChangedField('path')) { - $old_path = $event->getOldValue('path'); + if ($event->hasChangedField('internal_path')) { + $old_path = $event->getOldValue('internal_path'); //Dont delete file if the attachment uses a builtin ressource: if (Attachment::checkIfBuiltin($old_path)) { diff --git a/src/EntityListeners/TreeCacheInvalidationListener.php b/src/EntityListeners/TreeCacheInvalidationListener.php index 4cbcf8f8..eae7ce35 100644 --- a/src/EntityListeners/TreeCacheInvalidationListener.php +++ b/src/EntityListeners/TreeCacheInvalidationListener.php @@ -24,49 +24,52 @@ namespace App\EntityListeners; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\AbstractStructuralDBElement; -use App\Entity\LabelSystem\LabelProfile; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; -use App\Services\UserSystem\UserCacheKeyGenerator; -use Doctrine\ORM\Event\LifecycleEventArgs; +use App\Services\Cache\ElementCacheTagGenerator; +use App\Services\Cache\UserCacheKeyGenerator; +use Doctrine\ORM\Event\PostPersistEventArgs; +use Doctrine\ORM\Event\PostRemoveEventArgs; +use Doctrine\ORM\Event\PostUpdateEventArgs; use Doctrine\ORM\Mapping as ORM; -use function get_class; use Symfony\Contracts\Cache\TagAwareCacheInterface; class TreeCacheInvalidationListener { - public function __construct(protected TagAwareCacheInterface $cache, protected UserCacheKeyGenerator $keyGenerator) + public function __construct( + protected TagAwareCacheInterface $cache, + protected UserCacheKeyGenerator $keyGenerator, + protected ElementCacheTagGenerator $tagGenerator + ) { } #[ORM\PostUpdate] #[ORM\PostPersist] #[ORM\PostRemove] - public function invalidate(AbstractDBElement $element, LifecycleEventArgs $event): void + public function invalidate(AbstractDBElement $element, PostUpdateEventArgs|PostPersistEventArgs|PostRemoveEventArgs $event): void { - //If an element was changed, then invalidate all cached trees with this element class - if ($element instanceof AbstractStructuralDBElement || $element instanceof LabelProfile) { - $secure_class_name = str_replace('\\', '_', $element::class); - $this->cache->invalidateTags([$secure_class_name]); + //For all changes, we invalidate the cache for all elements of this class + $tags = [$this->tagGenerator->getElementTypeCacheTag($element)]; - //Trigger a sidebar reload for all users (see SidebarTreeUpdater service) - if(!$element instanceof LabelProfile) { - $this->cache->invalidateTags(['sidebar_tree_update']); - } + + //For changes on structural elements, we also invalidate the sidebar tree + if ($element instanceof AbstractStructuralDBElement) { + $tags[] = 'sidebar_tree_update'; } - //If a user change, then invalidate all cached trees for him + //For user changes, we invalidate the cache for this user if ($element instanceof User) { - $secure_class_name = str_replace('\\', '_', $element::class); - $tag = $this->keyGenerator->generateKey($element); - $this->cache->invalidateTags([$tag, $secure_class_name]); + $tags[] = $this->keyGenerator->generateKey($element); } /* If any group change, then invalidate all cached trees. Users Permissions can be inherited from groups, so a change in any group can cause big permisssion changes for users. So to be sure, invalidate all trees */ if ($element instanceof Group) { - $tag = 'groups'; - $this->cache->invalidateTags([$tag]); + $tags[] = 'groups'; } + + //Invalidate the cache for the given tags + $this->cache->invalidateTags($tags); } } diff --git a/src/EventListener/AddEditCommentRequestListener.php b/src/EventListener/AddEditCommentRequestListener.php new file mode 100644 index 00000000..33c72b3f --- /dev/null +++ b/src/EventListener/AddEditCommentRequestListener.php @@ -0,0 +1,62 @@ +. + */ + +declare(strict_types=1); + + +namespace App\EventListener; + +use App\Services\LogSystem\EventCommentHelper; +use Symfony\Component\EventDispatcher\Attribute\AsEventListener; +use Symfony\Component\HttpKernel\Event\RequestEvent; + +#[AsEventListener] +class AddEditCommentRequestListener +{ + public function __construct(private readonly EventCommentHelper $helper) + { + + } + + public function __invoke(RequestEvent $event) + { + if (!$event->isMainRequest()) { + return; + } + $request = $event->getRequest(); + + //Do not add comment if the request is a GET request + if ($request->isMethod('GET')) { + return; + } + + //Check if the user tries to access a /api/ endpoint, if not skip + if (!str_contains($request->getPathInfo(), '/api/')) { + return; + } + + //Extract the comment from the query parameter + $comment = $request->query->getString('_comment', ''); + + if ($comment !== '') { + $this->helper->setMessage($comment); + } + } +} \ No newline at end of file diff --git a/src/EventListener/AllowSlowNaturalSortListener.php b/src/EventListener/AllowSlowNaturalSortListener.php new file mode 100644 index 00000000..02ec6144 --- /dev/null +++ b/src/EventListener/AllowSlowNaturalSortListener.php @@ -0,0 +1,49 @@ +. + */ + +declare(strict_types=1); + + +namespace App\EventListener; + +use App\Doctrine\Functions\Natsort; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\EventDispatcher\Attribute\AsEventListener; +use Symfony\Component\HttpKernel\Event\RequestEvent; + +/** + * This is a workaround to the fact that we can not inject parameters into doctrine custom functions. + * Therefore we use this event listener to call the static function on the custom function, to inject the value, before + * any NATSORT function is called. + */ +#[AsEventListener] +class AllowSlowNaturalSortListener +{ + public function __construct( + #[Autowire(param: 'partdb.db.emulate_natural_sort')] + private readonly bool $allowNaturalSort) + { + } + + public function __invoke(RequestEvent $event) + { + Natsort::allowSlowNaturalSort($this->allowNaturalSort); + } +} \ No newline at end of file diff --git a/src/EventListener/ConsoleEnsureWebserverUserListener.php b/src/EventListener/ConsoleEnsureWebserverUserListener.php new file mode 100644 index 00000000..7c119304 --- /dev/null +++ b/src/EventListener/ConsoleEnsureWebserverUserListener.php @@ -0,0 +1,159 @@ +. + */ + +declare(strict_types=1); + + +namespace App\EventListener; + +use Symfony\Component\Console\ConsoleEvents; +use Symfony\Component\Console\Event\ConsoleCommandEvent; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\EventDispatcher\Attribute\AsEventListener; + +/** + * This event listener is called before any console command is executed and should ensure that the webserver + * user is used for all operations (and show a warning if not). This ensures that all files are created with the + * correct permissions. + * If the console is in non-interactive mode, a warning is shown, but the command is still executed. + */ +#[AsEventListener(ConsoleEvents::COMMAND)] +class ConsoleEnsureWebserverUserListener +{ + public function __construct( + #[Autowire('%kernel.project_dir%')] + private readonly string $project_root) + { + } + + public function __invoke(ConsoleCommandEvent $event): void + { + $input = $event->getInput(); + $io = new SymfonyStyle($event->getInput(), $event->getOutput()); + + //Check if we are (not) running as the webserver user + $webserver_user = $this->getWebserverUser(); + $running_user = $this->getRunningUser(); + + //Check if we are trying to run as root + if ($this->isRunningAsRoot()) { + //If the COMPOSER_ALLOW_SUPERUSER environment variable is set, we allow running as root + if ($_SERVER['COMPOSER_ALLOW_SUPERUSER'] ?? false) { + return; + } + + $io->warning('You are running this command as root. This is not recommended, as it can cause permission problems. Please run this command as the webserver user "'. ($webserver_user ?? '??') . '" instead.'); + $io->info('You might have already caused permission problems by running this command as wrong user. If you encounter issues with Part-DB, delete the var/cache directory completely and let it be recreated by Part-DB.'); + if ($input->isInteractive() && !$io->confirm('Do you want to continue?', false)) { + $event->disableCommand(); + } + + return; + } + + if ($webserver_user !== null && $running_user !== null && $webserver_user !== $running_user) { + $io->warning('You are running this command as the user "' . $running_user . '". This is not recommended, as it can cause permission problems. Please run this command as the webserver user "' . $webserver_user . '" instead.'); + $io->info('You might have already caused permission problems by running this command as wrong user. If you encounter issues with Part-DB, delete the var/cache directory completely and let it be recreated by Part-DB.'); + if ($input->isInteractive() && !$io->confirm('Do you want to continue?', false)) { + $event->disableCommand(); + } + + return; + } + } + + /** @noinspection PhpUndefinedFunctionInspection */ + private function isRunningAsRoot(): bool + { + //If we are on windows, we can't run as root + if (PHP_OS_FAMILY === 'Windows') { + return false; + } + + //Try to use the posix extension if available (Linux) + if (function_exists('posix_geteuid')) { + //Check if the current user is root + return posix_geteuid() === 0; + } + + //Otherwise we can't determine the username + return false; + } + + /** + * Determines the username of the user who started the current script if possible. + * Returns null if the username could not be determined. + * @return string|null + * @noinspection PhpUndefinedFunctionInspection + */ + private function getRunningUser(): ?string + { + //Try to use the posix extension if available (Linux) + if (function_exists('posix_geteuid') && function_exists('posix_getpwuid')) { + $id = posix_geteuid(); + + $user = posix_getpwuid($id); + //Try to get the username from the posix extension or return the id + return $user['name'] ?? ("ID: " . $id); + } + + //Otherwise we can't determine the username + return $_SERVER['USERNAME'] ?? $_SERVER['USER'] ?? null; + } + + private function getWebserverUser(): ?string + { + //Determine the webserver user, by checking who owns the uploads/ directory + $path_to_check = $this->project_root . '/uploads/'; + + //Determine the owner of this directory + if (!is_dir($path_to_check)) { + return null; + } + + //If we are on windows we need some special logic + if (PHP_OS_FAMILY === 'Windows') { + //If we have the COM extension available, we can use it to determine the owner + if (extension_loaded('com_dotnet')) { + /** @noinspection PhpUndefinedClassInspection */ + $su = new \COM("ADsSecurityUtility"); // Call interface + //@phpstan-ignore-next-line + $securityInfo = $su->GetSecurityDescriptor($path_to_check, 1, 1); // Call method + return $securityInfo->owner; // Get file owner + } + + //Otherwise we can't determine the owner + return null; + } + + //When we are on a POSIX system, we can use the fileowner function + $owner = fileowner($path_to_check); + + if (function_exists('posix_getpwuid')) { + $user = posix_getpwuid($owner); + //Try to get the username from the posix extension or return the id + return $user['name'] ?? ("ID: " . $owner); + } + + return null; + } + +} \ No newline at end of file diff --git a/src/EventListener/DisallowSearchEngineIndexingRequestListener.php b/src/EventListener/DisallowSearchEngineIndexingRequestListener.php new file mode 100644 index 00000000..b969b6b2 --- /dev/null +++ b/src/EventListener/DisallowSearchEngineIndexingRequestListener.php @@ -0,0 +1,54 @@ +. + */ + +declare(strict_types=1); + + +namespace App\EventListener; + +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\EventDispatcher\Attribute\AsEventListener; +use Symfony\Component\HttpKernel\Event\ResponseEvent; + +#[AsEventListener] +class DisallowSearchEngineIndexingRequestListener +{ + private const HEADER_NAME = 'X-Robots-Tag'; + + private readonly bool $enabled; + + public function __construct(#[Autowire(param: 'partdb.demo_mode')] bool $demo_mode) + { + // Disable this listener in demo mode + $this->enabled = !$demo_mode; + } + + public function __invoke(ResponseEvent $event): void + { + //Skip if disabled + if (!$this->enabled) { + return; + } + + if (!$event->getResponse()->headers->has(self::HEADER_NAME)) { + $event->getResponse()->headers->set(self::HEADER_NAME, 'noindex'); + } + } +} \ No newline at end of file diff --git a/src/EventSubscriber/LogSystem/EventLoggerSubscriber.php b/src/EventListener/LogSystem/EventLoggerListener.php similarity index 97% rename from src/EventSubscriber/LogSystem/EventLoggerSubscriber.php rename to src/EventListener/LogSystem/EventLoggerListener.php index b3f07a9b..6fe3d8dc 100644 --- a/src/EventSubscriber/LogSystem/EventLoggerSubscriber.php +++ b/src/EventListener/LogSystem/EventLoggerListener.php @@ -20,7 +20,7 @@ declare(strict_types=1); -namespace App\EventSubscriber\LogSystem; +namespace App\EventListener\LogSystem; use App\Entity\Attachments\Attachment; use App\Entity\Base\AbstractDBElement; @@ -38,7 +38,7 @@ use App\Entity\UserSystem\User; use App\Services\LogSystem\EventCommentHelper; use App\Services\LogSystem\EventLogger; use App\Services\LogSystem\EventUndoHelper; -use Doctrine\Common\EventSubscriber; +use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Event\OnFlushEventArgs; use Doctrine\ORM\Event\PostFlushEventArgs; @@ -50,7 +50,10 @@ use Symfony\Component\Serializer\SerializerInterface; /** * This event subscriber writes to the event log when entities are changed, removed, created. */ -class EventLoggerSubscriber implements EventSubscriber +#[AsDoctrineListener(event: Events::onFlush)] +#[AsDoctrineListener(event: Events::postPersist)] +#[AsDoctrineListener(event: Events::postFlush)] +class EventLoggerListener { /** * @var array The given fields will not be saved, because they contain sensitive information @@ -187,15 +190,6 @@ class EventLoggerSubscriber implements EventSubscriber return true; } - public function getSubscribedEvents(): array - { - return[ - Events::onFlush, - Events::postPersist, - Events::postFlush, - ]; - } - protected function logElementDeleted(AbstractDBElement $entity, EntityManagerInterface $em): void { $log = new ElementDeletedLogEntry($entity); diff --git a/src/EventSubscriber/LogSystem/LogDBMigrationSubscriber.php b/src/EventListener/LogSystem/LogDBMigrationListener.php similarity index 92% rename from src/EventSubscriber/LogSystem/LogDBMigrationSubscriber.php rename to src/EventListener/LogSystem/LogDBMigrationListener.php index 07ec8ea4..c8b60e18 100644 --- a/src/EventSubscriber/LogSystem/LogDBMigrationSubscriber.php +++ b/src/EventListener/LogSystem/LogDBMigrationListener.php @@ -20,11 +20,11 @@ declare(strict_types=1); -namespace App\EventSubscriber\LogSystem; +namespace App\EventListener\LogSystem; use App\Entity\LogSystem\DatabaseUpdatedLogEntry; use App\Services\LogSystem\EventLogger; -use Doctrine\Common\EventSubscriber; +use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener; use Doctrine\Migrations\DependencyFactory; use Doctrine\Migrations\Event\MigrationsEventArgs; use Doctrine\Migrations\Events; @@ -32,7 +32,9 @@ use Doctrine\Migrations\Events; /** * This subscriber logs databaseMigrations to Event log. */ -class LogDBMigrationSubscriber implements EventSubscriber +#[AsDoctrineListener(event: Events::onMigrationsMigrated)] +#[AsDoctrineListener(event: Events::onMigrationsMigrating)] +class LogDBMigrationListener { protected ?string $old_version = null; protected ?string $new_version = null; diff --git a/src/EventSubscriber/LogSystem/LogLogoutEventSubscriber.php b/src/EventSubscriber/LogSystem/LogLogoutEventSubscriber.php index 87d97b1e..7e6d2da7 100644 --- a/src/EventSubscriber/LogSystem/LogLogoutEventSubscriber.php +++ b/src/EventSubscriber/LogSystem/LogLogoutEventSubscriber.php @@ -27,7 +27,6 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use App\Entity\LogSystem\UserLogoutLogEntry; use App\Entity\UserSystem\User; use App\Services\LogSystem\EventLogger; -use Symfony\Component\EventDispatcher\Attribute\AsEventListener; use Symfony\Component\Security\Http\Event\LogoutEvent; /** diff --git a/src/EventSubscriber/LogSystem/SecurityEventLoggerSubscriber.php b/src/EventSubscriber/LogSystem/SecurityEventLoggerSubscriber.php index d9af32c5..7880a41d 100644 --- a/src/EventSubscriber/LogSystem/SecurityEventLoggerSubscriber.php +++ b/src/EventSubscriber/LogSystem/SecurityEventLoggerSubscriber.php @@ -48,7 +48,6 @@ use App\Events\SecurityEvents; use App\Services\LogSystem\EventLogger; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Security\Http\Event\SwitchUserEvent; /** * This subscriber writes entries to log if a security related event happens (e.g. the user changes its password). diff --git a/src/EventSubscriber/RedirectToHttpsSubscriber.php b/src/EventSubscriber/RedirectToHttpsSubscriber.php new file mode 100644 index 00000000..7089109e --- /dev/null +++ b/src/EventSubscriber/RedirectToHttpsSubscriber.php @@ -0,0 +1,72 @@ +. + */ + +declare(strict_types=1); + + +namespace App\EventSubscriber; + +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\Security\Http\HttpUtils; + +/** + * The purpose of this event listener is (if enabled) to redirect all requests to https. + */ +final class RedirectToHttpsSubscriber implements EventSubscriberInterface +{ + + public function __construct( + #[Autowire('%env(bool:REDIRECT_TO_HTTPS)%')] + private readonly bool $enabled, + private readonly HttpUtils $httpUtils) + { + } + + public static function getSubscribedEvents(): array + { + return [ + KernelEvents::REQUEST => 'onKernelRequest', + ]; + } + + public function onKernelRequest(RequestEvent $event): void + { + //If the feature is disabled, or we are not the main request, we do nothing + if (!$this->enabled || !$event->isMainRequest()) { + return; + } + + + $request = $event->getRequest(); + + //If the request is already https, we do nothing + if ($request->isSecure()) { + return; + } + + + //Change the request to https + $new_url = str_replace('http://', 'https://' ,$request->getUri()); + $event->setResponse($this->httpUtils->createRedirectResponse($event->getRequest(), $new_url)); + } +} \ No newline at end of file diff --git a/src/EventSubscriber/SwitchUserEventSubscriber.php b/src/EventSubscriber/SwitchUserEventSubscriber.php index a7f2e39c..b68f6b4f 100644 --- a/src/EventSubscriber/SwitchUserEventSubscriber.php +++ b/src/EventSubscriber/SwitchUserEventSubscriber.php @@ -38,7 +38,7 @@ class SwitchUserEventSubscriber implements EventSubscriberInterface { } - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { return [ 'security.switch_user' => 'onSwitchUser', diff --git a/src/EventSubscriber/UserSystem/PasswordChangeNeededSubscriber.php b/src/EventSubscriber/UserSystem/PasswordChangeNeededSubscriber.php index 8cf0dfd1..2eb32436 100644 --- a/src/EventSubscriber/UserSystem/PasswordChangeNeededSubscriber.php +++ b/src/EventSubscriber/UserSystem/PasswordChangeNeededSubscriber.php @@ -27,9 +27,7 @@ use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; use Symfony\Component\HttpFoundation\Session\Session; -use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Security\Http\HttpUtils; diff --git a/src/Exceptions/TwigModeException.php b/src/Exceptions/TwigModeException.php index adcc86aa..b76d14d3 100644 --- a/src/Exceptions/TwigModeException.php +++ b/src/Exceptions/TwigModeException.php @@ -46,8 +46,23 @@ use Twig\Error\Error; class TwigModeException extends RuntimeException { + private const PROJECT_PATH = __DIR__ . '/../../'; + public function __construct(?Error $previous = null) { parent::__construct($previous->getMessage(), 0, $previous); } + + /** + * Returns the message of this exception, where it is tried to remove any sensitive information (like filepaths). + * @return string + */ + public function getSafeMessage(): string + { + //Resolve project root path + $projectPath = realpath(self::PROJECT_PATH); + + //Remove occurrences of the project path from the message + return str_replace($projectPath, '[Part-DB Root Folder]', $this->getMessage()); + } } diff --git a/src/Form/AdminPages/BaseEntityAdminForm.php b/src/Form/AdminPages/BaseEntityAdminForm.php index 19af4de8..d1a0ffd0 100644 --- a/src/Form/AdminPages/BaseEntityAdminForm.php +++ b/src/Form/AdminPages/BaseEntityAdminForm.php @@ -35,7 +35,6 @@ use App\Form\Type\MasterPictureAttachmentType; use App\Form\Type\RichTextEditorType; use App\Form\Type\StructuralEntityType; use App\Services\LogSystem\EventCommentNeededHelper; -use function get_class; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; diff --git a/src/Form/AdminPages/CategoryAdminForm.php b/src/Form/AdminPages/CategoryAdminForm.php index 10a56646..44c1dede 100644 --- a/src/Form/AdminPages/CategoryAdminForm.php +++ b/src/Form/AdminPages/CategoryAdminForm.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace App\Form\AdminPages; use App\Entity\Base\AbstractNamedDBElement; +use App\Form\Part\EDA\EDACategoryInfoType; use App\Form\Type\RichTextEditorType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -104,5 +105,11 @@ class CategoryAdminForm extends BaseEntityAdminForm ], 'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity), ]); + + //EDA info + $builder->add('eda_info', EDACategoryInfoType::class, [ + 'label' => false, + 'required' => false, + ]); } } diff --git a/src/Form/AdminPages/FootprintAdminForm.php b/src/Form/AdminPages/FootprintAdminForm.php index a01e91bc..f96564d0 100644 --- a/src/Form/AdminPages/FootprintAdminForm.php +++ b/src/Form/AdminPages/FootprintAdminForm.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace App\Form\AdminPages; use App\Entity\Base\AbstractNamedDBElement; +use App\Form\Part\EDA\EDAFootprintInfoType; use App\Form\Type\MasterPictureAttachmentType; use Symfony\Component\Form\FormBuilderInterface; @@ -37,5 +38,11 @@ class FootprintAdminForm extends BaseEntityAdminForm 'filter' => '3d_model', 'entity' => $entity, ]); + + //EDA info + $builder->add('eda_info', EDAFootprintInfoType::class, [ + 'label' => false, + 'required' => false, + ]); } } diff --git a/src/Form/AttachmentFormType.php b/src/Form/AttachmentFormType.php index 71c0bedd..957d692b 100644 --- a/src/Form/AttachmentFormType.php +++ b/src/Form/AttachmentFormType.php @@ -48,8 +48,16 @@ use Symfony\Contracts\Translation\TranslatorInterface; class AttachmentFormType extends AbstractType { - public function __construct(protected AttachmentManager $attachment_helper, protected UrlGeneratorInterface $urlGenerator, protected Security $security, protected AttachmentSubmitHandler $submitHandler, protected TranslatorInterface $translator, protected bool $allow_attachments_download, protected string $max_file_size) - { + public function __construct( + protected AttachmentManager $attachment_helper, + protected UrlGeneratorInterface $urlGenerator, + protected Security $security, + protected AttachmentSubmitHandler $submitHandler, + protected TranslatorInterface $translator, + protected bool $allow_attachments_download, + protected bool $download_by_default, + protected string $max_file_size + ) { } public function buildForm(FormBuilderInterface $builder, array $options): void @@ -85,7 +93,8 @@ class AttachmentFormType extends AbstractType 'required' => false, 'attr' => [ 'data-controller' => 'elements--attachment-autocomplete', - 'data-autocomplete' => $this->urlGenerator->generate('typeahead_builtInRessources', ['query' => '__QUERY__']), + 'data-autocomplete' => $this->urlGenerator->generate('typeahead_builtInRessources', + ['query' => '__QUERY__']), //Disable browser autocomplete 'autocomplete' => 'off', ], @@ -132,6 +141,12 @@ class AttachmentFormType extends AbstractType } if (!$file instanceof UploadedFile) { + //When no file was uploaded, but a URL was entered, try to determine the attachment name from the URL + if ((trim($attachment->getName()) === '') && ($attachment->getURL() !== null && $attachment->getURL() !== '')) { + $name = basename(parse_url($attachment->getURL(), PHP_URL_PATH)); + $attachment->setName($name); + } + return; } @@ -159,6 +174,30 @@ class AttachmentFormType extends AbstractType } } ); + + //If the attachment should be downloaded by default (and is download allowed at all), register a listener, + // which sets the downloadURL checkbox to true for new attachments + if ($this->download_by_default && $this->allow_attachments_download) { + $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event): void { + $form = $event->getForm(); + $attachment = $form->getData(); + + if (!$attachment instanceof Attachment && $attachment !== null) { + return; + } + + //If the attachment was not created yet, set the downloadURL checkbox to true + if ($attachment === null || $attachment->getId() === null) { + $checkbox = $form->get('downloadURL'); + //Ensure that the checkbox is not disabled + if ($checkbox->isDisabled()) { + return; + } + //Set the checkbox + $checkbox->setData(true); + } + }); + } } public function configureOptions(OptionsResolver $resolver): void diff --git a/src/Form/Filters/AttachmentFilterType.php b/src/Form/Filters/AttachmentFilterType.php index 92cb20b6..ff80bd38 100644 --- a/src/Form/Filters/AttachmentFilterType.php +++ b/src/Form/Filters/AttachmentFilterType.php @@ -32,7 +32,7 @@ use App\Entity\Attachments\FootprintAttachment; use App\Entity\Attachments\GroupAttachment; use App\Entity\Attachments\LabelAttachment; use App\Entity\Attachments\PartAttachment; -use App\Entity\Attachments\StorelocationAttachment; +use App\Entity\Attachments\StorageLocationAttachment; use App\Entity\Attachments\SupplierAttachment; use App\Entity\Attachments\UserAttachment; use App\Entity\Parts\Manufacturer; @@ -85,7 +85,7 @@ class AttachmentFilterType extends AbstractType 'label_profile.label' => LabelAttachment::class, 'manufacturer.label' => Manufacturer::class, 'measurement_unit.label' => MeasurementUnit::class, - 'storelocation.label' => StorelocationAttachment::class, + 'storelocation.label' => StorageLocationAttachment::class, 'supplier.label' => SupplierAttachment::class, 'user.label' => UserAttachment::class, ] @@ -100,6 +100,15 @@ class AttachmentFilterType extends AbstractType 'label' => 'attachment.edit.show_in_table' ]); + $builder->add('originalFileName', TextConstraintType::class, [ + 'label' => 'attachment.file_name' + ]); + + $builder->add('externalLink', TextConstraintType::class, [ + 'label' => 'attachment.table.external_link' + ]); + + $builder->add('lastModified', DateTimeConstraintType::class, [ 'label' => 'lastModified' ]); diff --git a/src/Form/Filters/Constraints/TextConstraintType.php b/src/Form/Filters/Constraints/TextConstraintType.php index 492278d2..c1007cf9 100644 --- a/src/Form/Filters/Constraints/TextConstraintType.php +++ b/src/Form/Filters/Constraints/TextConstraintType.php @@ -25,7 +25,6 @@ namespace App\Form\Filters\Constraints; use App\DataTables\Filters\Constraints\TextConstraint; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\Extension\Core\Type\SearchType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; diff --git a/src/Form/Filters/LogFilterType.php b/src/Form/Filters/LogFilterType.php index 0d8257f4..42b367b7 100644 --- a/src/Form/Filters/LogFilterType.php +++ b/src/Form/Filters/LogFilterType.php @@ -23,15 +23,9 @@ declare(strict_types=1); namespace App\Form\Filters; use App\DataTables\Filters\LogFilter; -use App\Entity\Attachments\Attachment; -use App\Entity\Attachments\AttachmentType; use App\Entity\LogSystem\LogLevel; use App\Entity\LogSystem\LogTargetType; use App\Entity\LogSystem\PartStockChangedLogEntry; -use App\Entity\ProjectSystem\Project; -use App\Entity\ProjectSystem\ProjectBOMEntry; -use App\Entity\LabelSystem\LabelProfile; -use App\Entity\LogSystem\AbstractLogEntry; use App\Entity\LogSystem\CollectionElementDeleted; use App\Entity\LogSystem\DatabaseUpdatedLogEntry; use App\Entity\LogSystem\ElementCreatedLogEntry; @@ -42,21 +36,6 @@ use App\Entity\LogSystem\SecurityEventLogEntry; use App\Entity\LogSystem\UserLoginLogEntry; use App\Entity\LogSystem\UserLogoutLogEntry; use App\Entity\LogSystem\UserNotAllowedLogEntry; -use App\Entity\Parameters\AbstractParameter; -use App\Entity\Parts\Category; -use App\Entity\Parts\Footprint; -use App\Entity\Parts\Manufacturer; -use App\Entity\Parts\MeasurementUnit; -use App\Entity\Parts\Part; -use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; -use App\Entity\Parts\Supplier; -use App\Entity\PriceInformations\Currency; -use App\Entity\PriceInformations\Orderdetail; -use App\Entity\PriceInformations\Pricedetail; -use App\Entity\UserSystem\Group; -use App\Entity\UserSystem\User; -use App\Form\Filters\Constraints\ChoiceConstraintType; use App\Form\Filters\Constraints\DateTimeConstraintType; use App\Form\Filters\Constraints\EnumConstraintType; use App\Form\Filters\Constraints\InstanceOfConstraintType; @@ -148,6 +127,7 @@ class LogFilterType extends AbstractType LogTargetType::MEASUREMENT_UNIT => 'measurement_unit.label', LogTargetType::PARAMETER => 'parameter.label', LogTargetType::LABEL_PROFILE => 'label_profile.label', + LogTargetType::PART_ASSOCIATION => 'part_association.label', }, ]); diff --git a/src/Form/Filters/PartFilterType.php b/src/Form/Filters/PartFilterType.php index 0a60dc4c..dfe449d1 100644 --- a/src/Form/Filters/PartFilterType.php +++ b/src/Form/Filters/PartFilterType.php @@ -29,8 +29,9 @@ use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; +use App\Entity\ProjectSystem\Project; use App\Form\Filters\Constraints\BooleanConstraintType; use App\Form\Filters\Constraints\ChoiceConstraintType; use App\Form\Filters\Constraints\DateTimeConstraintType; @@ -40,19 +41,21 @@ use App\Form\Filters\Constraints\StructuralEntityConstraintType; use App\Form\Filters\Constraints\TagsConstraintType; use App\Form\Filters\Constraints\TextConstraintType; use App\Form\Filters\Constraints\UserEntityConstraintType; -use Svg\Tag\Text; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; -use Symfony\Component\Form\Extension\Core\Type\DateTimeType; use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\ResetType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\SubmitButton; use Symfony\Component\OptionsResolver\OptionsResolver; class PartFilterType extends AbstractType { + public function __construct(private readonly Security $security) + { + } + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ @@ -178,8 +181,8 @@ class PartFilterType extends AbstractType $builder->add('orderdetailsCount', NumberConstraintType::class, [ 'label' => 'part.filter.orderdetails_count', - 'step' => 1, - 'min' => 0, + 'step' => 1, + 'min' => 0, ]); $builder->add('obsolete', BooleanConstraintType::class, [ @@ -191,7 +194,7 @@ class PartFilterType extends AbstractType */ $builder->add('storelocation', StructuralEntityConstraintType::class, [ 'label' => 'storelocation.label', - 'entity_class' => Storelocation::class + 'entity_class' => StorageLocation::class ]); $builder->add('minAmount', NumberConstraintType::class, [ @@ -271,6 +274,31 @@ class PartFilterType extends AbstractType 'min' => 0, ]); + /************************************************************************** + * Project tab + **************************************************************************/ + if ($this->security->isGranted('read', Project::class)) { + $builder + ->add('project', StructuralEntityConstraintType::class, [ + 'label' => 'project.label', + 'entity_class' => Project::class + ]) + ->add('bomQuantity', NumberConstraintType::class, [ + 'label' => 'project.bom.quantity', + 'min' => 0, + 'step' => "any", + ]) + ->add('bomName', TextConstraintType::class, [ + 'label' => 'project.bom.name', + ]) + ->add('bomComment', TextConstraintType::class, [ + 'label' => 'project.bom.comment', + ]) + ; + + } + + $builder->add('submit', SubmitType::class, [ 'label' => 'filter.submit', ]); diff --git a/src/Form/InfoProviderSystem/ProviderSelectType.php b/src/Form/InfoProviderSystem/ProviderSelectType.php index 6ebe663d..a9373390 100644 --- a/src/Form/InfoProviderSystem/ProviderSelectType.php +++ b/src/Form/InfoProviderSystem/ProviderSelectType.php @@ -25,7 +25,6 @@ namespace App\Form\InfoProviderSystem; use App\Services\InfoProviderSystem\ProviderRegistry; use App\Services\InfoProviderSystem\Providers\InfoProviderInterface; -use Hoa\Compiler\Llk\Rule\Choice; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ChoiceList; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; @@ -43,12 +42,12 @@ class ProviderSelectType extends AbstractType return ChoiceType::class; } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'choices' => $this->providerRegistry->getActiveProviders(), - 'choice_label' => ChoiceList::label($this, fn (?InfoProviderInterface $choice) => $choice?->getProviderInfo()['name']), - 'choice_value' => ChoiceList::value($this, fn(?InfoProviderInterface $choice) => $choice?->getProviderKey()), + 'choice_label' => ChoiceList::label($this, static fn (?InfoProviderInterface $choice) => $choice?->getProviderInfo()['name']), + 'choice_value' => ChoiceList::value($this, static fn(?InfoProviderInterface $choice) => $choice?->getProviderKey()), 'multiple' => true, ]); diff --git a/src/Form/LabelOptionsType.php b/src/Form/LabelOptionsType.php index 0b15046c..ad458374 100644 --- a/src/Form/LabelOptionsType.php +++ b/src/Form/LabelOptionsType.php @@ -48,7 +48,6 @@ use Symfony\Bundle\SecurityBundle\Security; use App\Entity\LabelSystem\LabelOptions; use App\Form\Type\RichTextEditorType; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\EnumType; use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; diff --git a/src/Form/LabelSystem/LabelDialogType.php b/src/Form/LabelSystem/LabelDialogType.php index 33c79797..f2710b19 100644 --- a/src/Form/LabelSystem/LabelDialogType.php +++ b/src/Form/LabelSystem/LabelDialogType.php @@ -71,6 +71,22 @@ class LabelDialogType extends AbstractType 'label' => false, 'disabled' => !$this->security->isGranted('@labels.edit_options') || $options['disable_options'], ]); + + $builder->add('save_profile_name', TextType::class, [ + 'required' => false, + 'attr' =>[ + 'placeholder' => 'label_generator.save_profile_name', + ] + ]); + + $builder->add('save_profile', SubmitType::class, [ + 'label' => 'label_generator.save_profile', + 'disabled' => !$this->security->isGranted('@labels.create_profiles'), + 'attr' => [ + 'class' => 'btn btn-outline-success' + ] + ]); + $builder->add('update', SubmitType::class, [ 'label' => 'label_generator.update', ]); diff --git a/src/Form/LabelSystem/ScanDialogType.php b/src/Form/LabelSystem/ScanDialogType.php index 163ee9c2..13ff8e6f 100644 --- a/src/Form/LabelSystem/ScanDialogType.php +++ b/src/Form/LabelSystem/ScanDialogType.php @@ -41,7 +41,10 @@ declare(strict_types=1); namespace App\Form\LabelSystem; +use App\Services\LabelSystem\BarcodeScanner\BarcodeSourceType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\EnumType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; @@ -53,12 +56,34 @@ class ScanDialogType extends AbstractType { $builder->add('input', TextType::class, [ 'label' => 'scan_dialog.input', + //Do not trim the input, otherwise this damages Format06 barcodes which end with non-printable characters + 'trim' => false, 'attr' => [ 'autofocus' => true, 'id' => 'scan_dialog_input', ], ]); + $builder->add('mode', EnumType::class, [ + 'label' => 'scan_dialog.mode', + 'expanded' => true, + 'class' => BarcodeSourceType::class, + 'required' => false, + 'placeholder' => 'scan_dialog.mode.auto', + 'choice_label' => fn (?BarcodeSourceType $enum) => match($enum) { + null => 'scan_dialog.mode.auto', + BarcodeSourceType::INTERNAL => 'scan_dialog.mode.internal', + BarcodeSourceType::IPN => 'scan_dialog.mode.ipn', + BarcodeSourceType::USER_DEFINED => 'scan_dialog.mode.user', + BarcodeSourceType::EIGP114 => 'scan_dialog.mode.eigp' + }, + ]); + + $builder->add('info_mode', CheckboxType::class, [ + 'label' => 'scan_dialog.info_mode', + 'required' => false, + ]); + $builder->add('submit', SubmitType::class, [ 'label' => 'scan_dialog.submit', ]); diff --git a/src/Form/ParameterType.php b/src/Form/ParameterType.php index 66e664be..4c2174ae 100644 --- a/src/Form/ParameterType.php +++ b/src/Form/ParameterType.php @@ -50,9 +50,10 @@ use App\Entity\Parameters\FootprintParameter; use App\Entity\Parameters\GroupParameter; use App\Entity\Parameters\ManufacturerParameter; use App\Entity\Parameters\PartParameter; -use App\Entity\Parameters\StorelocationParameter; +use App\Entity\Parameters\StorageLocationParameter; use App\Entity\Parameters\SupplierParameter; use App\Entity\Parts\MeasurementUnit; +use App\Form\Type\ExponentialNumberType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -93,7 +94,7 @@ class ParameterType extends AbstractType ], ]); - $builder->add('value_max', NumberType::class, [ + $builder->add('value_max', ExponentialNumberType::class, [ 'label' => false, 'required' => false, 'html5' => true, @@ -101,10 +102,10 @@ class ParameterType extends AbstractType 'step' => 'any', 'placeholder' => 'parameters.max.placeholder', 'class' => 'form-control-sm', - 'style' => 'max-width: 12ch;', + 'style' => 'max-width: 25ch;', ], ]); - $builder->add('value_min', NumberType::class, [ + $builder->add('value_min', ExponentialNumberType::class, [ 'label' => false, 'required' => false, 'html5' => true, @@ -112,10 +113,10 @@ class ParameterType extends AbstractType 'step' => 'any', 'placeholder' => 'parameters.min.placeholder', 'class' => 'form-control-sm', - 'style' => 'max-width: 12ch;', + 'style' => 'max-width: 25ch;', ], ]); - $builder->add('value_typical', NumberType::class, [ + $builder->add('value_typical', ExponentialNumberType::class, [ 'label' => false, 'required' => false, 'html5' => true, @@ -123,7 +124,7 @@ class ParameterType extends AbstractType 'step' => 'any', 'placeholder' => 'parameters.typical.placeholder', 'class' => 'form-control-sm', - 'style' => 'max-width: 12ch;', + 'style' => 'max-width: 25ch;', ], ]); $builder->add('unit', TextType::class, [ @@ -163,7 +164,7 @@ class ParameterType extends AbstractType GroupParameter::class => 'group', ManufacturerParameter::class => 'manufacturer', MeasurementUnit::class => 'measurement_unit', - StorelocationParameter::class => 'storelocation', + StorageLocationParameter::class => 'storelocation', SupplierParameter::class => 'supplier', ]; diff --git a/src/Form/Part/EDA/EDACategoryInfoType.php b/src/Form/Part/EDA/EDACategoryInfoType.php new file mode 100644 index 00000000..f45bd697 --- /dev/null +++ b/src/Form/Part/EDA/EDACategoryInfoType.php @@ -0,0 +1,87 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Part\EDA; + +use App\Entity\EDA\EDACategoryInfo; +use App\Form\Type\TriStateCheckboxType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +use function Symfony\Component\Translation\t; + +class EDACategoryInfoType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('reference_prefix', TextType::class, [ + 'label' => 'eda_info.reference_prefix', + 'attr' => [ + 'placeholder' => t('eda_info.reference_prefix.placeholder'), + ] + ] + ) + ->add('visibility', TriStateCheckboxType::class, [ + 'help' => 'eda_info.visibility.help', + 'label' => 'eda_info.visibility', + ]) + ->add('exclude_from_bom', TriStateCheckboxType::class, [ + 'label' => 'eda_info.exclude_from_bom', + 'label_attr' => [ + 'class' => 'checkbox-inline' + ] + ]) + ->add('exclude_from_board', TriStateCheckboxType::class, [ + 'label' => 'eda_info.exclude_from_board', + 'label_attr' => [ + 'class' => 'checkbox-inline' + ] + ]) + ->add('exclude_from_sim', TriStateCheckboxType::class, [ + 'label' => 'eda_info.exclude_from_sim', + 'label_attr' => [ + 'class' => 'checkbox-inline' + ] + ]) + ->add('kicad_symbol', KicadFieldAutocompleteType::class, [ + 'label' => 'eda_info.kicad_symbol', + 'type' => KicadFieldAutocompleteType::TYPE_SYMBOL, + 'attr' => [ + 'placeholder' => t('eda_info.kicad_symbol.placeholder'), + ] + ]) + ; + + + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => EDACategoryInfo::class, + ]); + } +} \ No newline at end of file diff --git a/src/Form/Part/EDA/EDAFootprintInfoType.php b/src/Form/Part/EDA/EDAFootprintInfoType.php new file mode 100644 index 00000000..bdfa346c --- /dev/null +++ b/src/Form/Part/EDA/EDAFootprintInfoType.php @@ -0,0 +1,55 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Part\EDA; + +use App\Entity\EDA\EDAFootprintInfo; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +use function Symfony\Component\Translation\t; + +class EDAFootprintInfoType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('kicad_footprint', KicadFieldAutocompleteType::class, [ + 'type' => KicadFieldAutocompleteType::TYPE_FOOTPRINT, + 'label' => 'eda_info.kicad_footprint', + 'attr' => [ + 'placeholder' => t('eda_info.kicad_footprint.placeholder'), + ] + ]); + + + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => EDAFootprintInfo::class, + ]); + } +} \ No newline at end of file diff --git a/src/Form/Part/EDA/EDAPartInfoType.php b/src/Form/Part/EDA/EDAPartInfoType.php new file mode 100644 index 00000000..e8cac681 --- /dev/null +++ b/src/Form/Part/EDA/EDAPartInfoType.php @@ -0,0 +1,97 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Part\EDA; + +use App\Entity\EDA\EDAPartInfo; +use App\Form\Type\TriStateCheckboxType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +use function Symfony\Component\Translation\t; + +class EDAPartInfoType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('reference_prefix', TextType::class, [ + 'label' => 'eda_info.reference_prefix', + 'attr' => [ + 'placeholder' => t('eda_info.reference_prefix.placeholder'), + ] + ] + ) + ->add('value', TextType::class, [ + 'label' => 'eda_info.value', + 'attr' => [ + 'placeholder' => t('eda_info.value.placeholder'), + ] + ]) + ->add('visibility', TriStateCheckboxType::class, [ + 'help' => 'eda_info.visibility.help', + 'label' => 'eda_info.visibility', + ]) + ->add('exclude_from_bom', TriStateCheckboxType::class, [ + 'label' => 'eda_info.exclude_from_bom', + 'label_attr' => [ + 'class' => 'checkbox-inline' + ] + ]) + ->add('exclude_from_board', TriStateCheckboxType::class, [ + 'label' => 'eda_info.exclude_from_board', + 'label_attr' => [ + 'class' => 'checkbox-inline' + ] + ]) + ->add('exclude_from_sim', TriStateCheckboxType::class, [ + 'label' => 'eda_info.exclude_from_sim', + 'label_attr' => [ + 'class' => 'checkbox-inline' + ] + ]) + ->add('kicad_symbol', KicadFieldAutocompleteType::class, [ + 'label' => 'eda_info.kicad_symbol', + 'type' => KicadFieldAutocompleteType::TYPE_SYMBOL, + 'attr' => [ + 'placeholder' => t('eda_info.kicad_symbol.placeholder'), + ] + ]) + ->add('kicad_footprint', KicadFieldAutocompleteType::class, [ + 'label' => 'eda_info.kicad_footprint', + 'type' => KicadFieldAutocompleteType::TYPE_FOOTPRINT, + 'attr' => [ + 'placeholder' => t('eda_info.kicad_footprint.placeholder'), + ] + ]); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => EDAPartInfo::class, + ]); + } +} \ No newline at end of file diff --git a/src/Form/Part/EDA/KicadFieldAutocompleteType.php b/src/Form/Part/EDA/KicadFieldAutocompleteType.php new file mode 100644 index 00000000..50de81d0 --- /dev/null +++ b/src/Form/Part/EDA/KicadFieldAutocompleteType.php @@ -0,0 +1,61 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Part\EDA; + +use App\Form\Type\StaticFileAutocompleteType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * This is a specialized version of the StaticFileAutocompleteType, which loads the different types of Kicad lists. + */ +class KicadFieldAutocompleteType extends AbstractType +{ + public const TYPE_FOOTPRINT = 'footprint'; + public const TYPE_SYMBOL = 'symbol'; + + //Do not use a leading slash here! otherwise it will not work under prefixed reverse proxies + public const FOOTPRINT_PATH = 'kicad/footprints.txt'; + public const SYMBOL_PATH = 'kicad/symbols.txt'; + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired('type'); + $resolver->setAllowedValues('type', [self::TYPE_SYMBOL, self::TYPE_FOOTPRINT]); + + $resolver->setDefaults([ + 'file' => fn(Options $options) => match ($options['type']) { + self::TYPE_FOOTPRINT => self::FOOTPRINT_PATH, + self::TYPE_SYMBOL => self::SYMBOL_PATH, + default => throw new \InvalidArgumentException('Invalid type'), + } + ]); + } + + public function getParent(): string + { + return StaticFileAutocompleteType::class; + } +} \ No newline at end of file diff --git a/src/Form/Part/PartAssociationType.php b/src/Form/Part/PartAssociationType.php new file mode 100644 index 00000000..bf9ec4f9 --- /dev/null +++ b/src/Form/Part/PartAssociationType.php @@ -0,0 +1,73 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Part; + +use App\Entity\Parts\AssociationType; +use App\Entity\Parts\PartAssociation; +use App\Form\Type\PartSelectType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\EnumType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class PartAssociationType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('other', PartSelectType::class, [ + 'label' => 'part_association.edit.other_part', + ]) + ->add('type', EnumType::class, [ + 'class' => AssociationType::class, + 'label' => 'part_association.edit.type', + 'choice_label' => fn(AssociationType $type) => $type->getTranslationKey(), + 'help' => 'part_association.edit.type.help', + 'attr' => [ + 'data-pages--association-edit-type-select-target' => 'select' + ] + ]) + ->add('other_type', TextType::class, [ + 'required' => false, + 'label' => 'part_association.edit.other_type', + 'row_attr' => [ + 'data-pages--association-edit-type-select-target' => 'display' + ] + ]) + ->add('comment', TextType::class, [ + 'required' => false, + 'label' => 'part_association.edit.comment' + ]) + ; + + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => PartAssociation::class, + ]); + } +} \ No newline at end of file diff --git a/src/Form/Part/PartBaseType.php b/src/Form/Part/PartBaseType.php index b15ec29f..b1d2ebea 100644 --- a/src/Form/Part/PartBaseType.php +++ b/src/Form/Part/PartBaseType.php @@ -22,27 +22,27 @@ declare(strict_types=1); namespace App\Form\Part; -use App\Entity\Parts\ManufacturingStatus; -use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; -use Symfony\Bundle\SecurityBundle\Security; use App\Entity\Attachments\PartAttachment; use App\Entity\Parameters\PartParameter; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; +use App\Entity\Parts\ManufacturingStatus; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; use App\Entity\PriceInformations\Orderdetail; use App\Form\AttachmentFormType; use App\Form\ParameterType; +use App\Form\Part\EDA\EDAPartInfoType; use App\Form\Type\MasterPictureAttachmentType; use App\Form\Type\RichTextEditorType; use App\Form\Type\SIUnitType; use App\Form\Type\StructuralEntityType; +use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; use App\Services\LogSystem\EventCommentNeededHelper; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\EnumType; use Symfony\Component\Form\Extension\Core\Type\ResetType; @@ -52,7 +52,6 @@ use Symfony\Component\Form\Extension\Core\Type\UrlType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Contracts\Translation\TranslatorInterface; class PartBaseType extends AbstractType { @@ -102,6 +101,8 @@ class PartBaseType extends AbstractType 'dto_value' => $dto?->category, 'label' => 'part.edit.category', 'disable_not_selectable' => true, + //Do not require category for new parts, so that the user must select the category by hand and cannot forget it (the requirement is handled by the constraint in the entity) + 'required' => !$new_part, ]) ->add('footprint', StructuralEntityType::class, [ 'class' => Footprint::class, @@ -245,6 +246,22 @@ class PartBaseType extends AbstractType ], ]); + //Part associations + $builder->add('associated_parts_as_owner', CollectionType::class, [ + 'entry_type' => PartAssociationType::class, + 'allow_add' => true, + 'allow_delete' => true, + 'reindex_enable' => true, + 'label' => false, + 'by_reference' => false, + ]); + + //EDA info + $builder->add('eda_info', EDAPartInfoType::class, [ + 'label' => false, + 'required' => false, + ]); + $builder->add('log_comment', TextType::class, [ 'label' => 'edit.log_comment', 'mapped' => false, diff --git a/src/Form/Part/PartLotType.php b/src/Form/Part/PartLotType.php index 707caf28..7d545340 100644 --- a/src/Form/Part/PartLotType.php +++ b/src/Form/Part/PartLotType.php @@ -25,7 +25,7 @@ namespace App\Form\Part; use Symfony\Bundle\SecurityBundle\Security; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Form\Type\SIUnitType; use App\Form\Type\StructuralEntityType; use App\Form\Type\UserSelectType; @@ -54,7 +54,7 @@ class PartLotType extends AbstractType ]); $builder->add('storage_location', StructuralEntityType::class, [ - 'class' => Storelocation::class, + 'class' => StorageLocation::class, 'label' => 'part_lot.edit.location', 'required' => false, 'disable_not_selectable' => true, @@ -80,7 +80,7 @@ class PartLotType extends AbstractType 'required' => false, ]); - $builder->add('expirationDate', DateType::class, [ + $builder->add('expiration_date', DateType::class, [ 'label' => 'part_lot.edit.expiration_date', 'attr' => [], 'widget' => 'single_text', @@ -102,6 +102,14 @@ class PartLotType extends AbstractType 'required' => false, 'help' => 'part_lot.owner.help', ]); + + $builder->add('user_barcode', TextType::class, [ + 'label' => 'part_lot.edit.user_barcode', + 'help' => 'part_lot.edit.vendor_barcode.help', + 'required' => false, + //Do not remove whitespace chars on the beginning and end of the string + 'trim' => false, + ]); } public function configureOptions(OptionsResolver $resolver): void diff --git a/src/Form/Part/PricedetailType.php b/src/Form/Part/PricedetailType.php index c8df4c71..cabb112d 100644 --- a/src/Form/Part/PricedetailType.php +++ b/src/Form/Part/PricedetailType.php @@ -27,12 +27,18 @@ use App\Entity\PriceInformations\Pricedetail; use App\Form\Type\BigDecimalNumberType; use App\Form\Type\CurrencyEntityType; use App\Form\Type\SIUnitType; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class PricedetailType extends AbstractType { + + public function __construct(private readonly Security $security) + { + } + public function buildForm(FormBuilderInterface $builder, array $options): void { //No labels needed, we define translation in templates @@ -63,6 +69,7 @@ class PricedetailType extends AbstractType 'required' => false, 'label' => false, 'short' => true, + 'allow_add' => $this->security->isGranted('@currencies.create'), ]); } diff --git a/src/Form/PasswordTypeExtension.php b/src/Form/PasswordTypeExtension.php index f97eeb8e..64711c53 100644 --- a/src/Form/PasswordTypeExtension.php +++ b/src/Form/PasswordTypeExtension.php @@ -1,4 +1,7 @@ . */ - namespace App\Form; use Symfony\Component\Form\AbstractTypeExtension; @@ -46,9 +48,9 @@ class PasswordTypeExtension extends AbstractTypeExtension $resolver->setAllowedTypes('password_estimator', 'bool'); } - public function finishView(FormView $view, FormInterface $form, array $options) + public function finishView(FormView $view, FormInterface $form, array $options): void { $view->vars['password_estimator'] = $options['password_estimator']; } -} \ No newline at end of file +} diff --git a/src/Form/Permissions/PermissionsMapper.php b/src/Form/Permissions/PermissionsMapper.php index 2163b26f..d4b937bc 100644 --- a/src/Form/Permissions/PermissionsMapper.php +++ b/src/Form/Permissions/PermissionsMapper.php @@ -47,7 +47,7 @@ final class PermissionsMapper implements DataMapperInterface * @param mixed $viewData View data of the compound form being initialized * @param Traversable $forms A list of {@link FormInterface} instances */ - public function mapDataToForms($viewData, \Traversable $forms): void + public function mapDataToForms(mixed $viewData, \Traversable $forms): void { foreach ($forms as $form) { if ($this->inherit) { @@ -94,7 +94,7 @@ final class PermissionsMapper implements DataMapperInterface * @param mixed $viewData The compound form's view data that get mapped * its children model data */ - public function mapFormsToData(\Traversable $forms, &$viewData): void + public function mapFormsToData(\Traversable $forms, mixed &$viewData): void { if ($this->inherit) { throw new RuntimeException('The permission type is readonly when it is showing read only data!'); diff --git a/src/Form/Permissions/PermissionsType.php b/src/Form/Permissions/PermissionsType.php index b0c7ba9d..86fdbc2c 100644 --- a/src/Form/Permissions/PermissionsType.php +++ b/src/Form/Permissions/PermissionsType.php @@ -45,6 +45,7 @@ class PermissionsType extends AbstractType $resolver->setDefaults([ 'show_legend' => true, 'show_presets' => false, + 'show_dependency_notice' => static fn(Options $options) => !$options['disabled'], 'constraints' => static function (Options $options) { if (!$options['disabled']) { return [new NoLockout()]; @@ -60,6 +61,7 @@ class PermissionsType extends AbstractType { $view->vars['show_legend'] = $options['show_legend']; $view->vars['show_presets'] = $options['show_presets']; + $view->vars['show_dependency_notice'] = $options['show_dependency_notice']; } public function buildForm(FormBuilderInterface $builder, array $options): void diff --git a/src/Form/ProjectSystem/ProjectAddPartsType.php b/src/Form/ProjectSystem/ProjectAddPartsType.php index f89f3567..61f72c41 100644 --- a/src/Form/ProjectSystem/ProjectAddPartsType.php +++ b/src/Form/ProjectSystem/ProjectAddPartsType.php @@ -1,4 +1,7 @@ . */ - namespace App\Form\ProjectSystem; use App\Entity\ProjectSystem\Project; @@ -35,7 +37,7 @@ use Symfony\Component\Validator\Constraints\NotNull; class ProjectAddPartsType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) + public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->add('project', StructuralEntityType::class, [ 'class' => Project::class, @@ -49,13 +51,15 @@ class ProjectAddPartsType extends AbstractType $builder->add('bom_entries', ProjectBOMEntryCollectionType::class, [ 'entry_options' => [ 'constraints' => [ - new UniqueEntity(fields: ['part', 'project'], entityClass: ProjectBOMEntry::class, message: 'project.bom_entry.part_already_in_bom'), - new UniqueEntity(fields: ['name', 'project'], entityClass: ProjectBOMEntry::class, message: 'project.bom_entry.name_already_in_bom', ignoreNull: true), + new UniqueEntity(fields: ['part', 'project'], message: 'project.bom_entry.part_already_in_bom', + entityClass: ProjectBOMEntry::class), + new UniqueEntity(fields: ['name', 'project'], message: 'project.bom_entry.name_already_in_bom', + entityClass: ProjectBOMEntry::class, ignoreNull: true), ] ], 'constraints' => [ - new UniqueObjectCollection(fields: ['part'], message: 'project.bom_entry.part_already_in_bom'), - new UniqueObjectCollection(fields: ['name'], message: 'project.bom_entry.name_already_in_bom'), + new UniqueObjectCollection(message: 'project.bom_entry.part_already_in_bom', fields: ['part']), + new UniqueObjectCollection(message: 'project.bom_entry.name_already_in_bom', fields: ['name']), ] ]); $builder->add('submit', SubmitType::class, ['label' => 'save']); @@ -73,7 +77,7 @@ class ProjectAddPartsType extends AbstractType }); } - public function configureOptions(OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'project' => null, @@ -81,4 +85,4 @@ class ProjectAddPartsType extends AbstractType $resolver->setAllowedTypes('project', ['null', Project::class]); } -} \ No newline at end of file +} diff --git a/src/Form/ProjectSystem/ProjectBuildType.php b/src/Form/ProjectSystem/ProjectBuildType.php index 82489471..2b7b52e2 100644 --- a/src/Form/ProjectSystem/ProjectBuildType.php +++ b/src/Form/ProjectSystem/ProjectBuildType.php @@ -62,6 +62,15 @@ class ProjectBuildType extends AbstractType implements DataMapperInterface 'disabled' => !$this->security->isGranted('@parts_stock.withdraw'), ]); + $builder->add('dontCheckQuantity', CheckboxType::class, [ + 'label' => 'project.build.dont_check_quantity', + 'help' => 'project.build.dont_check_quantity.help', + 'required' => false, + 'attr' => [ + 'data-controller' => 'pages--dont-check-quantity-checkbox' + ] + ]); + $builder->add('comment', TextType::class, [ 'label' => 'part.info.withdraw_modal.comment', 'help' => 'part.info.withdraw_modal.comment.hint', @@ -124,6 +133,7 @@ class ProjectBuildType extends AbstractType implements DataMapperInterface } $forms['comment']->setData($data->getComment()); + $forms['dontCheckQuantity']->setData($data->isDontCheckQuantity()); $forms['addBuildsToBuildsPart']->setData($data->getAddBuildsToBuildsPart()); if (isset($forms['buildsPartLot'])) { $forms['buildsPartLot']->setData($data->getBuildsPartLot()); @@ -145,11 +155,13 @@ class ProjectBuildType extends AbstractType implements DataMapperInterface $matches = []; if (preg_match('/^lot_(\d+)$/', $key, $matches)) { $lot_id = (int) $matches[1]; - $data->setLotWithdrawAmount($lot_id, $form->getData()); + $data->setLotWithdrawAmount($lot_id, (float) $form->getData()); } } $data->setComment($forms['comment']->getData()); + $data->setDontCheckQuantity($forms['dontCheckQuantity']->getData()); + if (isset($forms['buildsPartLot'])) { $lot = $forms['buildsPartLot']->getData(); if (!$lot) { //When the user selected "Create new lot", create a new lot diff --git a/src/Form/TFAGoogleSettingsType.php b/src/Form/TFAGoogleSettingsType.php index e00ba494..7917f705 100644 --- a/src/Form/TFAGoogleSettingsType.php +++ b/src/Form/TFAGoogleSettingsType.php @@ -53,6 +53,7 @@ class TFAGoogleSettingsType extends AbstractType 'google_confirmation', TextType::class, [ + 'label' => 'tfa.check.code.confirmation', 'mapped' => false, 'attr' => [ 'maxlength' => '6', @@ -60,7 +61,7 @@ class TFAGoogleSettingsType extends AbstractType 'pattern' => '\d*', 'autocomplete' => 'off', ], - 'constraints' => [new ValidGoogleAuthCode()], + 'constraints' => [new ValidGoogleAuthCode(groups: ["google_authenticator"])], ] ); @@ -92,6 +93,7 @@ class TFAGoogleSettingsType extends AbstractType { $resolver->setDefaults([ 'data_class' => User::class, + 'validation_groups' => ['google_authenticator'], ]); } } diff --git a/src/Form/Type/ExponentialNumberType.php b/src/Form/Type/ExponentialNumberType.php new file mode 100644 index 00000000..f566afbb --- /dev/null +++ b/src/Form/Type/ExponentialNumberType.php @@ -0,0 +1,61 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Type; + +use App\Form\Type\Helper\ExponentialNumberTransformer; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * Similar to the NumberType, but formats small values in scienfitic notation instead of rounding it to 0, like NumberType + */ +class ExponentialNumberType extends AbstractType +{ + public function getParent(): string + { + return NumberType::class; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + //We want to allow the full precision of the number, so disable rounding + 'scale' => null, + ]); + } + + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder->resetViewTransformers(); + + $builder->addViewTransformer(new ExponentialNumberTransformer( + $options['scale'], + $options['grouping'], + $options['rounding_mode'], + $options['html5'] ? 'en' : null + )); + } +} \ No newline at end of file diff --git a/src/Form/Type/Helper/ExponentialNumberTransformer.php b/src/Form/Type/Helper/ExponentialNumberTransformer.php new file mode 100644 index 00000000..ee2f4a4c --- /dev/null +++ b/src/Form/Type/Helper/ExponentialNumberTransformer.php @@ -0,0 +1,113 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Type\Helper; + +use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer; + +/** + * This transformer formats small values in scienfitic notation instead of rounding it to 0, like the default + * NumberFormatter. + */ +class ExponentialNumberTransformer extends NumberToLocalizedStringTransformer +{ + public function __construct( + private ?int $scale = null, + ?bool $grouping = false, + ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, + protected ?string $locale = null + ) { + //Set scale to null, to disable rounding of values + parent::__construct($scale, $grouping, $roundingMode, $locale); + } + + /** + * Transforms a number type into localized number. + * + * @param int|float|null $value Number value + * + * @throws TransformationFailedException if the given value is not numeric + * or if the value cannot be transformed + */ + public function transform(mixed $value): string + { + if (null === $value) { + return ''; + } + + if (!is_numeric($value)) { + throw new TransformationFailedException('Expected a numeric.'); + } + + //If the value is too small, the number formatter would return 0, therfore use exponential notation for small numbers + if (abs($value) < 1e-3) { + $formatter = $this->getScientificNumberFormatter(); + } else { + $formatter = $this->getNumberFormatter(); + } + + + + $value = $formatter->format($value); + + if (intl_is_failure($formatter->getErrorCode())) { + throw new TransformationFailedException($formatter->getErrorMessage()); + } + + // Convert non-breaking and narrow non-breaking spaces to normal ones + $value = str_replace(["\xc2\xa0", "\xe2\x80\xaf"], ' ', $value); + + return $value; + } + + protected function getScientificNumberFormatter(): \NumberFormatter + { + $formatter = new \NumberFormatter($this->locale ?? \Locale::getDefault(), \NumberFormatter::SCIENTIFIC); + + if (null !== $this->scale) { + $formatter->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $this->scale); + $formatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $this->roundingMode); + } + + $formatter->setAttribute(\NumberFormatter::GROUPING_USED, (int) $this->grouping); + + return $formatter; + } + + protected function getNumberFormatter(): \NumberFormatter + { + $formatter = parent::getNumberFormatter(); + + //Unset the fraction digits, as we don't want to round the number + $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, 0); + if (null !== $this->scale) { + $formatter->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $this->scale); + } else { + $formatter->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, 100); + } + + + return $formatter; + } +} \ No newline at end of file diff --git a/src/Form/Type/Helper/StructuralEntityChoiceHelper.php b/src/Form/Type/Helper/StructuralEntityChoiceHelper.php index 402270ce..1210d188 100644 --- a/src/Form/Type/Helper/StructuralEntityChoiceHelper.php +++ b/src/Form/Type/Helper/StructuralEntityChoiceHelper.php @@ -43,7 +43,7 @@ class StructuralEntityChoiceHelper /** * Generates the choice attributes for the given AbstractStructuralDBElement. - * @return array|string[] + * @return array */ public function generateChoiceAttr(AbstractNamedDBElement $choice, Options|array $options): array { @@ -75,7 +75,8 @@ class StructuralEntityChoiceHelper } if ($choice instanceof HasMasterAttachmentInterface) { - $tmp['data-image'] = $choice->getMasterPictureAttachment() instanceof Attachment ? + $tmp['data-image'] = ($choice->getMasterPictureAttachment() instanceof Attachment + && $choice->getMasterPictureAttachment()->isPicture()) ? $this->attachmentURLGenerator->getThumbnailURL($choice->getMasterPictureAttachment(), 'thumbnail_xs') : null @@ -99,7 +100,7 @@ class StructuralEntityChoiceHelper public function generateChoiceAttrCurrency(Currency $choice, Options|array $options): array { $tmp = $this->generateChoiceAttr($choice, $options); - $symbol = empty($choice->getIsoCode()) ? null : Currencies::getSymbol($choice->getIsoCode()); + $symbol = $choice->getIsoCode() === '' ? null : Currencies::getSymbol($choice->getIsoCode()); $tmp['data-short'] = $options['short'] ? $symbol : $choice->getName(); //Show entities that are not added to DB yet separately from other entities @@ -136,9 +137,10 @@ class StructuralEntityChoiceHelper if ($element->getID() === null) { if ($element instanceof AbstractStructuralDBElement) { //Must be the same as the separator in the choice_loader, otherwise this will not work! - return $element->getFullPath('->'); + return '$%$' . $element->getFullPath('->'); } - return $element->getName(); + // '$%$' is the indicator prefix for a new entity + return '$%$' . $element->getName(); } return $element->getID(); diff --git a/src/Form/Type/Helper/StructuralEntityChoiceLoader.php b/src/Form/Type/Helper/StructuralEntityChoiceLoader.php index df98e6ea..e2e4e841 100644 --- a/src/Form/Type/Helper/StructuralEntityChoiceLoader.php +++ b/src/Form/Type/Helper/StructuralEntityChoiceLoader.php @@ -20,34 +20,43 @@ declare(strict_types=1); * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + namespace App\Form\Type\Helper; +use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Base\AbstractStructuralDBElement; -use App\Entity\PriceInformations\Currency; use App\Repository\StructuralDBElementRepository; use App\Services\Trees\NodesListBuilder; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\ChoiceList\Loader\AbstractChoiceLoader; +use Symfony\Component\Form\FormError; +use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\Options; +use Symfony\Contracts\Translation\TranslatorInterface; +/** + * @template T of AbstractStructuralDBElement + */ class StructuralEntityChoiceLoader extends AbstractChoiceLoader { private ?string $additional_element = null; - private ?AbstractStructuralDBElement $starting_element = null; + private ?AbstractNamedDBElement $starting_element = null; - public function __construct(private readonly Options $options, private readonly NodesListBuilder $builder, private readonly EntityManagerInterface $entityManager) - { + private ?FormInterface $form = null; + + public function __construct( + private readonly Options $options, + private readonly NodesListBuilder $builder, + private readonly EntityManagerInterface $entityManager, + private readonly TranslatorInterface $translator + ) { } protected function loadChoices(): iterable { //If the starting_element is set and not persisted yet, add it to the list - if ($this->starting_element !== null && $this->starting_element->getID() === null) { - $tmp = [$this->starting_element]; - } else { - $tmp = []; - } + $tmp = $this->starting_element !== null && $this->starting_element->getID() === null ? [$this->starting_element] : []; if ($this->additional_element) { $tmp = $this->createNewEntitiesFromValue($this->additional_element); @@ -67,28 +76,43 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader if ($this->starting_element !== null && $this->starting_element->getID() === null //Element must not be persisted yet && $this->options['choice_value']($this->starting_element) === $value) { - //Then reuse the starting element $this->entityManager->persist($this->starting_element); return [$this->starting_element]; } + if (!$this->options['allow_add']) { - throw new \RuntimeException('Cannot create new entity, because allow_add is not enabled!'); + //If we have a form, add an error to it, to improve the user experience + if ($this->form !== null) { + $this->form->addError( + new FormError($this->translator->trans('entity.select.creating_new_entities_not_allowed') + ) + ); + } else { + throw new \RuntimeException('Cannot create new entity, because allow_add is not enabled!'); + } } + + /** @var class-string $class */ $class = $this->options['class']; - /** @var StructuralDBElementRepository $repo */ + + /** @var StructuralDBElementRepository $repo */ $repo = $this->entityManager->getRepository($class); + $entities = $repo->getNewEntityFromPath($value, '->'); $results = []; - foreach($entities as $entity) { + foreach ($entities as $entity) { //If the entity is newly created (ID null), add it as result and persist it. if ($entity->getID() === null) { - $this->entityManager->persist($entity); + //Only persist the entities if it is allowed + if ($this->options['allow_add']) { + $this->entityManager->persist($entity); + } $results[] = $entity; } } @@ -108,23 +132,48 @@ class StructuralEntityChoiceLoader extends AbstractChoiceLoader /** * Gets the initial value used to populate the field. - * @return AbstractStructuralDBElement|null + * @return AbstractNamedDBElement|null */ - public function getStartingElement(): ?AbstractStructuralDBElement + public function getStartingElement(): ?AbstractNamedDBElement { return $this->starting_element; } + /** + * Sets the form that this loader is bound to. + * @param FormInterface|null $form + * @return void + */ + public function setForm(?FormInterface $form): void + { + $this->form = $form; + } + /** * Sets the initial value used to populate the field. This will always be an allowed value. - * @param AbstractStructuralDBElement|null $starting_element + * @param AbstractNamedDBElement|null $starting_element * @return StructuralEntityChoiceLoader */ - public function setStartingElement(?AbstractStructuralDBElement $starting_element): StructuralEntityChoiceLoader + public function setStartingElement(?AbstractNamedDBElement $starting_element): StructuralEntityChoiceLoader { $this->starting_element = $starting_element; return $this; } + protected function doLoadChoicesForValues(array $values, ?callable $value): array + { + // Normalize the data (remove whitespaces around the arrow sign) and leading/trailing whitespaces + // This is required so that the value that is generated for an new entity based on its name structure is + // the same as the value that is generated for the same entity after it is persisted. + // Otherwise, errors occurs that the element could not be found. + foreach ($values as &$data) { + $data = trim((string) $data); + $data = preg_replace('/\s*->\s*/', '->', $data); + } + unset ($data); + + return $this->loadChoiceList($value)->getChoicesForValues($values); + } + } diff --git a/src/Form/Type/PartLotSelectType.php b/src/Form/Type/PartLotSelectType.php index 8eff5122..c68535a7 100644 --- a/src/Form/Type/PartLotSelectType.php +++ b/src/Form/Type/PartLotSelectType.php @@ -22,7 +22,7 @@ declare(strict_types=1); */ namespace App\Form\Type; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; use Doctrine\ORM\EntityRepository; @@ -46,7 +46,7 @@ class PartLotSelectType extends AbstractType $resolver->setDefaults([ 'class' => PartLot::class, - 'choice_label' => ChoiceList::label($this, static fn(PartLot $part_lot): string => ($part_lot->getStorageLocation() instanceof Storelocation ? $part_lot->getStorageLocation()->getFullPath() : '') + 'choice_label' => ChoiceList::label($this, static fn(PartLot $part_lot): string => ($part_lot->getStorageLocation() instanceof StorageLocation ? $part_lot->getStorageLocation()->getFullPath() : '') . ' (' . $part_lot->getName() . '): ' . $part_lot->getAmount()), 'query_builder' => fn(Options $options) => static fn(EntityRepository $er) => $er->createQueryBuilder('l') ->where('l.part = :part') diff --git a/src/Form/Type/SIUnitType.php b/src/Form/Type/SIUnitType.php index 2f0138f0..52bcaa3d 100644 --- a/src/Form/Type/SIUnitType.php +++ b/src/Form/Type/SIUnitType.php @@ -153,7 +153,7 @@ final class SIUnitType extends AbstractType implements DataMapperInterface * * @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported */ - public function mapDataToForms($viewData, \Traversable $forms): void + public function mapDataToForms(mixed $viewData, \Traversable $forms): void { $forms = iterator_to_array($forms); @@ -204,7 +204,7 @@ final class SIUnitType extends AbstractType implements DataMapperInterface * * @throws Exception\UnexpectedTypeException if the type of the data parameter is not supported */ - public function mapFormsToData(\Traversable $forms, &$viewData): void + public function mapFormsToData(\Traversable $forms, mixed &$viewData): void { //Convert both fields to a single float value. diff --git a/src/Form/Type/StaticFileAutocompleteType.php b/src/Form/Type/StaticFileAutocompleteType.php new file mode 100644 index 00000000..4d483e2a --- /dev/null +++ b/src/Form/Type/StaticFileAutocompleteType.php @@ -0,0 +1,63 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\Type; + +use Symfony\Component\Asset\Packages; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * Implements a text type with autocomplete functionality based on a static file, containing a list of autocomplete + * suggestions. + * Other values are allowed, but the user can select from the list of suggestions. + * The file must be located in the public directory! + */ +class StaticFileAutocompleteType extends AbstractType +{ + public function __construct( + private readonly Packages $assets + ) { + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setRequired('file'); + $resolver->setAllowedTypes('file', 'string'); + } + + public function getParent(): string + { + return TextType::class; + } + + public function finishView(FormView $view, FormInterface $form, array $options): void + { + //Add the data-controller and data-url attributes to the form field + $view->vars['attr']['data-controller'] = 'elements--static-file-autocomplete'; + $view->vars['attr']['data-url'] = $this->assets->getUrl($options['file']); + } +} \ No newline at end of file diff --git a/src/Form/Type/StructuralEntityType.php b/src/Form/Type/StructuralEntityType.php index 18368289..1018eeeb 100644 --- a/src/Form/Type/StructuralEntityType.php +++ b/src/Form/Type/StructuralEntityType.php @@ -51,11 +51,14 @@ class StructuralEntityType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options): void { $builder->addEventListener(FormEvents::PRE_SUBMIT, function (PreSubmitEvent $event) { - //When the data contains non-digit characters, we assume that the user entered a new element. + //When the data starts with "$%$", we assume that the user entered a new element. //In that case we add the new element to our choice_loader $data = $event->getData(); - if (null === $data || !is_string($data) || $data === "" || ctype_digit($data)) { + if (is_string($data) && str_starts_with($data, '$%$')) { + //Extract the real name from the data + $data = substr($data, 3); + } else { return; } @@ -64,6 +67,7 @@ class StructuralEntityType extends AbstractType $choice_loader = $options['choice_loader']; if ($choice_loader instanceof StructuralEntityChoiceLoader) { $choice_loader->setAdditionalElement($data); + $choice_loader->setForm($form); } }); @@ -80,7 +84,7 @@ class StructuralEntityType extends AbstractType 'subentities_of' => null, //Only show entities with the given parent class 'disable_not_selectable' => false, //Disable entries with not selectable property 'choice_value' => fn(?AbstractNamedDBElement $element) => $this->choice_helper->generateChoiceValue($element), //Use the element id as option value and for comparing items - 'choice_loader' => fn(Options $options) => new StructuralEntityChoiceLoader($options, $this->builder, $this->em), + 'choice_loader' => fn(Options $options) => new StructuralEntityChoiceLoader($options, $this->builder, $this->em, $this->translator), 'choice_label' => fn(Options $options) => fn($choice, $key, $value) => $this->choice_helper->generateChoiceLabel($choice), 'choice_attr' => fn(Options $options) => fn($choice, $key, $value) => $this->choice_helper->generateChoiceAttr($choice, $options), 'group_by' => fn(AbstractNamedDBElement $element) => $this->choice_helper->generateGroupBy($element), @@ -104,12 +108,8 @@ class StructuralEntityType extends AbstractType $resolver->setDefault('dto_value', null); $resolver->setAllowedTypes('dto_value', ['null', 'string']); //If no help text is explicitly set, we use the dto value as help text and show it as html - $resolver->setDefault('help', function (Options $options) { - return $this->dtoText($options['dto_value']); - }); - $resolver->setDefault('help_html', function (Options $options) { - return $options['dto_value'] !== null; - }); + $resolver->setDefault('help', fn(Options $options) => $this->dtoText($options['dto_value'])); + $resolver->setDefault('help_html', fn(Options $options) => $options['dto_value'] !== null); $resolver->setDefault('attr', function (Options $options) { $tmp = [ diff --git a/src/Form/Type/TriStateCheckboxType.php b/src/Form/Type/TriStateCheckboxType.php index df4b0f3a..4523a839 100644 --- a/src/Form/Type/TriStateCheckboxType.php +++ b/src/Form/Type/TriStateCheckboxType.php @@ -99,9 +99,8 @@ final class TriStateCheckboxType extends AbstractType implements DataTransformer * * @return mixed The value in the transformed representation * - * @throws TransformationFailedException when the transformation fails */ - public function transform($value) + public function transform(mixed $value) { if (true === $value) { return 'true'; @@ -142,10 +141,8 @@ final class TriStateCheckboxType extends AbstractType implements DataTransformer * @param mixed $value The value in the transformed representation * * @return mixed The value in the original representation - * - * @throws TransformationFailedException when the transformation fails */ - public function reverseTransform($value) + public function reverseTransform(mixed $value) { return match ($value) { 'true' => true, diff --git a/src/Form/Type/UserSelectType.php b/src/Form/Type/UserSelectType.php index cc16d724..8862cdf7 100644 --- a/src/Form/Type/UserSelectType.php +++ b/src/Form/Type/UserSelectType.php @@ -34,7 +34,7 @@ class UserSelectType extends AbstractType { $resolver->setDefaults([ 'class' => User::class, - 'choice_label' => fn(Options $options) => fn(User $choice, $key, $value) => $choice->getFullName(true), + 'choice_label' => fn(Options $options) => static fn(User $choice, $key, $value) => $choice->getFullName(true), ]); } diff --git a/src/Form/UserAdminForm.php b/src/Form/UserAdminForm.php index d1e5924e..864bcf6b 100644 --- a/src/Form/UserAdminForm.php +++ b/src/Form/UserAdminForm.php @@ -57,6 +57,8 @@ class UserAdminForm extends AbstractType parent::configureOptions($resolver); // TODO: Change the autogenerated stub $resolver->setRequired('attachment_class'); $resolver->setDefault('parameter_class', false); + + $resolver->setDefault('validation_groups', ['Default', 'permissions:edit']); } public function buildForm(FormBuilderInterface $builder, array $options): void diff --git a/src/Form/UserSettingsType.php b/src/Form/UserSettingsType.php index 53ca8cf8..05f63df4 100644 --- a/src/Form/UserSettingsType.php +++ b/src/Form/UserSettingsType.php @@ -27,6 +27,7 @@ use App\Entity\UserSystem\User; use App\Form\Type\CurrencyEntityType; use App\Form\Type\RichTextEditorType; use App\Form\Type\ThemeChoiceType; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Event\PreSetDataEvent; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; @@ -44,7 +45,9 @@ use Symfony\Component\Validator\Constraints\File; class UserSettingsType extends AbstractType { - public function __construct(protected Security $security, protected bool $demo_mode) + public function __construct(protected Security $security, + protected bool $demo_mode, + #[Autowire(param: 'partdb.locale_menu')] private readonly array $preferred_languages) { } @@ -90,7 +93,7 @@ class UserSettingsType extends AbstractType ], 'constraints' => [ new File([ - 'maxSize' => '2M', + 'maxSize' => '5M', ]), ], ]) @@ -109,7 +112,7 @@ class UserSettingsType extends AbstractType 'required' => false, 'placeholder' => 'user_settings.language.placeholder', 'label' => 'user.language_select', - 'preferred_choices' => ['en', 'de'], + 'preferred_choices' => $this->preferred_languages, ]) ->add('timezone', TimezoneType::class, [ 'disabled' => $this->demo_mode, diff --git a/src/Helpers/FilenameSanatizer.php b/src/Helpers/FilenameSanatizer.php new file mode 100644 index 00000000..f6744b1a --- /dev/null +++ b/src/Helpers/FilenameSanatizer.php @@ -0,0 +1,58 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Helpers; + +/** + * This class provides functions to sanitize filenames. + */ +class FilenameSanatizer +{ + /** + * Converts a given filename to a version, which is guaranteed to be safe to use on all filesystems. + * This function is adapted from https://stackoverflow.com/a/42058764/21879970 + * @param string $filename + * @return string + */ + public static function sanitizeFilename(string $filename): string + { + //Convert to ASCII + $filename = iconv('UTF-8', 'ASCII//TRANSLIT', $filename); + + $filename = preg_replace( + '~ + [<>:"/\\\|?*]| # file system reserved https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words + [\x00-\x1F]| # control characters http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx + [\x7F\xA0\xAD]| # non-printing characters DEL, NO-BREAK SPACE, SOFT HYPHEN + [#\[\]@!$&\'()+,;=]| # URI reserved https://www.rfc-editor.org/rfc/rfc3986#section-2.2 + [{}^\~`] # URL unsafe characters https://www.ietf.org/rfc/rfc1738.txt + ~x', + '-', $filename); + + // avoids ".", ".." or ".hiddenFiles" + $filename = ltrim((string) $filename, '.-'); + //Limit filename length to 255 bytes + $ext = pathinfo($filename, PATHINFO_EXTENSION); + return mb_strcut(pathinfo($filename, PATHINFO_FILENAME), 0, 255 - ($ext !== '' && $ext !== '0' ? strlen($ext) + 1 : 0), mb_detect_encoding($filename)) . ($ext !== '' && $ext !== '0' ? '.' . $ext : ''); + } +} \ No newline at end of file diff --git a/src/Helpers/IPAnonymizer.php b/src/Helpers/IPAnonymizer.php new file mode 100644 index 00000000..9662852f --- /dev/null +++ b/src/Helpers/IPAnonymizer.php @@ -0,0 +1,49 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Helpers; + +use Symfony\Component\HttpFoundation\IpUtils; + +/** + * Utils to assist with IP anonymization. + * The IPUtils::anonymize has a certain edgecase with local-link addresses, which is handled here. + * See: https://github.com/Part-DB/Part-DB-server/issues/782 + */ +final class IPAnonymizer +{ + public static function anonymize(string $ip): string + { + /** + * If the IP contains a % symbol, then it is a local-link address with scoping according to RFC 4007 + * In that case, we only care about the part before the % symbol, as the following functions, can only work with + * the IP address itself. As the scope can leak information (containing interface name), we do not want to + * include it in our anonymized IP data. + */ + if (str_contains($ip, '%')) { + $ip = substr($ip, 0, strpos($ip, '%')); + } + + return IpUtils::anonymize($ip); + } +} \ No newline at end of file diff --git a/src/Helpers/LabelResponse.php b/src/Helpers/LabelResponse.php index 98451e2f..2973eb7e 100644 --- a/src/Helpers/LabelResponse.php +++ b/src/Helpers/LabelResponse.php @@ -84,7 +84,7 @@ class LabelResponse extends Response */ public function setAutoLastModified(): LabelResponse { - $this->setLastModified(new DateTime()); + $this->setLastModified(new \DateTimeImmutable()); return $this; } diff --git a/src/Helpers/Projects/ProjectBuildRequest.php b/src/Helpers/Projects/ProjectBuildRequest.php index 36035744..430d37b5 100644 --- a/src/Helpers/Projects/ProjectBuildRequest.php +++ b/src/Helpers/Projects/ProjectBuildRequest.php @@ -47,6 +47,8 @@ final class ProjectBuildRequest private bool $add_build_to_builds_part = false; + private bool $dont_check_quantity = false; + /** * @param Project $project The project that should be build * @param int $number_of_builds The number of builds that should be created @@ -172,11 +174,7 @@ final class ProjectBuildRequest */ public function getLotWithdrawAmount(PartLot|int $lot): float { - if ($lot instanceof PartLot) { - $lot_id = $lot->getID(); - } else { // Then it must be an int - $lot_id = $lot; - } + $lot_id = $lot instanceof PartLot ? $lot->getID() : $lot; if (! array_key_exists($lot_id, $this->withdraw_amounts)) { throw new \InvalidArgumentException('The given lot is not in the withdraw amounts array!'); @@ -283,4 +281,26 @@ final class ProjectBuildRequest { return $this->number_of_builds; } + + /** + * If Set to true, the given withdraw amounts are used without any checks for requirements. + * @return bool + */ + public function isDontCheckQuantity(): bool + { + return $this->dont_check_quantity; + } + + /** + * Set to true, the given withdraw amounts are used without any checks for requirements. + * @param bool $dont_check_quantity + * @return $this + */ + public function setDontCheckQuantity(bool $dont_check_quantity): ProjectBuildRequest + { + $this->dont_check_quantity = $dont_check_quantity; + return $this; + } + + } diff --git a/src/Helpers/TrinaryLogicHelper.php b/src/Helpers/TrinaryLogicHelper.php new file mode 100644 index 00000000..f4b460de --- /dev/null +++ b/src/Helpers/TrinaryLogicHelper.php @@ -0,0 +1,107 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Helpers; + +/** + * Helper functions for logic operations with trinary logic. + * True and false are represented as classical boolean values, undefined is represented as null. + * @see \App\Tests\Helpers\TrinaryLogicHelperTest + */ +class TrinaryLogicHelper +{ + + /** + * Implements the trinary logic NOT. + * @param bool|null $a + * @return bool|null + */ + public static function not(?bool $a): ?bool + { + if ($a === null) { + return null; + } + return !$a; + } + + + /** + * Returns the trinary logic OR of the given parameters. At least one parameter is required. + * @param bool|null ...$args + * @return bool|null + */ + public static function or(?bool ...$args): ?bool + { + if (count($args) === 0) { + throw new \LogicException('At least one parameter is required.'); + } + + // The trinary or is the maximum of the integer representation of the parameters. + return self::intToBool( + max(array_map(self::boolToInt(...), $args)) + ); + } + + /** + * Returns the trinary logic AND of the given parameters. At least one parameter is required. + * @param bool|null ...$args + * @return bool|null + */ + public static function and(?bool ...$args): ?bool + { + if (count($args) === 0) { + throw new \LogicException('At least one parameter is required.'); + } + + // The trinary and is the minimum of the integer representation of the parameters. + return self::intToBool( + min(array_map(self::boolToInt(...), $args)) + ); + } + + /** + * Convert the trinary bool to an integer, where true is 1, false is -1 and null is 0. + * @param bool|null $a + * @return int + */ + private static function boolToInt(?bool $a): int + { + if ($a === null) { + return 0; + } + return $a ? 1 : -1; + } + + /** + * Convert the integer to a trinary bool, where 1 is true, -1 is false and 0 is null. + * @param int $a + * @return bool|null + */ + private static function intToBool(int $a): ?bool + { + if ($a === 0) { + return null; + } + return $a > 0; + } +} \ No newline at end of file diff --git a/src/Migration/AbstractMultiPlatformMigration.php b/src/Migration/AbstractMultiPlatformMigration.php index 54e3b529..bc2b3f19 100644 --- a/src/Migration/AbstractMultiPlatformMigration.php +++ b/src/Migration/AbstractMultiPlatformMigration.php @@ -25,7 +25,8 @@ namespace App\Migration; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; use Psr\Log\LoggerInterface; @@ -35,6 +36,9 @@ abstract class AbstractMultiPlatformMigration extends AbstractMigration final public const ADMIN_PW_LENGTH = 10; protected string $admin_pw = ''; + /** @noinspection SenselessProxyMethodInspection + * This method is required to redefine the logger type hint to protected + */ public function __construct(Connection $connection, protected LoggerInterface $logger) { parent::__construct($connection, $logger); @@ -47,6 +51,7 @@ abstract class AbstractMultiPlatformMigration extends AbstractMigration match ($db_type) { 'mysql' => $this->mySQLUp($schema), 'sqlite' => $this->sqLiteUp($schema), + 'postgresql' => $this->postgreSQLUp($schema), default => $this->abortIf(true, "Database type '$db_type' is not supported!"), }; } @@ -58,6 +63,7 @@ abstract class AbstractMultiPlatformMigration extends AbstractMigration match ($db_type) { 'mysql' => $this->mySQLDown($schema), 'sqlite' => $this->sqLiteDown($schema), + 'postgresql' => $this->postgreSQLDown($schema), default => $this->abortIf(true, "Database type is not supported!"), }; } @@ -132,6 +138,24 @@ abstract class AbstractMultiPlatformMigration extends AbstractMigration return $result > 0; } + /** + * Checks if a column exists in a table. + * @return bool Returns true, if the column exists + * @throws Exception + */ + public function doesColumnExist(string $table, string $column_name): bool + { + $db_type = $this->getDatabaseType(); + if ($db_type !== 'mysql') { + throw new \RuntimeException('This method is only supported for MySQL/MariaDB databases!'); + } + + $sql = "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '$table' AND COLUMN_NAME = '$column_name'"; + $result = (int) $this->connection->fetchOne($sql); + + return $result > 0; + } + /** * Returns the database type of the used database. * @return string|null Returns 'mysql' for MySQL/MariaDB and 'sqlite' for SQLite. Returns null if unknown type @@ -142,10 +166,14 @@ abstract class AbstractMultiPlatformMigration extends AbstractMigration return 'mysql'; } - if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) { + if ($this->connection->getDatabasePlatform() instanceof SQLitePlatform) { return 'sqlite'; } + if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) { + return 'postgresql'; + } + return null; } @@ -156,4 +184,8 @@ abstract class AbstractMultiPlatformMigration extends AbstractMigration abstract public function sqLiteUp(Schema $schema): void; abstract public function sqLiteDown(Schema $schema): void; + + abstract public function postgreSQLUp(Schema $schema): void; + + abstract public function postgreSQLDown(Schema $schema): void; } diff --git a/src/Migration/WithPermPresetsTrait.php b/src/Migration/WithPermPresetsTrait.php new file mode 100644 index 00000000..44bc4510 --- /dev/null +++ b/src/Migration/WithPermPresetsTrait.php @@ -0,0 +1,72 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Migration; + +use App\Entity\UserSystem\PermissionData; +use App\Security\Interfaces\HasPermissionsInterface; +use App\Services\UserSystem\PermissionPresetsHelper; +use Symfony\Component\DependencyInjection\ContainerInterface; + +trait WithPermPresetsTrait +{ + private ?ContainerInterface $container = null; + private ?PermissionPresetsHelper $permission_presets_helper = null; + + private function getJSONPermDataFromPreset(string $preset): string + { + if ($this->permission_presets_helper === null) { + throw new \RuntimeException('PermissionPresetsHelper not set! There seems to be some issue with the dependency injection!'); + } + + //Create a virtual user on which we can apply the preset + $user = new class implements HasPermissionsInterface { + + public PermissionData $perm_data; + + public function __construct() + { + $this->perm_data = new PermissionData(); + } + + public function getPermissions(): PermissionData + { + return $this->perm_data; + } + }; + + //Apply the preset to the virtual user + $this->permission_presets_helper->applyPreset($user, $preset); + + //And return the json data + return json_encode($user->getPermissions()); + } + + public function setContainer(?ContainerInterface $container = null): void + { + if ($container !== null) { + $this->container = $container; + $this->permission_presets_helper = $container->get(PermissionPresetsHelper::class); + } + } +} \ No newline at end of file diff --git a/src/Repository/AbstractPartsContainingRepository.php b/src/Repository/AbstractPartsContainingRepository.php index 3a389610..4fd0bbff 100644 --- a/src/Repository/AbstractPartsContainingRepository.php +++ b/src/Repository/AbstractPartsContainingRepository.php @@ -40,11 +40,11 @@ abstract class AbstractPartsContainingRepository extends StructuralDBElementRepo * Returns all parts associated with this element. * * @param object $element the element for which the parts should be determined - * @param array $order_by The order of the parts. Format ['name' => 'ASC'] + * @param string $nameOrderDirection the direction in which the parts should be ordered by name, either ASC or DESC * * @return Part[] */ - abstract public function getParts(object $element, array $order_by = ['name' => 'ASC']): array; + abstract public function getParts(object $element, string $nameOrderDirection = "ASC"): array; /** * Gets the count of the parts associated with this element. @@ -64,6 +64,11 @@ abstract class AbstractPartsContainingRepository extends StructuralDBElementRepo return $this->getPartsCountRecursiveWithDepthN($element, self::RECURSION_LIMIT); } + public function getPartsRecursive(AbstractPartsContainingDBElement $element): array + { + return $this->getPartsRecursiveWithDepthN($element, self::RECURSION_LIMIT); + } + /** * The implementation of the recursive function to get the parts count. * This function is used to limit the recursion depth (remaining_depth is decreased on each call). @@ -91,7 +96,24 @@ abstract class AbstractPartsContainingRepository extends StructuralDBElementRepo return $count; } - protected function getPartsByField(object $element, array $order_by, string $field_name): array + protected function getPartsRecursiveWithDepthN(AbstractPartsContainingDBElement $element, int $remaining_depth): array + { + if ($remaining_depth <= 0) { + throw new \RuntimeException('Recursion limit reached!'); + } + + //Add direct parts + $parts = $this->getParts($element); + + //Then iterate over all children and add their parts + foreach ($element->getChildren() as $child) { + $parts = array_merge($parts, $this->getPartsRecursiveWithDepthN($child, $remaining_depth - 1)); + } + + return $parts; + } + + protected function getPartsByField(object $element, string $nameOrderDirection, string $field_name): array { if (!$element instanceof AbstractPartsContainingDBElement) { throw new InvalidArgumentException('$element must be an instance of AbstractPartContainingDBElement!'); @@ -99,7 +121,14 @@ abstract class AbstractPartsContainingRepository extends StructuralDBElementRepo $repo = $this->getEntityManager()->getRepository(Part::class); - return $repo->findBy([$field_name => $element], $order_by); + //Build a query builder to get the parts with a custom order by + + $qb = $repo->createQueryBuilder('part') + ->where('part.'.$field_name.' = :element') + ->setParameter('element', $element) + ->orderBy('NATSORT(part.name)', $nameOrderDirection); + + return $qb->getQuery()->getResult(); } protected function getPartsCountByField(object $element, string $field_name): int diff --git a/src/Repository/AttachmentContainingDBElementRepository.php b/src/Repository/AttachmentContainingDBElementRepository.php index 7f00f87f..40869662 100644 --- a/src/Repository/AttachmentContainingDBElementRepository.php +++ b/src/Repository/AttachmentContainingDBElementRepository.php @@ -25,11 +25,12 @@ namespace App\Repository; use App\Doctrine\Helpers\FieldHelper; use App\Entity\Attachments\AttachmentContainingDBElement; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; /** * @template TEntityClass of AttachmentContainingDBElement * @extends NamedDBElementRepository + * @see \App\Tests\Repository\AttachmentContainingDBElementRepositoryTest */ class AttachmentContainingDBElementRepository extends NamedDBElementRepository { @@ -70,7 +71,7 @@ class AttachmentContainingDBElementRepository extends NamedDBElementRepository $q = $qb->getQuery(); - $q->setFetchMode($this->getEntityName(), 'master_picture_attachment', ClassMetadataInfo::FETCH_EAGER); + $q->setFetchMode($this->getEntityName(), 'master_picture_attachment', ClassMetadata::FETCH_EAGER); $result = $q->getResult(); diff --git a/src/Repository/AttachmentRepository.php b/src/Repository/AttachmentRepository.php index 240ab058..4fc0abc9 100644 --- a/src/Repository/AttachmentRepository.php +++ b/src/Repository/AttachmentRepository.php @@ -58,15 +58,15 @@ class AttachmentRepository extends DBElementRepository { $qb = $this->createQueryBuilder('attachment'); $qb->select('COUNT(attachment)') - ->where('attachment.path LIKE :like'); - $qb->setParameter('like', '\\%SECURE\\%%'); + ->where('attachment.internal_path LIKE :like ESCAPE \'#\''); + $qb->setParameter('like', '#%SECURE#%%'); $query = $qb->getQuery(); return (int) $query->getSingleScalarResult(); } /** - * Gets the count of all external attachments (attachments only containing a URL). + * Gets the count of all external attachments (attachments containing only an external path). * * @throws NoResultException * @throws NonUniqueResultException @@ -75,17 +75,16 @@ class AttachmentRepository extends DBElementRepository { $qb = $this->createQueryBuilder('attachment'); $qb->select('COUNT(attachment)') - ->where('attachment.path LIKE :http') - ->orWhere('attachment.path LIKE :https'); - $qb->setParameter('http', 'http://%'); - $qb->setParameter('https', 'https://%'); + ->where('attachment.external_path IS NOT NULL') + ->andWhere('attachment.internal_path IS NULL'); + $query = $qb->getQuery(); return (int) $query->getSingleScalarResult(); } /** - * Gets the count of all attachments where a user uploaded a file. + * Gets the count of all attachments where a user uploaded a file or a file was downloaded from an external source. * * @throws NoResultException * @throws NonUniqueResultException @@ -94,12 +93,12 @@ class AttachmentRepository extends DBElementRepository { $qb = $this->createQueryBuilder('attachment'); $qb->select('COUNT(attachment)') - ->where('attachment.path LIKE :base') - ->orWhere('attachment.path LIKE :media') - ->orWhere('attachment.path LIKE :secure'); - $qb->setParameter('secure', '\\%SECURE\\%%'); - $qb->setParameter('base', '\\%BASE\\%%'); - $qb->setParameter('media', '\\%MEDIA\\%%'); + ->where('attachment.internal_path LIKE :base ESCAPE \'#\'') + ->orWhere('attachment.internal_path LIKE :media ESCAPE \'#\'') + ->orWhere('attachment.internal_path LIKE :secure ESCAPE \'#\''); + $qb->setParameter('secure', '#%SECURE#%%'); + $qb->setParameter('base', '#%BASE#%%'); + $qb->setParameter('media', '#%MEDIA#%%'); $query = $qb->getQuery(); return (int) $query->getSingleScalarResult(); diff --git a/src/Repository/CurrencyRepository.php b/src/Repository/CurrencyRepository.php index 47642f4b..63473229 100644 --- a/src/Repository/CurrencyRepository.php +++ b/src/Repository/CurrencyRepository.php @@ -23,7 +23,6 @@ declare(strict_types=1); namespace App\Repository; -use App\Entity\Base\AbstractStructuralDBElement; use App\Entity\PriceInformations\Currency; use Symfony\Component\Intl\Currencies; diff --git a/src/Repository/DBElementRepository.php b/src/Repository/DBElementRepository.php index 296f2a9a..2437e848 100644 --- a/src/Repository/DBElementRepository.php +++ b/src/Repository/DBElementRepository.php @@ -43,13 +43,13 @@ namespace App\Repository; use App\Doctrine\Helpers\FieldHelper; use App\Entity\Base\AbstractDBElement; -use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\ORM\EntityRepository; use ReflectionClass; /** * @template TEntityClass of AbstractDBElement * @extends EntityRepository + * @see \App\Tests\Repository\DBElementRepositoryTest */ class DBElementRepository extends EntityRepository { @@ -80,7 +80,7 @@ class DBElementRepository extends EntityRepository /** * Find all elements that match a list of IDs. - * + * They are ordered by IDs in an ascending order. * @return AbstractDBElement[] * @phpstan-return list */ @@ -90,6 +90,7 @@ class DBElementRepository extends EntityRepository $q = $qb->select('element') ->where('element.id IN (?1)') ->setParameter(1, $ids) + ->orderBy('element.id', 'ASC') ->getQuery(); return $q->getResult(); @@ -143,9 +144,7 @@ class DBElementRepository extends EntityRepository */ protected function sortResultArrayByIDArray(array &$result_array, array $ids): void { - usort($result_array, static function (AbstractDBElement $a, AbstractDBElement $b) use ($ids) { - return array_search($a->getID(), $ids, true) <=> array_search($b->getID(), $ids, true); - }); + usort($result_array, static fn(AbstractDBElement $a, AbstractDBElement $b) => array_search($a->getID(), $ids, true) <=> array_search($b->getID(), $ids, true)); } protected function setField(AbstractDBElement $element, string $field, int $new_value): void diff --git a/src/Repository/LabelProfileRepository.php b/src/Repository/LabelProfileRepository.php index 9fa5d3cc..ad9e40f1 100644 --- a/src/Repository/LabelProfileRepository.php +++ b/src/Repository/LabelProfileRepository.php @@ -45,7 +45,6 @@ use App\Entity\LabelSystem\LabelOptions; use App\Entity\LabelSystem\LabelProfile; use App\Entity\LabelSystem\LabelSupportedElement; use App\Helpers\Trees\TreeViewNode; -use InvalidArgumentException; /** * @template TEntityClass of LabelProfile diff --git a/src/Repository/LogEntryRepository.php b/src/Repository/LogEntryRepository.php index 472993a7..6850d06b 100644 --- a/src/Repository/LogEntryRepository.php +++ b/src/Repository/LogEntryRepository.php @@ -30,7 +30,6 @@ use App\Entity\LogSystem\ElementDeletedLogEntry; use App\Entity\LogSystem\ElementEditedLogEntry; use App\Entity\LogSystem\LogTargetType; use App\Entity\UserSystem\User; -use DateTime; use RuntimeException; /** @@ -86,10 +85,8 @@ class LogEntryRepository extends DBElementRepository ->orderBy('log.timestamp', 'DESC') ->setMaxResults(1); - $qb->setParameters([ - 'target_type' => LogTargetType::fromElementClass($class), - 'target_id' => $id, - ]); + $qb->setParameter('target_type', LogTargetType::fromElementClass($class)); + $qb->setParameter('target_id', $id); $query = $qb->getQuery(); @@ -114,19 +111,18 @@ class LogEntryRepository extends DBElementRepository { $qb = $this->createQueryBuilder('log'); $qb->select('log') - //->where('log INSTANCE OF App\Entity\LogSystem\ElementEditedLogEntry') ->where('log INSTANCE OF '.ElementEditedLogEntry::class) ->orWhere('log INSTANCE OF '.CollectionElementDeleted::class) ->andWhere('log.target_type = :target_type') ->andWhere('log.target_id = :target_id') ->andWhere('log.timestamp >= :until') - ->orderBy('log.timestamp', 'DESC'); + ->orderBy('log.timestamp', 'DESC') + ; + + $qb->setParameter('target_type', LogTargetType::fromElementClass($element)); + $qb->setParameter('target_id', $element->getID()); + $qb->setParameter('until', $until); - $qb->setParameters([ - 'target_type' => LogTargetType::fromElementClass($element), - 'target_id' => $element->getID(), - 'until' => $until, - ]); $query = $qb->getQuery(); @@ -146,13 +142,11 @@ class LogEntryRepository extends DBElementRepository ->andWhere('log.target_type = :target_type') ->andWhere('log.target_id = :target_id') ->andWhere('log.timestamp >= :until') - ->orderBy('log.timestamp', 'DESC'); + ; - $qb->setParameters([ - 'target_type' => LogTargetType::fromElementClass($element), - 'target_id' => $element->getID(), - 'until' => $timestamp, - ]); + $qb->setParameter('target_type', LogTargetType::fromElementClass($element)); + $qb->setParameter('target_id', $element->getID()); + $qb->setParameter('until', $timestamp); $query = $qb->getQuery(); $count = $query->getSingleScalarResult(); @@ -163,10 +157,10 @@ class LogEntryRepository extends DBElementRepository /** * Gets the last log entries ordered by timestamp. * - * @param int|null $limit - * @param int|null $offset + * @param int|null $limit + * @param int|null $offset */ - public function getLogsOrderedByTimestamp(string $order = 'DESC', $limit = null, $offset = null): array + public function getLogsOrderedByTimestamp(string $order = 'DESC', ?int $limit = null, ?int $offset = null): array { return $this->findBy([], ['timestamp' => $order], $limit, $offset); } @@ -219,20 +213,29 @@ class LogEntryRepository extends DBElementRepository protected function getLastUser(AbstractDBElement $element, string $log_class): ?User { $qb = $this->createQueryBuilder('log'); + /** + * The select and join with user here are important, to get true null user values, if the user was deleted. + * This happens for sqlite database, before the SET NULL constraint was added, and doctrine generates a proxy + * entity which fails to resolve, without this line. + * This was the cause of issue #414 (https://github.com/Part-DB/Part-DB-server/issues/414) + */ $qb->select('log') - //->where('log INSTANCE OF App\Entity\LogSystem\ElementEditedLogEntry') + ->addSelect('user') ->where('log INSTANCE OF '.$log_class) + ->leftJoin('log.user', 'user') ->andWhere('log.target_type = :target_type') ->andWhere('log.target_id = :target_id') - ->orderBy('log.timestamp', 'DESC'); + ->orderBy('log.timestamp', 'DESC') + //Use id as fallback, if timestamp is the same (higher id means newer entry) + ->addOrderBy('log.id', 'DESC') + ; - $qb->setParameters([ - 'target_type' => LogTargetType::fromElementClass($element), - 'target_id' => $element->getID(), - ]); + $qb->setParameter('target_type', LogTargetType::fromElementClass($element)); + $qb->setParameter('target_id', $element->getID()); $query = $qb->getQuery(); $query->setMaxResults(1); + /** @var AbstractLogEntry[] $results */ $results = $query->execute(); if (isset($results[0])) { diff --git a/src/Repository/NamedDBElementRepository.php b/src/Repository/NamedDBElementRepository.php index ae8d4d8f..8c78cb5e 100644 --- a/src/Repository/NamedDBElementRepository.php +++ b/src/Repository/NamedDBElementRepository.php @@ -29,6 +29,7 @@ use App\Helpers\Trees\TreeViewNode; /** * @template TEntityClass of AbstractNamedDBElement * @extends DBElementRepository + * @see \App\Tests\Repository\NamedDBElementRepositoryTest */ class NamedDBElementRepository extends DBElementRepository { @@ -42,7 +43,7 @@ class NamedDBElementRepository extends DBElementRepository { $result = []; - $entities = $this->findBy([], ['name' => 'ASC']); + $entities = $this->getFlatList(); foreach ($entities as $entity) { /** @var AbstractNamedDBElement $entity */ $node = new TreeViewNode($entity->getName(), null, null); @@ -65,13 +66,17 @@ class NamedDBElementRepository extends DBElementRepository } /** - * Returns a flattened list of all nodes. + * Returns a flattened list of all nodes, sorted by name in natural order. * @return AbstractNamedDBElement[] * @phpstan-return array */ public function getFlatList(): array { - //All nodes are sorted by name - return $this->findBy([], ['name' => 'ASC']); + $qb = $this->createQueryBuilder('e'); + $q = $qb->select('e') + ->orderBy('NATSORT(e.name)', 'ASC') + ->getQuery(); + + return $q->getResult(); } } diff --git a/src/Repository/ParameterRepository.php b/src/Repository/ParameterRepository.php index a837435e..6c6c867d 100644 --- a/src/Repository/ParameterRepository.php +++ b/src/Repository/ParameterRepository.php @@ -44,7 +44,7 @@ class ParameterRepository extends DBElementRepository ->select('parameter.name') ->addSelect('parameter.symbol') ->addSelect('parameter.unit') - ->where('parameter.name LIKE :name'); + ->where('ILIKE(parameter.name, :name) = TRUE'); if ($exact) { $qb->setParameter('name', $name); } else { diff --git a/src/Repository/PartRepository.php b/src/Repository/PartRepository.php index 3ab3ed31..edccd74b 100644 --- a/src/Repository/PartRepository.php +++ b/src/Repository/PartRepository.php @@ -81,16 +81,16 @@ class PartRepository extends NamedDBElementRepository ->leftJoin('part.category', 'category') ->leftJoin('part.footprint', 'footprint') - ->where('part.name LIKE :query') - ->orWhere('part.description LIKE :query') - ->orWhere('category.name LIKE :query') - ->orWhere('footprint.name LIKE :query') + ->where('ILIKE(part.name, :query) = TRUE') + ->orWhere('ILIKE(part.description, :query) = TRUE') + ->orWhere('ILIKE(category.name, :query) = TRUE') + ->orWhere('ILIKE(footprint.name, :query) = TRUE') ; $qb->setParameter('query', '%'.$query.'%'); $qb->setMaxResults($max_limits); - $qb->orderBy('part.name', 'ASC'); + $qb->orderBy('NATSORT(part.name)', 'ASC'); return $qb->getQuery()->getResult(); } diff --git a/src/Repository/Parts/CategoryRepository.php b/src/Repository/Parts/CategoryRepository.php index 8e270047..9bbb1e37 100644 --- a/src/Repository/Parts/CategoryRepository.php +++ b/src/Repository/Parts/CategoryRepository.php @@ -28,13 +28,13 @@ use InvalidArgumentException; class CategoryRepository extends AbstractPartsContainingRepository { - public function getParts(object $element, array $order_by = ['name' => 'ASC']): array + public function getParts(object $element, string $nameOrderDirection = "ASC"): array { if (!$element instanceof Category) { throw new InvalidArgumentException('$element must be an Category!'); } - return $this->getPartsByField($element, $order_by, 'category'); + return $this->getPartsByField($element, $nameOrderDirection, 'category'); } public function getPartsCount(object $element): int diff --git a/src/Repository/Parts/FootprintRepository.php b/src/Repository/Parts/FootprintRepository.php index 355cb1bb..8934831a 100644 --- a/src/Repository/Parts/FootprintRepository.php +++ b/src/Repository/Parts/FootprintRepository.php @@ -28,13 +28,13 @@ use InvalidArgumentException; class FootprintRepository extends AbstractPartsContainingRepository { - public function getParts(object $element, array $order_by = ['name' => 'ASC']): array + public function getParts(object $element, string $nameOrderDirection = "ASC"): array { if (!$element instanceof Footprint) { throw new InvalidArgumentException('$element must be an Footprint!'); } - return $this->getPartsByField($element, $order_by, 'footprint'); + return $this->getPartsByField($element, $nameOrderDirection, 'footprint'); } public function getPartsCount(object $element): int diff --git a/src/Repository/Parts/ManufacturerRepository.php b/src/Repository/Parts/ManufacturerRepository.php index a47142d4..1a838710 100644 --- a/src/Repository/Parts/ManufacturerRepository.php +++ b/src/Repository/Parts/ManufacturerRepository.php @@ -28,13 +28,13 @@ use InvalidArgumentException; class ManufacturerRepository extends AbstractPartsContainingRepository { - public function getParts(object $element, array $order_by = ['name' => 'ASC']): array + public function getParts(object $element, string $nameOrderDirection = "ASC"): array { if (!$element instanceof Manufacturer) { throw new InvalidArgumentException('$element must be an Manufacturer!'); } - return $this->getPartsByField($element, $order_by, 'manufacturer'); + return $this->getPartsByField($element, $nameOrderDirection, 'manufacturer'); } public function getPartsCount(object $element): int diff --git a/src/Repository/Parts/MeasurementUnitRepository.php b/src/Repository/Parts/MeasurementUnitRepository.php index 1c9b106b..c581f751 100644 --- a/src/Repository/Parts/MeasurementUnitRepository.php +++ b/src/Repository/Parts/MeasurementUnitRepository.php @@ -28,13 +28,13 @@ use InvalidArgumentException; class MeasurementUnitRepository extends AbstractPartsContainingRepository { - public function getParts(object $element, array $order_by = ['name' => 'ASC']): array + public function getParts(object $element, string $nameOrderDirection = "ASC"): array { if (!$element instanceof MeasurementUnit) { throw new InvalidArgumentException('$element must be an MeasurementUnit!'); } - return $this->getPartsByField($element, $order_by, 'partUnit'); + return $this->getPartsByField($element, $nameOrderDirection, 'partUnit'); } public function getPartsCount(object $element): int diff --git a/src/Repository/Parts/StorelocationRepository.php b/src/Repository/Parts/StorelocationRepository.php index e6eea9a5..82317868 100644 --- a/src/Repository/Parts/StorelocationRepository.php +++ b/src/Repository/Parts/StorelocationRepository.php @@ -23,21 +23,16 @@ declare(strict_types=1); namespace App\Repository\Parts; use App\Entity\Parts\Part; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Repository\AbstractPartsContainingRepository; use Doctrine\ORM\QueryBuilder; use InvalidArgumentException; class StorelocationRepository extends AbstractPartsContainingRepository { - /** - * @param object $element - * @param array $order_by - * @return array - */ - public function getParts(object $element, array $order_by = ['name' => 'ASC']): array + public function getParts(object $element, string $nameOrderDirection = "ASC"): array { - if (!$element instanceof Storelocation) { + if (!$element instanceof StorageLocation) { throw new InvalidArgumentException('$element must be an Storelocation!'); } @@ -47,18 +42,16 @@ class StorelocationRepository extends AbstractPartsContainingRepository ->from(Part::class, 'part') ->leftJoin('part.partLots', 'lots') ->where('lots.storage_location = ?1') - ->setParameter(1, $element); - - foreach ($order_by as $field => $order) { - $qb->addOrderBy('part.'.$field, $order); - } + ->setParameter(1, $element) + ->orderBy('NATSORT(part.name)', $nameOrderDirection) + ; return $qb->getQuery()->getResult(); } public function getPartsCount(object $element): int { - if (!$element instanceof Storelocation) { + if (!$element instanceof StorageLocation) { throw new InvalidArgumentException('$element must be an Storelocation!'); } diff --git a/src/Repository/Parts/SupplierRepository.php b/src/Repository/Parts/SupplierRepository.php index 6dc995f1..393ae593 100644 --- a/src/Repository/Parts/SupplierRepository.php +++ b/src/Repository/Parts/SupplierRepository.php @@ -30,7 +30,7 @@ use InvalidArgumentException; class SupplierRepository extends AbstractPartsContainingRepository { - public function getParts(object $element, array $order_by = ['name' => 'ASC']): array + public function getParts(object $element, string $nameOrderDirection = "ASC"): array { if (!$element instanceof Supplier) { throw new InvalidArgumentException('$element must be an Supplier!'); @@ -42,11 +42,9 @@ class SupplierRepository extends AbstractPartsContainingRepository ->from(Part::class, 'part') ->leftJoin('part.orderdetails', 'orderdetail') ->where('orderdetail.supplier = ?1') - ->setParameter(1, $element); - - foreach ($order_by as $field => $order) { - $qb->addOrderBy('part.'.$field, $order); - } + ->setParameter(1, $element) + ->orderBy('NATSORT(part.name)', $nameOrderDirection) + ; return $qb->getQuery()->getResult(); } diff --git a/src/Repository/StructuralDBElementRepository.php b/src/Repository/StructuralDBElementRepository.php index 978cee20..781c7622 100644 --- a/src/Repository/StructuralDBElementRepository.php +++ b/src/Repository/StructuralDBElementRepository.php @@ -40,6 +40,28 @@ class StructuralDBElementRepository extends AttachmentContainingDBElementReposit */ private array $new_entity_cache = []; + /** + * Finds all nodes for the given parent node, ordered by name in a natural sort way + * @param AbstractStructuralDBElement|null $parent + * @param string $nameOrdering The ordering of the names. Either ASC or DESC + * @return array + */ + public function findNodesForParent(?AbstractStructuralDBElement $parent, string $nameOrdering = "ASC"): array + { + $qb = $this->createQueryBuilder('e'); + $qb->select('e') + ->orderBy('NATSORT(e.name)', $nameOrdering); + + if ($parent !== null) { + $qb->where('e.parent = :parent') + ->setParameter('parent', $parent); + } else { + $qb->where('e.parent IS NULL'); + } + //@phpstan-ignore-next-line [parent is only defined by the sub classes] + return $qb->getQuery()->getResult(); + } + /** * Finds all nodes without a parent node. They are our root nodes. * @@ -47,7 +69,7 @@ class StructuralDBElementRepository extends AttachmentContainingDBElementReposit */ public function findRootNodes(): array { - return $this->findBy(['parent' => null], ['name' => 'ASC']); + return $this->findNodesForParent(null); } /** @@ -63,7 +85,7 @@ class StructuralDBElementRepository extends AttachmentContainingDBElementReposit { $result = []; - $entities = $this->findBy(['parent' => $parent], ['name' => 'ASC']); + $entities = $this->findNodesForParent($parent); foreach ($entities as $entity) { /** @var AbstractStructuralDBElement $entity */ //Make a recursive call to find all children nodes @@ -89,7 +111,7 @@ class StructuralDBElementRepository extends AttachmentContainingDBElementReposit { $result = []; - $entities = $this->findBy(['parent' => $parent], ['name' => 'ASC']); + $entities = $this->findNodesForParent($parent); $elementIterator = new StructuralDBElementIterator($entities); $recursiveIterator = new RecursiveIteratorIterator($elementIterator, RecursiveIteratorIterator::SELF_FIRST); @@ -129,7 +151,7 @@ class StructuralDBElementRepository extends AttachmentContainingDBElementReposit } if (null === $entity) { $class = $this->getClassName(); - /** @var AbstractStructuralDBElement $entity */ + /** @var TEntityClass $entity */ $entity = new $class; $entity->setName($name); $entity->setParent($parent); @@ -238,12 +260,12 @@ class StructuralDBElementRepository extends AttachmentContainingDBElementReposit //Try to find if we already have an element cached for this name $entity = $this->getNewEntityFromCache($name, null); - if ($entity) { + if ($entity !== null) { return $entity; } $class = $this->getClassName(); - /** @var AbstractStructuralDBElement $entity */ + /** @var TEntityClass $entity */ $entity = new $class; $entity->setName($name); diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index f1e738d0..bbaa2b39 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -23,7 +23,9 @@ declare(strict_types=1); namespace App\Repository; use App\Entity\UserSystem\User; +use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\NonUniqueResultException; +use Doctrine\ORM\Query\Parameter; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; use Symfony\Component\Security\Core\User\UserInterface; @@ -34,6 +36,7 @@ use Symfony\Component\Security\Core\User\UserInterface; * @method User[] findAll() * @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) * @extends NamedDBElementRepository + * @see \App\Tests\Repository\UserRepositoryTest */ final class UserRepository extends NamedDBElementRepository implements PasswordUpgraderInterface { @@ -42,6 +45,7 @@ final class UserRepository extends NamedDBElementRepository implements PasswordU /** * Returns the anonymous user. * The result is cached, so the database is only called once, after the anonymous user was found. + * @return User|null The user if it is existing, null if no one matched the criteria */ public function getAnonymousUser(): ?User { @@ -54,6 +58,30 @@ final class UserRepository extends NamedDBElementRepository implements PasswordU return $this->anonymous_user; } + /** + * Find a user by its username. + * @param string $username + * @return User|null + */ + public function findByUsername(string $username): ?User + { + if ($username === '') { + return null; + } + + $qb = $this->createQueryBuilder('u'); + $qb->select('u') + ->where('u.name = (:name)'); + + $qb->setParameter('name', $username); + + try { + return $qb->getQuery()->getOneOrNullResult(); + } catch (NonUniqueResultException) { + return null; + } + } + /** * Find a user by its name or its email. Useful for login or password reset purposes. * @@ -72,10 +100,8 @@ final class UserRepository extends NamedDBElementRepository implements PasswordU ->where('u.name = (:name)') ->orWhere('u.email = (:email)'); - $qb->setParameters([ - 'email' => $name_or_password, - 'name' => $name_or_password, - ]); + $qb->setParameter('email', $name_or_password); + $qb->setParameter('name', $name_or_password); try { return $qb->getQuery()->getOneOrNullResult(); diff --git a/src/Repository/UserSystem/ApiTokenRepository.php b/src/Repository/UserSystem/ApiTokenRepository.php new file mode 100644 index 00000000..609014f3 --- /dev/null +++ b/src/Repository/UserSystem/ApiTokenRepository.php @@ -0,0 +1,30 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Repository\UserSystem; + +use Doctrine\ORM\EntityRepository; + +class ApiTokenRepository extends EntityRepository +{ +} \ No newline at end of file diff --git a/src/Security/ApiTokenAuthenticatedToken.php b/src/Security/ApiTokenAuthenticatedToken.php new file mode 100644 index 00000000..2f186e63 --- /dev/null +++ b/src/Security/ApiTokenAuthenticatedToken.php @@ -0,0 +1,52 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Security; + +use App\Entity\UserSystem\ApiToken; +use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken; + +class ApiTokenAuthenticatedToken extends PostAuthenticationToken +{ + public function __construct(UserInterface $user, string $firewallName, array $roles, private readonly ApiToken $apiToken) + { + //Add roles for the API + $roles[] = 'ROLE_API_AUTHENTICATED'; + + //Add roles based on the token level + $roles = array_merge($roles, $apiToken->getLevel()->getAdditionalRoles()); + + + parent::__construct($user, $firewallName, array_unique($roles)); + } + + /** + * Returns the API token that was used to authenticate the user. + * @return ApiToken + */ + public function getApiToken(): ApiToken + { + return $this->apiToken; + } +} \ No newline at end of file diff --git a/src/Security/ApiTokenAuthenticator.php b/src/Security/ApiTokenAuthenticator.php new file mode 100644 index 00000000..a52b1f7c --- /dev/null +++ b/src/Security/ApiTokenAuthenticator.php @@ -0,0 +1,156 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Security; + +use App\Entity\UserSystem\ApiToken; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; +use Symfony\Component\Security\Http\AccessToken\AccessTokenExtractorInterface; +use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface; +use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; +use Symfony\Component\Security\Http\Authenticator\Passport\Passport; +use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; +use Symfony\Contracts\Translation\TranslatorInterface; + +/** + * Authenticator similar to the builtin AccessTokenAuthenticator, but we return a Token here which contains information + * about the used token. + */ +class ApiTokenAuthenticator implements AuthenticatorInterface +{ + public function __construct( + #[Autowire(service: 'security.access_token_extractor.main')] + private readonly AccessTokenExtractorInterface $accessTokenExtractor, + private readonly TranslatorInterface $translator, + private readonly EntityManagerInterface $entityManager, + private readonly string $realm = 'api', + ) { + } + + /** + * Gets the ApiToken belonging to the given accessToken string. + * If the token is invalid or expired, an exception is thrown and authentication fails. + * @param string $accessToken + * @return ApiToken + */ + private function getTokenFromString(#[\SensitiveParameter] string $accessToken): ApiToken + { + $repo = $this->entityManager->getRepository(ApiToken::class); + $token = $repo->findOneBy(['token' => $accessToken]); + + if (!$token instanceof ApiToken) { + throw new BadCredentialsException(); + } + + if (!$token->isValid()) { + throw new CustomUserMessageAuthenticationException('Token expired'); + } + + $old_time = $token->getLastTimeUsed(); + //Set the last used date of the token + $token->setLastTimeUsed(new \DateTimeImmutable()); + //Only flush the token if the last used date change is more than 10 minutes + //For performance reasons we don't want to flush the token every time it is used, but only if it is used more than 10 minutes after the last time it was used + //If a flush is later in the code we don't want to flush the token again + if ($old_time === null || $old_time->diff($token->getLastTimeUsed())->i > 10) { + $this->entityManager->flush(); + } + + return $token; + } + + public function supports(Request $request): ?bool + { + return null === $this->accessTokenExtractor->extractAccessToken($request) ? false : null; + } + + public function authenticate(Request $request): Passport + { + $accessToken = $this->accessTokenExtractor->extractAccessToken($request); + if (!$accessToken) { + throw new BadCredentialsException('Invalid credentials.'); + } + + $apiToken = $this->getTokenFromString($accessToken); + $userBadge = new UserBadge($apiToken->getUser()?->getUserIdentifier() ?? throw new BadCredentialsException('Invalid credentials.')); + $apiBadge = new ApiTokenBadge($apiToken); + + return new SelfValidatingPassport($userBadge, [$apiBadge]); + } + + public function createToken(Passport $passport, string $firewallName): TokenInterface + { + return new ApiTokenAuthenticatedToken( + $passport->getUser(), + $firewallName, + $passport->getUser()->getRoles(), + $passport->getBadge(ApiTokenBadge::class)?->getApiToken() ?? throw new \LogicException('Passport does not contain an API token.') + ); + } + + + public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response + { + $errorMessage = $this->translator->trans($exception->getMessageKey(), $exception->getMessageData(), + 'security'); + + return new Response( + null, + Response::HTTP_UNAUTHORIZED, + ['WWW-Authenticate' => $this->getAuthenticateHeader($errorMessage)] + ); + } + + /** + * @see https://datatracker.ietf.org/doc/html/rfc6750#section-3 + */ + private function getAuthenticateHeader(?string $errorDescription = null): string + { + $data = [ + 'realm' => $this->realm, + 'error' => 'invalid_token', + 'error_description' => $errorDescription, + ]; + $values = []; + foreach ($data as $k => $v) { + if (null === $v || '' === $v) { + continue; + } + $values[] = sprintf('%s="%s"', $k, $v); + } + + return sprintf('Bearer %s', implode(',', $values)); + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response + { + return null; + } +} \ No newline at end of file diff --git a/src/Security/ApiTokenBadge.php b/src/Security/ApiTokenBadge.php new file mode 100644 index 00000000..d2429a06 --- /dev/null +++ b/src/Security/ApiTokenBadge.php @@ -0,0 +1,51 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Security; + +use App\Entity\UserSystem\ApiToken; +use Symfony\Component\Security\Http\Authenticator\Passport\Badge\BadgeInterface; + +class ApiTokenBadge implements BadgeInterface +{ + + /** + * @param ApiToken $apiToken + */ + public function __construct(private readonly ApiToken $apiToken) + { + } + + /** + * @return ApiToken The token that was used to authenticate the user + */ + public function getApiToken(): ApiToken + { + return $this->apiToken; + } + + public function isResolved(): bool + { + return true; + } +} \ No newline at end of file diff --git a/src/Security/AuthenticationEntryPoint.php b/src/Security/AuthenticationEntryPoint.php new file mode 100644 index 00000000..41f624b2 --- /dev/null +++ b/src/Security/AuthenticationEntryPoint.php @@ -0,0 +1,89 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Security; + +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; + +use function Symfony\Component\Translation\t; + +/** + * This class decides, what to do, when a user tries to access a page, that requires authentication and he is not + * authenticated / logged in yet. + * For browser requests, the user is redirected to the login page, for API requests, a 401 response with a JSON encoded + * message is returned. + */ +class AuthenticationEntryPoint implements AuthenticationEntryPointInterface +{ + public function __construct( + private readonly UrlGeneratorInterface $urlGenerator, + ) { + } + + public function start(Request $request, ?AuthenticationException $authException = null): Response + { + //Check if the request is an API request + if ($this->isJSONRequest($request)) { + //If it is, we return a 401 response with a JSON body + return new JsonResponse([ + 'title' => 'Unauthorized', + 'detail' => 'Authentication is required. Please pass a valid API token in the Authorization header.', + ], Response::HTTP_UNAUTHORIZED); + } + + //Otherwise we redirect to the login page + + //Add a nice flash message to make it clear what happened + if ($request->getSession() instanceof Session) { + $request->getSession()->getFlashBag()->add('error', t('login.flash.access_denied_please_login')); + } + + return new RedirectResponse($this->urlGenerator->generate('login')); + } + + private function isJSONRequest(Request $request): bool + { + //If either the content type or accept header is a json type, we assume it is an API request + $contentType = $request->headers->get('Content-Type'); + $accept = $request->headers->get('Accept'); + + $tmp = false; + + if ($contentType !== null) { + $tmp = str_contains($contentType, 'json'); + } + + if ($accept !== null) { + $tmp = $tmp || str_contains($accept, 'json'); + } + + return $tmp; + } +} \ No newline at end of file diff --git a/src/Security/EnsureSAMLUserForSAMLLoginChecker.php b/src/Security/EnsureSAMLUserForSAMLLoginChecker.php index 7b540984..0ebf893c 100644 --- a/src/Security/EnsureSAMLUserForSAMLLoginChecker.php +++ b/src/Security/EnsureSAMLUserForSAMLLoginChecker.php @@ -25,6 +25,7 @@ namespace App\Security; use App\Entity\UserSystem\User; use Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\Token\SamlToken; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent; use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException; use Symfony\Contracts\Translation\TranslatorInterface; @@ -50,13 +51,20 @@ class EnsureSAMLUserForSAMLLoginChecker implements EventSubscriberInterface $token = $event->getAuthenticationToken(); $user = $token->getUser(); - //If we are using SAML, we need to check that the user is a SAML user. - if ($token instanceof SamlToken) { - if ($user instanceof User && !$user->isSamlUser()) { - throw new CustomUserMessageAccountStatusException($this->translator->trans('saml.error.cannot_login_local_user_per_saml', [], 'security')); - } - } elseif ($user instanceof User && $user->isSamlUser()) { - //Ensure that you can not login locally with a SAML user (even if this should not happen, as the password is not set) + //Do not check for anonymous users + if (!$user instanceof User) { + return; + } + + //Do not allow SAML users to login as local user + if ($token instanceof SamlToken && !$user->isSamlUser()) { + throw new CustomUserMessageAccountStatusException($this->translator->trans('saml.error.cannot_login_local_user_per_saml', + [], 'security')); + } + + //Do not allow local users to login as SAML user via local username and password + if ($token instanceof UsernamePasswordToken && $user->isSamlUser()) { + //Ensure that you can not login locally with a SAML user (even though this should not happen, as the password is not set) throw new CustomUserMessageAccountStatusException($this->translator->trans('saml.error.cannot_login_saml_user_locally', [], 'security')); } } diff --git a/src/Security/SamlUserFactory.php b/src/Security/SamlUserFactory.php index d5c68146..312be859 100644 --- a/src/Security/SamlUserFactory.php +++ b/src/Security/SamlUserFactory.php @@ -116,10 +116,10 @@ class SamlUserFactory implements SamlUserFactoryInterface, EventSubscriberInterf * Maps a list of SAML roles to a local group ID. * The first available mapping will be used (so the order of the $map is important, first match wins). * @param array $roles The list of SAML roles - * @param array $map|null The mapping from SAML roles. If null, the global mapping will be used. + * @param array|null $map The mapping from SAML roles. If null, the global mapping will be used. * @return int|null The ID of the local group or null if no mapping was found. */ - public function mapSAMLRolesToLocalGroupID(array $roles, array $map = null): ?int + public function mapSAMLRolesToLocalGroupID(array $roles, ?array $map = null): ?int { $map ??= $this->saml_role_mapping; diff --git a/src/Security/TwoFactor/WebauthnKeyLastUseTwoFactorProvider.php b/src/Security/TwoFactor/WebauthnKeyLastUseTwoFactorProvider.php new file mode 100644 index 00000000..9bfa691d --- /dev/null +++ b/src/Security/TwoFactor/WebauthnKeyLastUseTwoFactorProvider.php @@ -0,0 +1,106 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Security\TwoFactor; + +use App\Entity\UserSystem\WebauthnKey; +use Doctrine\ORM\EntityManagerInterface; +use Jbtronics\TFAWebauthn\Services\UserPublicKeyCredentialSourceRepository; +use Jbtronics\TFAWebauthn\Services\WebauthnProvider; +use Scheb\TwoFactorBundle\Security\TwoFactor\AuthenticationContextInterface; +use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\TwoFactorFormRendererInterface; +use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\TwoFactorProviderInterface; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated; + +/** + * This class decorates the Webauthn TwoFactorProvider and adds additional logic which allows us to set a last used date + * on the used webauthn key, which can be viewed in the user settings. + */ +#[AsDecorator('jbtronics_webauthn_tfa.two_factor_provider')] +class WebauthnKeyLastUseTwoFactorProvider implements TwoFactorProviderInterface +{ + + public function __construct( + #[AutowireDecorated] + private readonly TwoFactorProviderInterface $decorated, + private readonly EntityManagerInterface $entityManager, + #[Autowire(service: 'jbtronics_webauthn_tfa.user_public_key_source_repo')] + private readonly UserPublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository, + #[Autowire(service: 'jbtronics_webauthn_tfa.webauthn_provider')] + private readonly WebauthnProvider $webauthnProvider, + ) + { + } + + public function beginAuthentication(AuthenticationContextInterface $context): bool + { + return $this->decorated->beginAuthentication($context); + } + + public function prepareAuthentication(object $user): void + { + $this->decorated->prepareAuthentication($user); + } + + public function validateAuthenticationCode(object $user, string $authenticationCode): bool + { + //Try to extract the used webauthn key from the code + $webauthnKey = $this->getWebauthnKeyFromCode($authenticationCode); + + //Perform the actual validation like normal + $tmp = $this->decorated->validateAuthenticationCode($user, $authenticationCode); + + //Update the last used date of the webauthn key, if the validation was successful + if($tmp && $webauthnKey !== null) { + $webauthnKey->updateLastTimeUsed(); + $this->entityManager->flush(); + } + + return $tmp; + } + + public function getFormRenderer(): TwoFactorFormRendererInterface + { + return $this->decorated->getFormRenderer(); + } + + private function getWebauthnKeyFromCode(string $authenticationCode): ?WebauthnKey + { + $publicKeyCredentialLoader = $this->webauthnProvider->getPublicKeyCredentialLoader(); + + //Try to load the public key credential from the code + $publicKeyCredential = $publicKeyCredentialLoader->load($authenticationCode); + + //Find the credential source for the given credential id + $publicKeyCredentialSource = $this->publicKeyCredentialSourceRepository->findOneByCredentialId($publicKeyCredential->rawId); + + //If the credential source is not an instance of WebauthnKey, return null + if(!($publicKeyCredentialSource instanceof WebauthnKey)) { + return null; + } + + return $publicKeyCredentialSource; + } +} \ No newline at end of file diff --git a/src/Security/UserChecker.php b/src/Security/UserChecker.php index fd53a295..16afb37e 100644 --- a/src/Security/UserChecker.php +++ b/src/Security/UserChecker.php @@ -40,12 +40,10 @@ final class UserChecker implements UserCheckerInterface /** * Checks the user account before authentication. - * - * @throws AccountStatusException */ public function checkPreAuth(UserInterface $user): void { - // TODO: Implement checkPreAuth() method. + //We don't need to check the user before authentication, just implemented to fulfill the interface } /** diff --git a/src/Security/Voter/AttachmentVoter.php b/src/Security/Voter/AttachmentVoter.php index 0b32188c..c2b17053 100644 --- a/src/Security/Voter/AttachmentVoter.php +++ b/src/Security/Voter/AttachmentVoter.php @@ -22,6 +22,7 @@ declare(strict_types=1); namespace App\Security\Voter; +use App\Services\UserSystem\VoterHelper; use Symfony\Bundle\SecurityBundle\Security; use App\Entity\Attachments\AttachmentContainingDBElement; use App\Entity\Attachments\Attachment; @@ -34,32 +35,29 @@ use App\Entity\Attachments\ManufacturerAttachment; use App\Entity\Attachments\MeasurementUnitAttachment; use App\Entity\Attachments\PartAttachment; use App\Entity\Attachments\ProjectAttachment; -use App\Entity\Attachments\StorelocationAttachment; +use App\Entity\Attachments\StorageLocationAttachment; use App\Entity\Attachments\SupplierAttachment; use App\Entity\Attachments\UserAttachment; -use App\Entity\UserSystem\User; -use App\Services\UserSystem\PermissionManager; -use Doctrine\ORM\EntityManagerInterface; use RuntimeException; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; + use function in_array; -class AttachmentVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class AttachmentVoter extends Voter { - public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, protected Security $security) + private const ALLOWED_ATTRIBUTES = ['read', 'view', 'edit', 'delete', 'create', 'show_private', 'show_history']; + + public function __construct(private readonly Security $security, private readonly VoterHelper $helper) { - parent::__construct($resolver, $entityManager); } - /** - * Similar to voteOnAttribute, but checking for the anonymous user is already done. - * The current user (or the anonymous user) is passed by $user. - * - * @param string $attribute - */ - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { - //return $this->resolver->inherit($user, 'attachments', $attribute) ?? false; //This voter only works for attachments if (!is_a($subject, Attachment::class, true)) { @@ -67,7 +65,7 @@ class AttachmentVoter extends ExtendedVoter } if ($attribute === 'show_private') { - return $this->resolver->inherit($user, 'attachments', 'show_private') ?? false; + return $this->helper->isGranted($token, 'attachments', 'show_private'); } @@ -99,7 +97,7 @@ class AttachmentVoter extends ExtendedVoter $param = 'measurement_units'; } elseif (is_a($subject, PartAttachment::class, true)) { $param = 'parts'; - } elseif (is_a($subject, StorelocationAttachment::class, true)) { + } elseif (is_a($subject, StorageLocationAttachment::class, true)) { $param = 'storelocations'; } elseif (is_a($subject, SupplierAttachment::class, true)) { $param = 'suppliers'; @@ -113,7 +111,7 @@ class AttachmentVoter extends ExtendedVoter throw new RuntimeException('Encountered unknown Parameter type: ' . $subject); } - return $this->resolver->inherit($user, $param, $this->mapOperation($attribute)) ?? false; + return $this->helper->isGranted($token, $param, $this->mapOperation($attribute)); } return false; @@ -137,14 +135,24 @@ class AttachmentVoter extends ExtendedVoter * * @return bool True if the attribute and subject are supported, false otherwise */ - protected function supports(string $attribute, $subject): bool + protected function supports(string $attribute, mixed $subject): bool { if (is_a($subject, Attachment::class, true)) { //These are the allowed attributes - return in_array($attribute, ['read', 'view', 'edit', 'delete', 'create', 'show_private', 'show_history'], true); + return in_array($attribute, self::ALLOWED_ATTRIBUTES, true); } //Allow class name as subject return false; } + + public function supportsAttribute(string $attribute): bool + { + return in_array($attribute, self::ALLOWED_ATTRIBUTES, true); + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, Attachment::class, true); + } } diff --git a/src/Security/Voter/BOMEntryVoter.php b/src/Security/Voter/BOMEntryVoter.php new file mode 100644 index 00000000..121c8172 --- /dev/null +++ b/src/Security/Voter/BOMEntryVoter.php @@ -0,0 +1,90 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Security\Voter; + +use App\Entity\ProjectSystem\Project; +use App\Entity\ProjectSystem\ProjectBOMEntry; +use Symfony\Bundle\SecurityBundle\Security; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; + +/** + * @phpstan-extends Voter + */ +class BOMEntryVoter extends Voter +{ + + private const ALLOWED_ATTRIBUTES = ['read', 'view', 'edit', 'delete', 'create', 'show_history']; + + public function __construct(private readonly Security $security) + { + } + + protected function supports(string $attribute, mixed $subject): bool + { + return $this->supportsAttribute($attribute) && is_a($subject, ProjectBOMEntry::class, true); + } + + protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool + { + if (!is_a($subject, ProjectBOMEntry::class, true)) { + return false; + } + + if (is_object($subject)) { + $project = $subject->getProject(); + + //Allow everything if the project was not set yet + if ($project === null) { + return true; + } + } else { + //If a string was given, use the general project permissions to resolve permissions + $project = Project::class; + } + + //Entry can be read if the user has read access to the project + if ($attribute === 'read') { + return $this->security->isGranted('read', $project); + } + + //History can be shown if the user has show_history access to the project + if ($attribute === 'show_history') { + return $this->security->isGranted('show_history', $project); + } + + //Everything else can be done if the user has edit access to the project + return $this->security->isGranted('edit', $project); + } + + public function supportsAttribute(string $attribute): bool + { + return in_array($attribute, self::ALLOWED_ATTRIBUTES, true); + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, ProjectBOMEntry::class, true); + } +} \ No newline at end of file diff --git a/src/Security/Voter/ExtendedVoter.php b/src/Security/Voter/ExtendedVoter.php deleted file mode 100644 index 279944fc..00000000 --- a/src/Security/Voter/ExtendedVoter.php +++ /dev/null @@ -1,68 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace App\Security\Voter; - -use App\Entity\UserSystem\User; -use App\Repository\UserRepository; -use App\Services\UserSystem\PermissionManager; -use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\Voter\Voter; - -/** - * The purpose of this class is, to use the anonymous user from DB in the case, that nobody is logged in. - */ -abstract class ExtendedVoter extends Voter -{ - public function __construct(protected PermissionManager $resolver, protected EntityManagerInterface $entityManager) - { - } - - final protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool - { - $user = $token->getUser(); - - //An allowed user is not allowed to do anything... - if ($user instanceof User && $user->isDisabled()) { - return false; - } - - // if the user is anonymous (meaning $user is null), we use the anonymous user. - if (!$user instanceof User) { - /** @var UserRepository $repo */ - $repo = $this->entityManager->getRepository(User::class); - $user = $repo->getAnonymousUser(); - if (!$user instanceof User) { - return false; - } - } - - return $this->voteOnUser($attribute, $subject, $user); - } - - /** - * Similar to voteOnAttribute, but checking for the anonymous user is already done. - * The current user (or the anonymous user) is passed by $user. - */ - abstract protected function voteOnUser(string $attribute, $subject, User $user): bool; -} diff --git a/src/Security/Voter/GroupVoter.php b/src/Security/Voter/GroupVoter.php index e1e21543..34839d38 100644 --- a/src/Security/Voter/GroupVoter.php +++ b/src/Security/Voter/GroupVoter.php @@ -23,19 +23,29 @@ declare(strict_types=1); namespace App\Security\Voter; use App\Entity\UserSystem\Group; -use App\Entity\UserSystem\User; +use App\Services\UserSystem\VoterHelper; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; -class GroupVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class GroupVoter extends Voter { + + public function __construct(private readonly VoterHelper $helper) + { + } + /** * Similar to voteOnAttribute, but checking for the anonymous user is already done. * The current user (or the anonymous user) is passed by $user. * * @param string $attribute */ - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { - return $this->resolver->inherit($user, 'groups', $attribute) ?? false; + return $this->helper->isGranted($token, 'groups', $attribute); } /** @@ -46,12 +56,22 @@ class GroupVoter extends ExtendedVoter * * @return bool True if the attribute and subject are supported, false otherwise */ - protected function supports(string $attribute, $subject): bool + protected function supports(string $attribute, mixed $subject): bool { if (is_a($subject, Group::class, true)) { - return $this->resolver->isValidOperation('groups', $attribute); + return $this->helper->isValidOperation('groups', $attribute); } return false; } + + public function supportsAttribute(string $attribute): bool + { + return $this->helper->isValidOperation('groups', $attribute); + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, Group::class, true); + } } diff --git a/src/Security/Voter/HasAccessPermissionsVoter.php b/src/Security/Voter/HasAccessPermissionsVoter.php new file mode 100644 index 00000000..bd466d07 --- /dev/null +++ b/src/Security/Voter/HasAccessPermissionsVoter.php @@ -0,0 +1,59 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Security\Voter; + +use App\Services\UserSystem\PermissionManager; +use App\Services\UserSystem\VoterHelper; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; + +/** + * This voter implements a virtual role, which can be used if the user has any permission set to allowed. + * We use this to restrict access to the homepage. + * @phpstan-extends Voter + */ +final class HasAccessPermissionsVoter extends Voter +{ + public const ROLE = "HAS_ACCESS_PERMISSIONS"; + + public function __construct(private readonly PermissionManager $permissionManager, private readonly VoterHelper $helper) + { + } + + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool + { + $user = $this->helper->resolveUser($token); + return $this->permissionManager->hasAnyPermissionSetToAllowInherited($user); + } + + protected function supports(string $attribute, mixed $subject): bool + { + return $attribute === self::ROLE; + } + + public function supportsAttribute(string $attribute): bool + { + return $attribute === self::ROLE; + } +} \ No newline at end of file diff --git a/src/Security/Voter/ImpersonateUserVoter.php b/src/Security/Voter/ImpersonateUserVoter.php index f1392568..edf55c62 100644 --- a/src/Security/Voter/ImpersonateUserVoter.php +++ b/src/Security/Voter/ImpersonateUserVoter.php @@ -24,37 +24,41 @@ declare(strict_types=1); namespace App\Security\Voter; use App\Entity\UserSystem\User; -use App\Services\UserSystem\PermissionManager; +use App\Services\UserSystem\VoterHelper; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Voter; use Symfony\Component\Security\Core\User\UserInterface; -class ImpersonateUserVoter extends Voter +/** + * This voter implements a virtual role, which can be used if the user has any permission set to allowed. + * We use this to restrict access to the homepage. + * @phpstan-extends Voter + */ +final class ImpersonateUserVoter extends Voter { - public function __construct(private PermissionManager $permissionManager) + public function __construct(private readonly VoterHelper $helper) { } protected function supports(string $attribute, mixed $subject): bool { - return $attribute == 'CAN_SWITCH_USER' + return $attribute === 'CAN_SWITCH_USER' && $subject instanceof UserInterface; } protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool { - $user = $token->getUser(); + return $this->helper->isGranted($token, 'users', 'impersonate'); + } - if (!$user instanceof User || !$subject instanceof UserInterface) { - return false; - } + public function supportsAttribute(string $attribute): bool + { + return $attribute === 'CAN_SWITCH_USER'; + } - //An disabled user is not allowed to do anything... - if ($user->isDisabled()) { - return false; - } - - return $this->permissionManager->inherit($user, 'users', 'impersonate') ?? false; + public function supportsType(string $subjectType): bool + { + return is_a($subjectType, User::class, true); } } \ No newline at end of file diff --git a/src/Security/Voter/LabelProfileVoter.php b/src/Security/Voter/LabelProfileVoter.php index 5a3699a2..47505bf9 100644 --- a/src/Security/Voter/LabelProfileVoter.php +++ b/src/Security/Voter/LabelProfileVoter.php @@ -42,9 +42,14 @@ declare(strict_types=1); namespace App\Security\Voter; use App\Entity\LabelSystem\LabelProfile; -use App\Entity\UserSystem\User; +use App\Services\UserSystem\VoterHelper; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; -class LabelProfileVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class LabelProfileVoter extends Voter { protected const MAPPING = [ 'read' => 'read_profiles', @@ -55,21 +60,34 @@ class LabelProfileVoter extends ExtendedVoter 'revert_element' => 'revert_element', ]; - protected function voteOnUser(string $attribute, $subject, User $user): bool + public function __construct(private readonly VoterHelper $helper) + {} + + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { - return $this->resolver->inherit($user, 'labels', self::MAPPING[$attribute]) ?? false; + return $this->helper->isGranted($token, 'labels', self::MAPPING[$attribute]); } protected function supports($attribute, $subject): bool { - if ($subject instanceof LabelProfile) { + if (is_a($subject, LabelProfile::class, true)) { if (!isset(self::MAPPING[$attribute])) { return false; } - return $this->resolver->isValidOperation('labels', self::MAPPING[$attribute]); + return $this->helper->isValidOperation('labels', self::MAPPING[$attribute]); } return false; } + + public function supportsAttribute(string $attribute): bool + { + return isset(self::MAPPING[$attribute]); + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, LabelProfile::class, true); + } } diff --git a/src/Security/Voter/LogEntryVoter.php b/src/Security/Voter/LogEntryVoter.php index 20c34863..08bc3b70 100644 --- a/src/Security/Voter/LogEntryVoter.php +++ b/src/Security/Voter/LogEntryVoter.php @@ -22,41 +22,45 @@ declare(strict_types=1); namespace App\Security\Voter; +use App\Services\UserSystem\VoterHelper; use Symfony\Bundle\SecurityBundle\Security; use App\Entity\LogSystem\AbstractLogEntry; -use App\Entity\UserSystem\User; -use App\Services\UserSystem\PermissionManager; -use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; -class LogEntryVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class LogEntryVoter extends Voter { final public const ALLOWED_OPS = ['read', 'show_details', 'delete']; - public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, private readonly Security $security) + public function __construct(private readonly Security $security, private readonly VoterHelper $helper) { - parent::__construct($resolver, $entityManager); } - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { + $user = $this->helper->resolveUser($token); + if (!$subject instanceof AbstractLogEntry) { throw new \InvalidArgumentException('The subject must be an instance of '.AbstractLogEntry::class); } if ('delete' === $attribute) { - return $this->resolver->inherit($user, 'system', 'delete_logs') ?? false; + return $this->helper->isGranted($token, 'system', 'delete_logs'); } if ('read' === $attribute) { //Allow read of the users own log entries if ( $subject->getUser() === $user - && $this->resolver->inherit($user, 'self', 'show_logs') + && $this->helper->isGranted($token, 'self', 'show_logs') ) { return true; } - return $this->resolver->inherit($user, 'system', 'show_logs') ?? false; + return $this->helper->isGranted($token, 'system', 'show_logs'); } if ('show_details' === $attribute) { @@ -67,7 +71,7 @@ class LogEntryVoter extends ExtendedVoter } //In other cases, this behaves like the read permission - return $this->voteOnUser('read', $subject, $user); + return $this->voteOnAttribute('read', $subject, $token); } return false; @@ -81,4 +85,14 @@ class LogEntryVoter extends ExtendedVoter return false; } + + public function supportsAttribute(string $attribute): bool + { + return in_array($attribute, static::ALLOWED_OPS, true); + } + + public function supportsType(string $subjectType): bool + { + return is_a($subjectType, AbstractLogEntry::class, true); + } } diff --git a/src/Security/Voter/OrderdetailVoter.php b/src/Security/Voter/OrderdetailVoter.php index 96ff609e..20843b9a 100644 --- a/src/Security/Voter/OrderdetailVoter.php +++ b/src/Security/Voter/OrderdetailVoter.php @@ -41,23 +41,25 @@ declare(strict_types=1); namespace App\Security\Voter; +use App\Services\UserSystem\VoterHelper; use Symfony\Bundle\SecurityBundle\Security; use App\Entity\Parts\Part; use App\Entity\PriceInformations\Orderdetail; -use App\Entity\UserSystem\User; -use App\Services\UserSystem\PermissionManager; -use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; -class OrderdetailVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class OrderdetailVoter extends Voter { - public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, protected Security $security) + public function __construct(private readonly Security $security, private readonly VoterHelper $helper) { - parent::__construct($resolver, $entityManager); } protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element']; - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { if (! is_a($subject, Orderdetail::class, true)) { throw new \RuntimeException('This voter can only handle Orderdetail objects!'); @@ -73,7 +75,7 @@ class OrderdetailVoter extends ExtendedVoter //If we have no part associated use the generic part permission if (is_string($subject) || !$subject->getPart() instanceof Part) { - return $this->resolver->inherit($user, 'parts', $operation) ?? false; + return $this->helper->isGranted($token, 'parts', $operation); } //Otherwise vote on the part @@ -88,4 +90,14 @@ class OrderdetailVoter extends ExtendedVoter return false; } + + public function supportsAttribute(string $attribute): bool + { + return in_array($attribute, self::ALLOWED_PERMS, true); + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, Orderdetail::class, true); + } } diff --git a/src/Security/Voter/ParameterVoter.php b/src/Security/Voter/ParameterVoter.php index 6f752518..8ee2b9f5 100644 --- a/src/Security/Voter/ParameterVoter.php +++ b/src/Security/Voter/ParameterVoter.php @@ -22,6 +22,7 @@ declare(strict_types=1); */ namespace App\Security\Voter; +use App\Services\UserSystem\VoterHelper; use Symfony\Bundle\SecurityBundle\Security; use App\Entity\Base\AbstractDBElement; use App\Entity\Parameters\AbstractParameter; @@ -34,22 +35,25 @@ use App\Entity\Parameters\GroupParameter; use App\Entity\Parameters\ManufacturerParameter; use App\Entity\Parameters\MeasurementUnitParameter; use App\Entity\Parameters\PartParameter; -use App\Entity\Parameters\StorelocationParameter; +use App\Entity\Parameters\StorageLocationParameter; use App\Entity\Parameters\SupplierParameter; -use App\Entity\UserSystem\User; -use App\Services\UserSystem\PermissionManager; -use Doctrine\ORM\EntityManagerInterface; use RuntimeException; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; -class ParameterVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class ParameterVoter extends Voter { - public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, protected Security $security) + private const ALLOWED_ATTRIBUTES = ['read', 'edit', 'delete', 'create', 'show_history', 'revert_element']; + + public function __construct(private readonly Security $security, private readonly VoterHelper $helper) { - parent::__construct($resolver, $entityManager); } - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { //return $this->resolver->inherit($user, 'attachments', $attribute) ?? false; @@ -92,7 +96,7 @@ class ParameterVoter extends ExtendedVoter $param = 'measurement_units'; } elseif (is_a($subject, PartParameter::class, true)) { $param = 'parts'; - } elseif (is_a($subject, StorelocationParameter::class, true)) { + } elseif (is_a($subject, StorageLocationParameter::class, true)) { $param = 'storelocations'; } elseif (is_a($subject, SupplierParameter::class, true)) { $param = 'suppliers'; @@ -104,17 +108,28 @@ class ParameterVoter extends ExtendedVoter throw new RuntimeException('Encountered unknown Parameter type: ' . (is_object($subject) ? $subject::class : $subject)); } - return $this->resolver->inherit($user, $param, $attribute) ?? false; + return $this->helper->isGranted($token, $param, $attribute); } protected function supports(string $attribute, $subject): bool { if (is_a($subject, AbstractParameter::class, true)) { //These are the allowed attributes - return in_array($attribute, ['read', 'edit', 'delete', 'create', 'show_history', 'revert_element'], true); + return in_array($attribute, self::ALLOWED_ATTRIBUTES, true); } //Allow class name as subject return false; } + + public function supportsAttribute(string $attribute): bool + { + return in_array($attribute, self::ALLOWED_ATTRIBUTES, true); + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, AbstractParameter::class, true); + } + } diff --git a/src/Security/Voter/PartAssociationVoter.php b/src/Security/Voter/PartAssociationVoter.php new file mode 100644 index 00000000..7678b67a --- /dev/null +++ b/src/Security/Voter/PartAssociationVoter.php @@ -0,0 +1,105 @@ +. + */ + +declare(strict_types=1); + +/** + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace App\Security\Voter; + +use App\Entity\Parts\PartAssociation; +use App\Services\UserSystem\VoterHelper; +use Symfony\Bundle\SecurityBundle\Security; +use App\Entity\Parts\Part; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; + +/** + * This voter handles permissions for part associations. + * The permissions are inherited from the part. + * @phpstan-extends Voter + */ +final class PartAssociationVoter extends Voter +{ + public function __construct(private readonly Security $security, private readonly VoterHelper $helper) + { + } + + protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element']; + + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool + { + if (!is_string($subject) && !$subject instanceof PartAssociation) { + throw new \RuntimeException('Invalid subject type!'); + } + + $operation = match ($attribute) { + 'read' => 'read', + 'edit', 'create', 'delete' => 'edit', + 'show_history' => 'show_history', + 'revert_element' => 'revert_element', + default => throw new \RuntimeException('Encountered unknown operation "'.$attribute.'"!'), + }; + + //If we have no part associated use the generic part permission + if (is_string($subject) || !$subject->getOwner() instanceof Part) { + return $this->helper->isGranted($token, 'parts', $operation); + } + + //Otherwise vote on the part + return $this->security->isGranted($attribute, $subject->getOwner()); + } + + protected function supports($attribute, $subject): bool + { + if (is_a($subject, PartAssociation::class, true)) { + return in_array($attribute, self::ALLOWED_PERMS, true); + } + + return false; + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, PartAssociation::class, true); + } + + public function supportsAttribute(string $attribute): bool + { + return in_array($attribute, self::ALLOWED_PERMS, true); + } +} diff --git a/src/Security/Voter/PartLotVoter.php b/src/Security/Voter/PartLotVoter.php index c9ddb89e..a64473c8 100644 --- a/src/Security/Voter/PartLotVoter.php +++ b/src/Security/Voter/PartLotVoter.php @@ -41,31 +41,31 @@ declare(strict_types=1); namespace App\Security\Voter; +use App\Services\UserSystem\VoterHelper; use Symfony\Bundle\SecurityBundle\Security; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\UserSystem\User; -use App\Services\UserSystem\PermissionManager; -use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; -class PartLotVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class PartLotVoter extends Voter { - public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, protected Security $security) + public function __construct(private readonly Security $security, private readonly VoterHelper $helper) { - parent::__construct($resolver, $entityManager); } protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element', 'withdraw', 'add', 'move']; - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { - if (! is_a($subject, PartLot::class, true)) { - throw new \RuntimeException('This voter can only handle PartLot objects!'); - } + $user = $this->helper->resolveUser($token); if (in_array($attribute, ['withdraw', 'add', 'move'], true)) { - $base_permission = $this->resolver->inherit($user, 'parts_stock', $attribute) ?? false; + $base_permission = $this->helper->isGranted($token, 'parts_stock', $attribute); $lot_permission = true; //If the lot has an owner, we need to check if the user is the owner of the lot to be allowed to withdraw it. @@ -86,7 +86,7 @@ class PartLotVoter extends ExtendedVoter //If we have no part associated use the generic part permission if (is_string($subject) || !$subject->getPart() instanceof Part) { - return $this->resolver->inherit($user, 'parts', $operation) ?? false; + return $this->helper->isGranted($token, 'parts', $operation); } //Otherwise vote on the part @@ -101,4 +101,14 @@ class PartLotVoter extends ExtendedVoter return false; } + + public function supportsAttribute(string $attribute): bool + { + return in_array($attribute, self::ALLOWED_PERMS, true); + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, PartLot::class, true); + } } diff --git a/src/Security/Voter/PartVoter.php b/src/Security/Voter/PartVoter.php index 878fc6a4..ef70b6ce 100644 --- a/src/Security/Voter/PartVoter.php +++ b/src/Security/Voter/PartVoter.php @@ -23,30 +23,48 @@ declare(strict_types=1); namespace App\Security\Voter; use App\Entity\Parts\Part; -use App\Entity\UserSystem\User; +use App\Services\UserSystem\VoterHelper; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; /** * A Voter that votes on Part entities. * * See parts permissions for valid operations. + * + * @phpstan-extends Voter */ -class PartVoter extends ExtendedVoter +final class PartVoter extends Voter { final public const READ = 'read'; + public function __construct(private readonly VoterHelper $helper) + { + } + protected function supports($attribute, $subject): bool { if (is_a($subject, Part::class, true)) { - return $this->resolver->isValidOperation('parts', $attribute); + return $this->helper->isValidOperation('parts', $attribute); } //Allow class name as subject return false; } - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { //Null concealing operator means, that no - return $this->resolver->inherit($user, 'parts', $attribute) ?? false; + return $this->helper->isGranted($token, 'parts', $attribute); + } + + public function supportsAttribute(string $attribute): bool + { + return $this->helper->isValidOperation('parts', $attribute); + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, Part::class, true); } } diff --git a/src/Security/Voter/PermissionVoter.php b/src/Security/Voter/PermissionVoter.php index 018c4f92..c6ec1b3d 100644 --- a/src/Security/Voter/PermissionVoter.php +++ b/src/Security/Voter/PermissionVoter.php @@ -22,27 +22,35 @@ declare(strict_types=1); namespace App\Security\Voter; -use App\Entity\UserSystem\User; +use App\Services\UserSystem\VoterHelper; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; /** * This voter allows you to directly check permissions from the permission structure, without passing an object. * This use the syntax like "@permission.op" * However you should use the "normal" object based voters if possible, because they are needed for a future ACL system. + * @phpstan-extends Voter */ -class PermissionVoter extends ExtendedVoter +final class PermissionVoter extends Voter { - /** - * Similar to voteOnAttribute, but checking for the anonymous user is already done. - * The current user (or the anonymous user) is passed by $user. - * - * @param string $attribute - */ - protected function voteOnUser(string $attribute, $subject, User $user): bool + public function __construct(private readonly VoterHelper $helper) + { + + } + + protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool { $attribute = ltrim($attribute, '@'); [$perm, $op] = explode('.', $attribute); - return $this->resolver->inherit($user, $perm, $op) ?? false; + return $this->helper->isGranted($token, $perm, $op); + } + + public function supportsAttribute(string $attribute): bool + { + //Check if the attribute has the form '@permission.operation' + return preg_match('#^@\\w+\\.\\w+$#', $attribute) === 1; } /** @@ -53,14 +61,14 @@ class PermissionVoter extends ExtendedVoter * * @return bool True if the attribute and subject are supported, false otherwise */ - protected function supports(string $attribute, $subject): bool + protected function supports(string $attribute, mixed $subject): bool { //Check if the attribute has the form @permission.operation if (preg_match('#^@\\w+\\.\\w+$#', $attribute)) { $attribute = ltrim($attribute, '@'); [$perm, $op] = explode('.', $attribute); - $valid = $this->resolver->isValidOperation($perm, $op); + $valid = $this->helper->isValidOperation($perm, $op); //if an invalid operation is encountered, throw an exception so the developer knows it if(!$valid) { diff --git a/src/Security/Voter/PricedetailVoter.php b/src/Security/Voter/PricedetailVoter.php index c4def709..681b73b7 100644 --- a/src/Security/Voter/PricedetailVoter.php +++ b/src/Security/Voter/PricedetailVoter.php @@ -41,29 +41,27 @@ declare(strict_types=1); namespace App\Security\Voter; +use App\Services\UserSystem\VoterHelper; use Symfony\Bundle\SecurityBundle\Security; use App\Entity\PriceInformations\Orderdetail; use App\Entity\Parts\Part; use App\Entity\PriceInformations\Pricedetail; -use App\Entity\UserSystem\User; -use App\Services\UserSystem\PermissionManager; -use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; -class PricedetailVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class PricedetailVoter extends Voter { - public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, protected Security $security) + public function __construct(private readonly Security $security, private readonly VoterHelper $helper) { - parent::__construct($resolver, $entityManager); } protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element']; - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { - if (!is_a($subject, Pricedetail::class, true)) { - throw new \RuntimeException('This voter can only handle Pricedetails objects!'); - } - $operation = match ($attribute) { 'read' => 'read', 'edit', 'create', 'delete' => 'edit', @@ -74,7 +72,7 @@ class PricedetailVoter extends ExtendedVoter //If we have no part associated use the generic part permission if (is_string($subject) || !$subject->getOrderdetail() instanceof Orderdetail || !$subject->getOrderdetail()->getPart() instanceof Part) { - return $this->resolver->inherit($user, 'parts', $operation) ?? false; + return $this->helper->isGranted($token, 'parts', $operation); } //Otherwise vote on the part @@ -89,4 +87,14 @@ class PricedetailVoter extends ExtendedVoter return false; } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, Pricedetail::class, true); + } + + public function supportsAttribute(string $attribute): bool + { + return in_array($attribute, self::ALLOWED_PERMS, true); + } } diff --git a/src/Security/Voter/StructureVoter.php b/src/Security/Voter/StructureVoter.php index 79cef811..2417b796 100644 --- a/src/Security/Voter/StructureVoter.php +++ b/src/Security/Voter/StructureVoter.php @@ -28,14 +28,19 @@ use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; -use App\Entity\UserSystem\User; -use function get_class; +use App\Services\UserSystem\VoterHelper; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; + use function is_object; -class StructureVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class StructureVoter extends Voter { protected const OBJ_PERM_MAP = [ AttachmentType::class => 'attachment_types', @@ -43,12 +48,16 @@ class StructureVoter extends ExtendedVoter Project::class => 'projects', Footprint::class => 'footprints', Manufacturer::class => 'manufacturers', - Storelocation::class => 'storelocations', + StorageLocation::class => 'storelocations', Supplier::class => 'suppliers', Currency::class => 'currencies', MeasurementUnit::class => 'measurement_units', ]; + public function __construct(private readonly VoterHelper $helper) + { + } + /** * Determines if the attribute and subject are supported by this voter. * @@ -57,25 +66,30 @@ class StructureVoter extends ExtendedVoter * * @return bool True if the attribute and subject are supported, false otherwise */ - protected function supports(string $attribute, $subject): bool + protected function supports(string $attribute, mixed $subject): bool { if (is_object($subject) || is_string($subject)) { $permission_name = $this->instanceToPermissionName($subject); //If permission name is null, then the subject is not supported - return (null !== $permission_name) && $this->resolver->isValidOperation($permission_name, $attribute); + return (null !== $permission_name) && $this->helper->isValidOperation($permission_name, $attribute); } return false; } + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || $this->instanceToPermissionName($subjectType) !== null; + } + /** * Maps an instance type to the permission name. * - * @param object|string $subject The subject for which the permission name should be generated + * @param object|string $subject The subject for which the permission name should be generated * * @return string|null the name of the permission for the subject's type or null, if the subject is not supported */ - protected function instanceToPermissionName($subject): ?string + protected function instanceToPermissionName(object|string $subject): ?string { $class_name = is_string($subject) ? $subject : $subject::class; @@ -99,10 +113,10 @@ class StructureVoter extends ExtendedVoter * * @param string $attribute */ - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { $permission_name = $this->instanceToPermissionName($subject); //Just resolve the permission - return $this->resolver->inherit($user, $permission_name, $attribute) ?? false; + return $this->helper->isGranted($token, $permission_name, $attribute); } } diff --git a/src/Security/Voter/UserVoter.php b/src/Security/Voter/UserVoter.php index e98e1701..b41c1a40 100644 --- a/src/Security/Voter/UserVoter.php +++ b/src/Security/Voter/UserVoter.php @@ -23,10 +23,22 @@ declare(strict_types=1); namespace App\Security\Voter; use App\Entity\UserSystem\User; +use App\Services\UserSystem\PermissionManager; +use App\Services\UserSystem\VoterHelper; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; + use function in_array; -class UserVoter extends ExtendedVoter +/** + * @phpstan-extends Voter + */ +final class UserVoter extends Voter { + public function __construct(private readonly VoterHelper $helper, private readonly PermissionManager $resolver) + { + } + /** * Determines if the attribute and subject are supported by this voter. * @@ -35,7 +47,7 @@ class UserVoter extends ExtendedVoter * * @return bool True if the attribute and subject are supported, false otherwise */ - protected function supports(string $attribute, $subject): bool + protected function supports(string $attribute, mixed $subject): bool { if (is_a($subject, User::class, true)) { return in_array($attribute, @@ -51,14 +63,26 @@ class UserVoter extends ExtendedVoter return false; } + public function supportsAttribute(string $attribute): bool + { + return $this->helper->isValidOperation('users', $attribute) || $this->helper->isValidOperation('self', $attribute) || $attribute === 'info'; + } + + public function supportsType(string $subjectType): bool + { + return $subjectType === 'string' || is_a($subjectType, User::class, true); + } + /** * Similar to voteOnAttribute, but checking for the anonymous user is already done. * The current user (or the anonymous user) is passed by $user. * * @param string $attribute */ - protected function voteOnUser(string $attribute, $subject, User $user): bool + protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool { + $user = $this->helper->resolveUser($token); + if ($attribute === 'info') { //Every logged-in user (non-anonymous) can see the info pages of other users if (!$user->isAnonymousUser()) { @@ -71,9 +95,9 @@ class UserVoter extends ExtendedVoter //Check if the checked user is the user itself if (($subject instanceof User) && $subject->getID() === $user->getID() && - $this->resolver->isValidOperation('self', $attribute)) { + $this->helper->isValidOperation('self', $attribute)) { //Then we also need to check the self permission - $tmp = $this->resolver->inherit($user, 'self', $attribute) ?? false; + $tmp = $this->helper->isGranted($token, 'self', $attribute); //But if the self value is not allowed then use just the user value: if ($tmp) { return $tmp; @@ -81,8 +105,8 @@ class UserVoter extends ExtendedVoter } //Else just check user permission: - if ($this->resolver->isValidOperation('users', $attribute)) { - return $this->resolver->inherit($user, 'users', $attribute) ?? false; + if ($this->helper->isValidOperation('users', $attribute)) { + return $this->helper->isGranted($token, 'users', $attribute); } return false; diff --git a/src/Serializer/APIPlatform/DetermineTypeFromElementIRIDenormalizer.php b/src/Serializer/APIPlatform/DetermineTypeFromElementIRIDenormalizer.php new file mode 100644 index 00000000..8283dbbe --- /dev/null +++ b/src/Serializer/APIPlatform/DetermineTypeFromElementIRIDenormalizer.php @@ -0,0 +1,124 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Serializer\APIPlatform; + +use ApiPlatform\Metadata\Exception\ResourceClassNotFoundException; +use ApiPlatform\Api\IriConverterInterface; +use ApiPlatform\Metadata\Operation; +use ApiPlatform\Metadata\Post; +use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; +use App\Entity\Attachments\Attachment; +use App\Entity\Parameters\AbstractParameter; +use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + +/** + * The purpose of this normalizer is to automatically add the _type discriminator field for the Attachment and AbstractParameter classes + * based on the element IRI. + * So that for a request pointing for a part element, an PartAttachment is automatically created. + * This highly improves UX and is the expected behavior. + */ +class DetermineTypeFromElementIRIDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface +{ + private const SUPPORTED_CLASSES = [ + Attachment::class, + AbstractParameter::class + ]; + + use DenormalizerAwareTrait; + + private const ALREADY_CALLED = self::class . '::ALREADY_CALLED'; + + public function __construct(private readonly IriConverterInterface $iriConverter, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataCollectionFactory) + { + } + + /** + * This functions add the _type discriminator to the input array if necessary automatically from the given element IRI. + * @param array $input + * @param Operation $operation + * @return array + * @throws ResourceClassNotFoundException + */ + private function addTypeDiscriminatorIfNecessary(array $input, Operation $operation): array + { + + //We only want to modify POST requests + if (!$operation instanceof Post) { + return $input; + } + + + //Ignore if the _type variable is already set + if (isset($input['_type'])) { + return $input; + } + + if (!isset($input['element']) || !is_string($input['element'])) { + return $input; + } + + //Retrieve the element + $element = $this->iriConverter->getResourceFromIri($input['element']); + + //Retrieve the short name of the operation + $type = $this->resourceMetadataCollectionFactory->create($element::class)->getOperation()->getShortName(); + $input['_type'] = $type; + + return $input; + } + + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): object + { + //If we are on API platform, we want to add the type discriminator if necessary + if (!isset($data['_type']) && isset($context['operation'])) { + $data = $this->addTypeDiscriminatorIfNecessary($data, $context['operation']); + } + + $context[self::ALREADY_CALLED] = true; + + return $this->denormalizer->denormalize($data, $type, $format, $context); + } + + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool + { + //Only denormalize if the _type discriminator is not set and the class is supported and we not have already called this function + return !isset($context[self::ALREADY_CALLED]) + && is_array($data) + && !isset($data['_type']) + && in_array($type, self::SUPPORTED_CLASSES, true); + } + + public function getSupportedTypes(?string $format): array + { + $tmp = []; + + foreach (self::SUPPORTED_CLASSES as $class) { + $tmp[$class] = false; + } + + return $tmp; + } +} \ No newline at end of file diff --git a/src/Serializer/APIPlatform/OverrideClassDenormalizer.php b/src/Serializer/APIPlatform/OverrideClassDenormalizer.php new file mode 100644 index 00000000..c8155abc --- /dev/null +++ b/src/Serializer/APIPlatform/OverrideClassDenormalizer.php @@ -0,0 +1,61 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Serializer\APIPlatform; + +use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; + +/** + * The idea of this denormalizer is to allow to override the type of the object created using a certain context key. + * This is required to resolve the issue of the serializer/API platform not correctly being able to determine the type + * of the "element" properties of the Attachment and Parameter subclasses. + */ +class OverrideClassDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface +{ + use DenormalizerAwareTrait; + + public const CONTEXT_KEY = '__override_type__'; + + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed + { + //Deserialize the data with the overridden type + $overrideType = $context[self::CONTEXT_KEY]; + unset($context[self::CONTEXT_KEY]); + + return $this->denormalizer->denormalize($data, $overrideType, $format, $context); + } + + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool + { + return isset($context[self::CONTEXT_KEY]); + } + + public function getSupportedTypes(?string $format): array + { + return [ + '*' => false, + ]; + } +} \ No newline at end of file diff --git a/src/Serializer/APIPlatform/SkippableItemNormalizer.php b/src/Serializer/APIPlatform/SkippableItemNormalizer.php new file mode 100644 index 00000000..5568c4cb --- /dev/null +++ b/src/Serializer/APIPlatform/SkippableItemNormalizer.php @@ -0,0 +1,90 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Serializer\APIPlatform; + +use ApiPlatform\Serializer\ItemNormalizer; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\SerializerAwareInterface; +use Symfony\Component\Serializer\SerializerInterface; + +/** + * This class decorates API Platform's ItemNormalizer to allow skipping the normalization process by setting the + * DISABLE_ITEM_NORMALIZER context key to true. This is useful for all kind of serialization operations, where the API + * Platform subsystem should not be used. + */ +#[AsDecorator("api_platform.serializer.normalizer.item")] +class SkippableItemNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface +{ + + public const DISABLE_ITEM_NORMALIZER = 'DISABLE_ITEM_NORMALIZER'; + + public function __construct(private readonly ItemNormalizer $inner) + { + + } + + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed + { + return $this->inner->denormalize($data, $type, $format, $context); + } + + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool + { + if ($context[self::DISABLE_ITEM_NORMALIZER] ?? false) { + return false; + } + + return $this->inner->supportsDenormalization($data, $type, $format, $context); + } + + public function normalize(mixed $object, ?string $format = null, array $context = []): float|int|bool|\ArrayObject|array|string|null + { + return $this->inner->normalize($object, $format, $context); + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + if ($context[self::DISABLE_ITEM_NORMALIZER] ?? false) { + return false; + } + + return $this->inner->supportsNormalization($data, $format, $context); + } + + public function setSerializer(SerializerInterface $serializer): void + { + $this->inner->setSerializer($serializer); + } + + public function getSupportedTypes(?string $format): array + { + //Don't cache results, as we check for the context + return [ + 'object' => false + ]; + } +} \ No newline at end of file diff --git a/src/Serializer/AttachmentNormalizer.php b/src/Serializer/AttachmentNormalizer.php new file mode 100644 index 00000000..bd791d04 --- /dev/null +++ b/src/Serializer/AttachmentNormalizer.php @@ -0,0 +1,84 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Serializer; + +use App\Entity\Attachments\Attachment; +use App\Services\Attachments\AttachmentURLGenerator; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; + +class AttachmentNormalizer implements NormalizerInterface, NormalizerAwareInterface +{ + + use NormalizerAwareTrait; + + private const ALREADY_CALLED = 'ATTACHMENT_NORMALIZER_ALREADY_CALLED'; + + public function __construct( + private readonly AttachmentURLGenerator $attachmentURLGenerator, + ) + { + } + + public function normalize(mixed $object, ?string $format = null, array $context = []): array|null + { + if (!$object instanceof Attachment) { + throw new \InvalidArgumentException('This normalizer only supports Attachment objects!'); + } + + //Prevent loops, by adding a flag to the context + $context[self::ALREADY_CALLED] = true; + + $data = $this->normalizer->normalize($object, $format, $context); + $data['internal_path'] = $this->attachmentURLGenerator->getInternalViewURL($object); + + //Add thumbnail url if the attachment is a picture + $data['thumbnail_url'] = $object->isPicture() ? $this->attachmentURLGenerator->getThumbnailURL($object) : null; + + //For backwards compatibility reasons + //Deprecated: Use internal_path and external_path instead + $data['media_url'] = $data['internal_path'] ?? $object->getExternalPath(); + + return $data; + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + // avoid recursion: only call once per object + if (isset($context[self::ALREADY_CALLED])) { + return false; + } + + return $data instanceof Attachment; + } + + public function getSupportedTypes(?string $format): array + { + return [ + //We depend on the context to determine if we should normalize or not + Attachment::class => false, + ]; + } +} \ No newline at end of file diff --git a/src/Serializer/BigNumberNormalizer.php b/src/Serializer/BigNumberNormalizer.php index 8bb686ee..10cedfa5 100644 --- a/src/Serializer/BigNumberNormalizer.php +++ b/src/Serializer/BigNumberNormalizer.php @@ -22,21 +22,23 @@ declare(strict_types=1); */ namespace App\Serializer; +use Brick\Math\BigDecimal; use Brick\Math\BigNumber; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** * @see \App\Tests\Serializer\BigNumberNormalizerTest */ -class BigNumberNormalizer implements NormalizerInterface +class BigNumberNormalizer implements NormalizerInterface, DenormalizerInterface { - public function supportsNormalization($data, string $format = null, array $context = []): bool + public function supportsNormalization($data, ?string $format = null, array $context = []): bool { return $data instanceof BigNumber; } - public function normalize($object, string $format = null, array $context = []): string + public function normalize($object, ?string $format = null, array $context = []): string { if (!$object instanceof BigNumber) { throw new \InvalidArgumentException('This normalizer only supports BigNumber objects!'); @@ -52,6 +54,22 @@ class BigNumberNormalizer implements NormalizerInterface { return [ BigNumber::class => true, + BigDecimal::class => true, ]; } + + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): BigNumber|null + { + if (!is_a($type, BigNumber::class, true)) { + throw new \InvalidArgumentException('This normalizer only supports BigNumber objects!'); + } + + return $type::of($data); + } + + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool + { + //data must be a string or a number (int, float, etc.) and the type must be BigNumber or BigDecimal + return (is_string($data) || is_numeric($data)) && (is_subclass_of($type, BigNumber::class)); + } } diff --git a/src/Serializer/PartNormalizer.php b/src/Serializer/PartNormalizer.php index b453a58e..9050abfc 100644 --- a/src/Serializer/PartNormalizer.php +++ b/src/Serializer/PartNormalizer.php @@ -24,25 +24,29 @@ namespace App\Serializer; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Orderdetail; use App\Entity\PriceInformations\Pricedetail; use Brick\Math\BigDecimal; -use Symfony\Component\DependencyInjection\Attribute\Autowire; -use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; +use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; /** * @see \App\Tests\Serializer\PartNormalizerTest */ -class PartNormalizer implements NormalizerInterface, DenormalizerInterface +class PartNormalizer implements NormalizerInterface, DenormalizerInterface, NormalizerAwareInterface, DenormalizerAwareInterface { + use NormalizerAwareTrait; + use DenormalizerAwareTrait; + + private const ALREADY_CALLED = 'PART_NORMALIZER_ALREADY_CALLED'; + private const DENORMALIZE_KEY_MAPPING = [ 'notes' => 'comment', 'quantity' => 'instock', @@ -55,30 +59,29 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface public function __construct( private readonly StructuralElementFromNameDenormalizer $locationDenormalizer, - #[Autowire(service: ObjectNormalizer::class)] - private readonly NormalizerInterface $normalizer, - #[Autowire(service: ObjectNormalizer::class)] - private readonly DenormalizerInterface $denormalizer, ) { } - public function supportsNormalization($data, string $format = null, array $context = []): bool + public function supportsNormalization($data, ?string $format = null, array $context = []): bool { - return $data instanceof Part; + //We only remove the type field for CSV export + return !isset($context[self::ALREADY_CALLED]) && $format === 'csv' && $data instanceof Part ; } - /** - * @return (float|mixed)[]|\ArrayObject|null|scalar - * - * @psalm-return \ArrayObject|array{total_instock: float|mixed,...}|null|scalar - */ - public function normalize($object, string $format = null, array $context = []) + public function normalize($object, ?string $format = null, array $context = []): array { if (!$object instanceof Part) { throw new \InvalidArgumentException('This normalizer only supports Part objects!'); } + $context[self::ALREADY_CALLED] = true; + + //Prevent exception in API Platform + if ($object->getID() === null) { + $context['iri'] = 'not-persisted'; + } + $data = $this->normalizer->normalize($object, $format, $context); //Remove type field for CSV export @@ -86,14 +89,19 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface unset($data['type']); } - $data['total_instock'] = $object->getAmountSum(); - return $data; } public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool { - return is_array($data) && is_a($type, Part::class, true); + //Only denormalize if we are doing a file import operation + if (!($context['partdb_import'] ?? false)) { + return false; + } + + //Only make the denormalizer available on import operations + return !isset($context[self::ALREADY_CALLED]) + && is_array($data) && is_a($type, Part::class, true); } private function normalizeKeys(array &$data): array @@ -109,7 +117,7 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface return $data; } - public function denormalize($data, string $type, string $format = null, array $context = []): ?Part + public function denormalize($data, string $type, ?string $format = null, array $context = []): ?Part { $this->normalizeKeys($data); @@ -129,6 +137,8 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface $data['minamount'] = 0.0; } + $context[self::ALREADY_CALLED] = true; + $object = $this->denormalizer->denormalize($data, $type, $format, $context); if (!$object instanceof Part) { @@ -148,7 +158,7 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface } if (isset($data['storelocation']) && $data['storelocation'] !== "") { - $location = $this->locationDenormalizer->denormalize($data['storelocation'], Storelocation::class, $format, $context); + $location = $this->locationDenormalizer->denormalize($data['storelocation'], StorageLocation::class, $format, $context); $partLot->setStorageLocation($location); } @@ -158,7 +168,7 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface if (isset($data['supplier']) && $data['supplier'] !== "") { $supplier = $this->locationDenormalizer->denormalize($data['supplier'], Supplier::class, $format, $context); - if ($supplier) { + if ($supplier !== null) { $orderdetail = new Orderdetail(); $orderdetail->setSupplier($supplier); diff --git a/src/Serializer/StructuralElementDenormalizer.php b/src/Serializer/StructuralElementDenormalizer.php index ce6f91ca..d9b03ae7 100644 --- a/src/Serializer/StructuralElementDenormalizer.php +++ b/src/Serializer/StructuralElementDenormalizer.php @@ -24,9 +24,9 @@ namespace App\Serializer; use App\Entity\Base\AbstractStructuralDBElement; use App\Repository\StructuralDBElementRepository; +use App\Serializer\APIPlatform\SkippableItemNormalizer; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; -use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; @@ -35,33 +35,66 @@ use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; /** * @see \App\Tests\Serializer\StructuralElementDenormalizerTest */ -class StructuralElementDenormalizer implements DenormalizerInterface +class StructuralElementDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface { + use DenormalizerAwareTrait; + + private const ALREADY_CALLED = 'STRUCTURAL_DENORMALIZER_ALREADY_CALLED'; + private array $object_cache = []; public function __construct( - private readonly EntityManagerInterface $entityManager, - #[Autowire(service: ObjectNormalizer::class)] - private readonly DenormalizerInterface $denormalizer) + private readonly EntityManagerInterface $entityManager) { } - public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool + public function supportsDenormalization($data, string $type, ?string $format = null, array $context = []): bool { + //Only denormalize if we are doing a file import operation + if (!($context['partdb_import'] ?? false)) { + return false; + } + + //If we already handled this object, skip it + if (isset($context[self::ALREADY_CALLED]) + && is_array($context[self::ALREADY_CALLED]) + && in_array($data, $context[self::ALREADY_CALLED], true)) { + return false; + } + return is_array($data) && is_subclass_of($type, AbstractStructuralDBElement::class) //Only denormalize if we are doing a file import operation && in_array('import', $context['groups'] ?? [], true); } - public function denormalize($data, string $type, string $format = null, array $context = []): ?AbstractStructuralDBElement + /** + * @template T of AbstractStructuralDBElement + * @param $data + * @phpstan-param class-string $type + * @param string|null $format + * @param array $context + * @return AbstractStructuralDBElement|null + * @phpstan-return T|null + */ + public function denormalize($data, string $type, ?string $format = null, array $context = []): ?AbstractStructuralDBElement { + //Do not use API Platform's denormalizer + $context[SkippableItemNormalizer::DISABLE_ITEM_NORMALIZER] = true; + + if (!isset($context[self::ALREADY_CALLED])) { + $context[self::ALREADY_CALLED] = []; + } + + $context[self::ALREADY_CALLED][] = $data; + + /** @var AbstractStructuralDBElement $deserialized_entity */ $deserialized_entity = $this->denormalizer->denormalize($data, $type, $format, $context); //Check if we already have the entity in the database (via path) - /** @var StructuralDBElementRepository $repo */ + /** @var StructuralDBElementRepository $repo */ $repo = $this->entityManager->getRepository($type); $path = $deserialized_entity->getFullPath(AbstractStructuralDBElement::PATH_DELIMITER_ARROW); diff --git a/src/Serializer/StructuralElementFromNameDenormalizer.php b/src/Serializer/StructuralElementFromNameDenormalizer.php index 4277fed4..1d7255b7 100644 --- a/src/Serializer/StructuralElementFromNameDenormalizer.php +++ b/src/Serializer/StructuralElementFromNameDenormalizer.php @@ -25,7 +25,6 @@ namespace App\Serializer; use App\Entity\Base\AbstractStructuralDBElement; use App\Repository\StructuralDBElementRepository; use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** @@ -37,8 +36,13 @@ class StructuralElementFromNameDenormalizer implements DenormalizerInterface { } - public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool + public function supportsDenormalization($data, string $type, ?string $format = null, array $context = []): bool { + //Only denormalize if we are doing a file import operation + if (!($context['partdb_import'] ?? false)) { + return false; + } + return is_string($data) && is_subclass_of($type, AbstractStructuralDBElement::class); } @@ -47,10 +51,10 @@ class StructuralElementFromNameDenormalizer implements DenormalizerInterface * @phpstan-param class-string $type * @phpstan-return T|null */ - public function denormalize($data, string $type, string $format = null, array $context = []): AbstractStructuralDBElement|null + public function denormalize($data, string $type, ?string $format = null, array $context = []): AbstractStructuralDBElement|null { //Retrieve the repository for the given type - /** @var StructuralDBElementRepository $repo */ + /** @var StructuralDBElementRepository $repo */ $repo = $this->em->getRepository($type); $path_delimiter = $context['path_delimiter'] ?? '->'; diff --git a/src/Serializer/StructuralElementNormalizer.php b/src/Serializer/StructuralElementNormalizer.php index fc64aec0..e73f69be 100644 --- a/src/Serializer/StructuralElementNormalizer.php +++ b/src/Serializer/StructuralElementNormalizer.php @@ -24,9 +24,6 @@ namespace App\Serializer; use App\Entity\Base\AbstractStructuralDBElement; use Symfony\Component\DependencyInjection\Attribute\Autowire; -use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; -use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; -use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; @@ -41,15 +38,17 @@ class StructuralElementNormalizer implements NormalizerInterface { } - public function supportsNormalization($data, string $format = null, array $context = []): bool + public function supportsNormalization($data, ?string $format = null, array $context = []): bool { + //Only normalize if we are doing a file export operation + if (!($context['partdb_export'] ?? false)) { + return false; + } + return $data instanceof AbstractStructuralDBElement; } - /** - * @return array - */ - public function normalize($object, string $format = null, array $context = []) + public function normalize($object, ?string $format = null, array $context = []): mixed { if (!$object instanceof AbstractStructuralDBElement) { throw new \InvalidArgumentException('This normalizer only supports AbstractStructural objects!'); @@ -57,6 +56,11 @@ class StructuralElementNormalizer implements NormalizerInterface $data = $this->normalizer->normalize($object, $format, $context); + //If the data is not an array, we can't do anything with it + if (!is_array($data)) { + return $data; + } + //Remove type field for CSV export if ($format === 'csv') { unset($data['type']); diff --git a/src/Services/Attachments/AttachmentManager.php b/src/Services/Attachments/AttachmentManager.php index 4429179e..1075141b 100644 --- a/src/Services/Attachments/AttachmentManager.php +++ b/src/Services/Attachments/AttachmentManager.php @@ -44,35 +44,31 @@ class AttachmentManager * * @param Attachment $attachment The attachment for which the file should be generated * - * @return SplFileInfo|null The fileinfo for the attachment file. Null, if the attachment is external or has + * @return SplFileInfo|null The fileinfo for the attachment file. Null, if the attachment is only external or has * invalid file. */ public function attachmentToFile(Attachment $attachment): ?SplFileInfo { - if ($attachment->isExternal() || !$this->isFileExisting($attachment)) { + if (!$this->isInternalFileExisting($attachment)) { return null; } - return new SplFileInfo($this->toAbsoluteFilePath($attachment)); + return new SplFileInfo($this->toAbsoluteInternalFilePath($attachment)); } /** - * Returns the absolute filepath of the attachment. Null is returned, if the attachment is externally saved, - * or is not existing. + * Returns the absolute filepath to the internal copy of the attachment. Null is returned, if the attachment is + * only externally saved, or is not existing. * * @param Attachment $attachment The attachment for which the filepath should be determined */ - public function toAbsoluteFilePath(Attachment $attachment): ?string + public function toAbsoluteInternalFilePath(Attachment $attachment): ?string { - if ($attachment->getPath() === '') { + if (!$attachment->hasInternal()){ return null; } - if ($attachment->isExternal()) { - return null; - } - - $path = $this->pathResolver->placeholderToRealPath($attachment->getPath()); + $path = $this->pathResolver->placeholderToRealPath($attachment->getInternalPath()); //realpath does not work with null as argument if (null === $path) { @@ -89,8 +85,8 @@ class AttachmentManager } /** - * Checks if the file in this attachement is existing. This works for files on the HDD, and for URLs - * (it's not checked if the ressource behind the URL is really existing, so for every external attachment true is returned). + * Checks if the file in this attachment is existing. This works for files on the HDD, and for URLs + * (it's not checked if the resource behind the URL is really existing, so for every external attachment true is returned). * * @param Attachment $attachment The attachment for which the existence should be checked * @@ -98,15 +94,23 @@ class AttachmentManager */ public function isFileExisting(Attachment $attachment): bool { - if ($attachment->getPath() === '') { - return false; - } - - if ($attachment->isExternal()) { + if($attachment->hasExternal()){ return true; } + return $this->isInternalFileExisting($attachment); + } - $absolute_path = $this->toAbsoluteFilePath($attachment); + /** + * Checks if the internal file in this attachment is existing. Returns false if the attachment doesn't have an + * internal file. + * + * @param Attachment $attachment The attachment for which the existence should be checked + * + * @return bool true if the file is existing + */ + public function isInternalFileExisting(Attachment $attachment): bool + { + $absolute_path = $this->toAbsoluteInternalFilePath($attachment); if (null === $absolute_path) { return false; @@ -117,21 +121,17 @@ class AttachmentManager /** * Returns the filesize of the attachments in bytes. - * For external attachments or not existing attachments, null is returned. + * For purely external attachments or inexistent attachments, null is returned. * * @param Attachment $attachment the filesize for which the filesize should be calculated */ public function getFileSize(Attachment $attachment): ?int { - if ($attachment->isExternal()) { + if (!$this->isInternalFileExisting($attachment)) { return null; } - if (!$this->isFileExisting($attachment)) { - return null; - } - - $tmp = filesize($this->toAbsoluteFilePath($attachment)); + $tmp = filesize($this->toAbsoluteInternalFilePath($attachment)); return false !== $tmp ? $tmp : null; } diff --git a/src/Services/Attachments/AttachmentPathResolver.php b/src/Services/Attachments/AttachmentPathResolver.php index 4e1a7149..1b52c89b 100644 --- a/src/Services/Attachments/AttachmentPathResolver.php +++ b/src/Services/Attachments/AttachmentPathResolver.php @@ -22,7 +22,6 @@ declare(strict_types=1); namespace App\Services\Attachments; -use FontLib\Table\Type\maxp; use const DIRECTORY_SEPARATOR; use Symfony\Component\Filesystem\Filesystem; @@ -116,12 +115,16 @@ class AttachmentPathResolver * Converts an relative placeholder filepath (with %MEDIA% or older %BASE%) to an absolute filepath on disk. * The directory separator is always /. Relative pathes are not realy possible (.. is striped). * - * @param string $placeholder_path the filepath with placeholder for which the real path should be determined + * @param string|null $placeholder_path the filepath with placeholder for which the real path should be determined * * @return string|null The absolute real path of the file, or null if the placeholder path is invalid */ - public function placeholderToRealPath(string $placeholder_path): ?string + public function placeholderToRealPath(?string $placeholder_path): ?string { + if (null === $placeholder_path) { + return null; + } + //The new attachments use %MEDIA% as placeholders, which is the directory set in media_directory //Older path entries are given via %BASE% which was the project root @@ -140,12 +143,12 @@ class AttachmentPathResolver } //If we have now have a placeholder left, the string is invalid: - if (preg_match('#%\w+%#', $placeholder_path)) { + if (preg_match('#%\w+%#', (string) $placeholder_path)) { return null; } //Path is invalid if path is directory traversal - if (str_contains($placeholder_path, '..')) { + if (str_contains((string) $placeholder_path, '..')) { return null; } @@ -184,7 +187,7 @@ class AttachmentPathResolver } //If the new string does not begin with a placeholder, it is invalid - if (!preg_match('#^%\w+%#', $real_path)) { + if (!preg_match('#^%\w+%#', (string) $real_path)) { return null; } diff --git a/src/Services/Attachments/AttachmentReverseSearch.php b/src/Services/Attachments/AttachmentReverseSearch.php index 5f4f86de..e05192d0 100644 --- a/src/Services/Attachments/AttachmentReverseSearch.php +++ b/src/Services/Attachments/AttachmentReverseSearch.php @@ -55,7 +55,7 @@ class AttachmentReverseSearch $repo = $this->em->getRepository(Attachment::class); return $repo->findBy([ - 'path' => [$relative_path_new, $relative_path_old], + 'internal_path' => [$relative_path_new, $relative_path_old], ]); } diff --git a/src/Services/Attachments/AttachmentSubmitHandler.php b/src/Services/Attachments/AttachmentSubmitHandler.php index b8b15907..89457cea 100644 --- a/src/Services/Attachments/AttachmentSubmitHandler.php +++ b/src/Services/Attachments/AttachmentSubmitHandler.php @@ -26,6 +26,7 @@ use App\Entity\Attachments\Attachment; use App\Entity\Attachments\AttachmentContainingDBElement; use App\Entity\Attachments\AttachmentType; use App\Entity\Attachments\AttachmentTypeAttachment; +use App\Entity\Attachments\AttachmentUpload; use App\Entity\Attachments\CategoryAttachment; use App\Entity\Attachments\CurrencyAttachment; use App\Entity\Attachments\LabelAttachment; @@ -35,18 +36,18 @@ use App\Entity\Attachments\GroupAttachment; use App\Entity\Attachments\ManufacturerAttachment; use App\Entity\Attachments\MeasurementUnitAttachment; use App\Entity\Attachments\PartAttachment; -use App\Entity\Attachments\StorelocationAttachment; +use App\Entity\Attachments\StorageLocationAttachment; use App\Entity\Attachments\SupplierAttachment; use App\Entity\Attachments\UserAttachment; use App\Exceptions\AttachmentDownloadException; +use Hshn\Base64EncodedFile\HttpFoundation\File\Base64EncodedFile; +use Hshn\Base64EncodedFile\HttpFoundation\File\UploadedBase64EncodedFile; use const DIRECTORY_SEPARATOR; -use function get_class; use InvalidArgumentException; use RuntimeException; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\Mime\MimeTypesInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -64,7 +65,7 @@ class AttachmentSubmitHandler 'htpasswd', '']; public function __construct(protected AttachmentPathResolver $pathResolver, protected bool $allow_attachments_downloads, - protected HttpClientInterface $httpClient, protected MimeTypesInterface $mimeTypes, + protected HttpClientInterface $httpClient, protected MimeTypesInterface $mimeTypes, protected readonly SVGSanitizer $SVGSanitizer, protected FileTypeFilterTools $filterTools, /** * @var string The user configured maximum upload size. This is a string like "10M" or "1G" and will be converted to */ @@ -81,7 +82,7 @@ class AttachmentSubmitHandler GroupAttachment::class => 'group', ManufacturerAttachment::class => 'manufacturer', MeasurementUnitAttachment::class => 'measurement_unit', - StorelocationAttachment::class => 'storelocation', + StorageLocationAttachment::class => 'storelocation', SupplierAttachment::class => 'supplier', UserAttachment::class => 'user', LabelAttachment::class => 'label_profile', @@ -143,19 +144,35 @@ class AttachmentSubmitHandler { $base_path = $secure_upload ? $this->pathResolver->getSecurePath() : $this->pathResolver->getMediaPath(); - //Ensure the given attachment class is known to mapping - if (!isset($this->folder_mapping[$attachment::class])) { - throw new InvalidArgumentException('The given attachment class is not known! The passed class was: '.$attachment::class); - } //Ensure the attachment has an assigned element if (!$attachment->getElement() instanceof AttachmentContainingDBElement) { throw new InvalidArgumentException('The given attachment is not assigned to an element! An element is needed to generate a path!'); } + //Determine the folder prefix for the given attachment class: + $prefix = null; + //Check if we can use the class name dire + if (isset($this->folder_mapping[$attachment::class])) { + $prefix = $this->folder_mapping[$attachment::class]; + } else { + //If not, check for instance of: + foreach ($this->folder_mapping as $class => $folder) { + if ($attachment instanceof $class) { + $prefix = $folder; + break; + } + } + } + + //Ensure the given attachment class is known to mapping + if (!$prefix) { + throw new InvalidArgumentException('The given attachment class is not known! The passed class was: '.$attachment::class); + } + //Build path return $base_path.DIRECTORY_SEPARATOR //Base path - .$this->folder_mapping[$attachment::class].DIRECTORY_SEPARATOR.$attachment->getElement()->getID(); + .$prefix.DIRECTORY_SEPARATOR.$attachment->getElement()->getID(); } /** @@ -163,38 +180,62 @@ class AttachmentSubmitHandler * This function will move the uploaded file or download the URL file to server, if needed. * * @param Attachment $attachment the attachment that should be used for handling - * @param UploadedFile|null $file If given, that file will be moved to the right location - * @param array $options The options to use with the upload. Here you can specify that a URL should be downloaded, - * or an file should be moved to a secure location. + * @param AttachmentUpload|null $upload The upload options DTO. If it is null, it will be tried to get from the attachment option * * @return Attachment The attachment with the new filename (same instance as passed $attachment) */ - public function handleFormSubmit(Attachment $attachment, ?UploadedFile $file, array $options = []): Attachment + public function handleUpload(Attachment $attachment, ?AttachmentUpload $upload): Attachment { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); + if ($upload === null) { + $upload = $attachment->getUpload(); + if ($upload === null) { + throw new InvalidArgumentException('No upload options given and no upload options set in attachment!'); + } + } + + $file = $upload->file; + + //If no file was uploaded, but we have base64 encoded data, create a file from it + if (!$file && $upload->data !== null) { + $file = new UploadedBase64EncodedFile(new Base64EncodedFile($upload->data), $upload->filename ?? 'base64'); + } + + //By default we assume a public upload + $secure_attachment = $upload->private ?? false; //When a file is given then upload it, otherwise check if we need to download the URL if ($file instanceof UploadedFile) { - $this->upload($attachment, $file, $options); - } elseif ($options['download_url'] && $attachment->isExternal()) { - $this->downloadURL($attachment, $options); + + $this->upload($attachment, $file, $secure_attachment); + } elseif ($upload->downloadUrl && $attachment->hasExternal()) { + $this->downloadURL($attachment, $secure_attachment); } //Move the attachment files to secure location (and back) if needed - $this->moveFile($attachment, $options['secure_attachment']); + $this->moveFile($attachment, $secure_attachment); + + //Sanitize the SVG if needed + $this->sanitizeSVGAttachment($attachment); //Rename blacklisted (unsecure) files to a better extension $this->renameBlacklistedExtensions($attachment); - //Check if we should assign this attachment to master picture - //this is only possible if the attachment is new (not yet persisted to DB) - if ($options['become_preview_if_empty'] && null === $attachment->getID() && $attachment->isPicture()) { - $element = $attachment->getElement(); - if ($element instanceof AttachmentContainingDBElement && !$element->getMasterPictureAttachment() instanceof Attachment) { + //Set / Unset the master picture attachment / preview image + $element = $attachment->getElement(); + if ($element instanceof AttachmentContainingDBElement) { + //Make this attachment the master picture if needed and this was requested + if ($upload->becomePreviewIfEmpty + && $element->getMasterPictureAttachment() === null //Element must not have an preview image yet + && null === $attachment->getID() //Attachment must be null + && $attachment->isPicture() //Attachment must be a picture + ) { $element->setMasterPictureAttachment($attachment); } + + //If this attachment is the master picture, but is not a picture anymore, dont use it as master picture anymore + if ($element->getMasterPictureAttachment() === $attachment && !$attachment->isPicture()) { + $element->setMasterPictureAttachment(null); + } } return $attachment; @@ -206,12 +247,12 @@ class AttachmentSubmitHandler protected function renameBlacklistedExtensions(Attachment $attachment): Attachment { //We can not do anything on builtins or external ressources - if ($attachment->isBuiltIn() || $attachment->isExternal()) { + if ($attachment->isBuiltIn() || !$attachment->hasInternal()) { return $attachment; } //Determine the old filepath - $old_path = $this->pathResolver->placeholderToRealPath($attachment->getPath()); + $old_path = $this->pathResolver->placeholderToRealPath($attachment->getInternalPath()); if ($old_path === null || $old_path === '' || !file_exists($old_path)) { return $attachment; } @@ -222,43 +263,32 @@ class AttachmentSubmitHandler //Check if the extension is blacklisted and replace the file extension with txt if needed if(in_array($ext, self::BLACKLISTED_EXTENSIONS, true)) { $new_path = $this->generateAttachmentPath($attachment, $attachment->isSecure()) - .DIRECTORY_SEPARATOR.$this->generateAttachmentFilename($attachment, 'txt'); + .DIRECTORY_SEPARATOR.$this->generateAttachmentFilename($attachment, 'txt'); //Move file to new directory $fs = new Filesystem(); $fs->rename($old_path, $new_path); //Update the attachment - $attachment->setPath($this->pathResolver->realPathToPlaceholder($new_path)); + $attachment->setInternalPath($this->pathResolver->realPathToPlaceholder($new_path)); } return $attachment; } - protected function configureOptions(OptionsResolver $resolver): void - { - $resolver->setDefaults([ - //If no preview image was set yet, the new uploaded file will become the preview image - 'become_preview_if_empty' => true, - //When a URL is given download the URL - 'download_url' => false, - 'secure_attachment' => false, - ]); - } - /** - * Move the given attachment to secure location (or back to public folder) if needed. + * Move the internal copy of the given attachment to a secure location (or back to public folder) if needed. * * @param Attachment $attachment the attachment for which the file should be moved * @param bool $secure_location this value determines, if the attachment is moved to the secure or public folder * - * @return Attachment The attachment with the updated filepath + * @return Attachment The attachment with the updated internal filepath */ protected function moveFile(Attachment $attachment, bool $secure_location): Attachment { //We can not do anything on builtins or external ressources - if ($attachment->isBuiltIn() || $attachment->isExternal()) { + if ($attachment->isBuiltIn() || !$attachment->hasInternal()) { return $attachment; } @@ -268,12 +298,12 @@ class AttachmentSubmitHandler } //Determine the old filepath - $old_path = $this->pathResolver->placeholderToRealPath($attachment->getPath()); + $old_path = $this->pathResolver->placeholderToRealPath($attachment->getInternalPath()); if (!file_exists($old_path)) { return $attachment; } - $filename = basename($old_path); + $filename = basename((string) $old_path); //If the basename is not one of the new unique on, we have to save the old filename if (!preg_match('#\w+-\w{13}\.#', $filename)) { //Save filename to attachment field @@ -292,7 +322,7 @@ class AttachmentSubmitHandler //Save info to attachment entity $new_path = $this->pathResolver->realPathToPlaceholder($new_path); - $attachment->setPath($new_path); + $attachment->setInternalPath($new_path); return $attachment; } @@ -300,27 +330,46 @@ class AttachmentSubmitHandler /** * Download the URL set in the attachment and save it on the server. * - * @param array $options The options from the handleFormSubmit function + * @param bool $secureAttachment True if the file should be moved to the secure attachment storage * - * @return Attachment The attachment with the new filepath + * @return Attachment The attachment with the downloaded copy */ - protected function downloadURL(Attachment $attachment, array $options): Attachment + protected function downloadURL(Attachment $attachment, bool $secureAttachment): Attachment { //Check if we are allowed to download files if (!$this->allow_attachments_downloads) { throw new RuntimeException('Download of attachments is not allowed!'); } - $url = $attachment->getURL(); + $url = $attachment->getExternalPath(); $fs = new Filesystem(); - $attachment_folder = $this->generateAttachmentPath($attachment, $options['secure_attachment']); + $attachment_folder = $this->generateAttachmentPath($attachment, $secureAttachment); $tmp_path = $attachment_folder.DIRECTORY_SEPARATOR.$this->generateAttachmentFilename($attachment, 'tmp'); try { - $response = $this->httpClient->request('GET', $url, [ + $opts = [ 'buffer' => false, - ]); + //Use user-agent and other headers to make the server think we are a browser + 'headers' => [ + "sec-ch-ua" => "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"", + "sec-ch-ua-mobile" => "?0", + "sec-ch-ua-platform" => "\"Windows\"", + "user-agent" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", + "sec-fetch-site" => "none", + "sec-fetch-mode" => "navigate", + ], + + ]; + $response = $this->httpClient->request('GET', $url, $opts); + //Digikey wants TLSv1.3, so try again with that if we get a 403 + if ($response->getStatusCode() === 403) { + $opts['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT; + $response = $this->httpClient->request('GET', $url, $opts); + } + # if you have these changes and downloads still fail, check if it's due to an unknown certificate. Curl by + # default uses the systems ca store and that doesn't contain all the intermediate certificates needed to + # verify the leafs if (200 !== $response->getStatusCode()) { throw new AttachmentDownloadException('Status code: '.$response->getStatusCode()); @@ -343,13 +392,15 @@ class AttachmentSubmitHandler //If a content disposition header was set try to extract the filename out of it if (isset($headers['content-disposition'])) { $tmp = []; - preg_match('/[^;\\n=]*=([\'\"])*(.*)(?(1)\1|)/', $headers['content-disposition'][0], $tmp); - $filename = $tmp[2]; + //Only use the filename if the regex matches properly + if (preg_match('/[^;\\n=]*=([\'\"])*(.*)(?(1)\1|)/', $headers['content-disposition'][0], $tmp)) { + $filename = $tmp[2]; + } } //If we don't know filename yet, try to determine it out of url if ('' === $filename) { - $filename = basename(parse_url($url, PHP_URL_PATH)); + $filename = basename(parse_url((string) $url, PHP_URL_PATH)); } //Set original file @@ -357,7 +408,7 @@ class AttachmentSubmitHandler //Check if we have an extension given $pathinfo = pathinfo($filename); - if ($pathinfo['extension'] !== '') { + if (isset($pathinfo['extension']) && $pathinfo['extension'] !== '') { $new_ext = $pathinfo['extension']; } else { //Otherwise we have to guess the extension for the new file, based on its content $new_ext = $this->mimeTypes->getExtensions($this->mimeTypes->guessMimeType($tmp_path))[0] ?? 'tmp'; @@ -370,7 +421,7 @@ class AttachmentSubmitHandler //Make our file path relative to %BASE% $new_path = $this->pathResolver->realPathToPlaceholder($new_path); //Save the path to the attachment - $attachment->setPath($new_path); + $attachment->setInternalPath($new_path); } catch (TransportExceptionInterface) { throw new AttachmentDownloadException('Transport error!'); } @@ -383,22 +434,24 @@ class AttachmentSubmitHandler * * @param Attachment $attachment The attachment in which the file should be saved * @param UploadedFile $file The file which was uploaded - * @param array $options The options from the handleFormSubmit function + * @param bool $secureAttachment True if the file should be moved to the secure attachment storage * * @return Attachment The attachment with the new filepath */ - protected function upload(Attachment $attachment, UploadedFile $file, array $options): Attachment + protected function upload(Attachment $attachment, UploadedFile $file, bool $secureAttachment): Attachment { - //Move our temporay attachment to its final location + //Move our temporary attachment to its final location $file_path = $file->move( - $this->generateAttachmentPath($attachment, $options['secure_attachment']), + $this->generateAttachmentPath($attachment, $secureAttachment), $this->generateAttachmentFilename($attachment, $file->getClientOriginalExtension()) )->getRealPath(); //Make our file path relative to %BASE% $file_path = $this->pathResolver->realPathToPlaceholder($file_path); //Save the path to the attachment - $attachment->setPath($file_path); + $attachment->setInternalPath($file_path); + //reset any external paths the attachment might have had + $attachment->setExternalPath(null); //And save original filename $attachment->setFilename($file->getClientOriginalName()); @@ -419,7 +472,7 @@ class AttachmentSubmitHandler 'g' => 1000 * 1000 * 1000, 'gi' => 1 << 30, ]; - if (ctype_digit((string) $maxSize)) { + if (ctype_digit($maxSize)) { return (int) $maxSize; } @@ -448,4 +501,32 @@ class AttachmentSubmitHandler return $this->max_upload_size_bytes; } + + /** + * Sanitizes the given SVG file, if the attachment is an internal SVG file. + * @param Attachment $attachment + * @return Attachment + */ + public function sanitizeSVGAttachment(Attachment $attachment): Attachment + { + //We can not do anything on builtins or external ressources + if ($attachment->isBuiltIn() || !$attachment->hasInternal()) { + return $attachment; + } + + //Resolve the path to the file + $path = $this->pathResolver->placeholderToRealPath($attachment->getInternalPath()); + + //Check if the file exists + if (!file_exists($path)) { + return $attachment; + } + + //Check if the file is an SVG + if ($attachment->getExtension() === "svg") { + $this->SVGSanitizer->sanitizeFile($path); + } + + return $attachment; + } } diff --git a/src/Services/Attachments/AttachmentURLGenerator.php b/src/Services/Attachments/AttachmentURLGenerator.php index afbfade3..c22cefe4 100644 --- a/src/Services/Attachments/AttachmentURLGenerator.php +++ b/src/Services/Attachments/AttachmentURLGenerator.php @@ -92,9 +92,9 @@ class AttachmentURLGenerator * Returns a URL under which the attachment file can be viewed. * @return string|null The URL or null if the attachment file is not existing */ - public function getViewURL(Attachment $attachment): ?string + public function getInternalViewURL(Attachment $attachment): ?string { - $absolute_path = $this->attachmentHelper->toAbsoluteFilePath($attachment); + $absolute_path = $this->attachmentHelper->toAbsoluteInternalFilePath($attachment); if (null === $absolute_path) { return null; } @@ -111,6 +111,7 @@ class AttachmentURLGenerator /** * Returns a URL to a thumbnail of the attachment file. + * For external files the original URL is returned. * @return string|null The URL or null if the attachment file is not existing */ public function getThumbnailURL(Attachment $attachment, string $filter_name = 'thumbnail_sm'): ?string @@ -119,11 +120,14 @@ class AttachmentURLGenerator throw new InvalidArgumentException('Thumbnail creation only works for picture attachments!'); } - if ($attachment->isExternal() && ($attachment->getURL() !== null && $attachment->getURL() !== '')) { - return $attachment->getURL(); + if (!$attachment->hasInternal()){ + if($attachment->hasExternal()) { + return $attachment->getExternalPath(); + } + return null; } - $absolute_path = $this->attachmentHelper->toAbsoluteFilePath($attachment); + $absolute_path = $this->attachmentHelper->toAbsoluteInternalFilePath($attachment); if (null === $absolute_path) { return null; } @@ -135,7 +139,10 @@ class AttachmentURLGenerator } //GD can not work with SVG, so serve it directly... - if ('svg' === $attachment->getExtension()) { + //We can not use getExtension here, because it uses the original filename and not the real extension + //Instead we use the logic, which is also used to determine if the attachment is a picture + $extension = pathinfo(parse_url($attachment->getInternalPath(), PHP_URL_PATH) ?? '', PATHINFO_EXTENSION); + if ('svg' === $extension) { return $this->assets->getUrl($asset_path); } @@ -154,7 +161,7 @@ class AttachmentURLGenerator /** * Returns a download link to the file associated with the attachment. */ - public function getDownloadURL(Attachment $attachment): string + public function getInternalDownloadURL(Attachment $attachment): string { //Redirect always to download controller, which sets the correct headers for downloading: return $this->urlGenerator->generate('attachment_download', ['id' => $attachment->getID()]); diff --git a/src/Services/Attachments/FileTypeFilterTools.php b/src/Services/Attachments/FileTypeFilterTools.php index 3380adb7..d689fda3 100644 --- a/src/Services/Attachments/FileTypeFilterTools.php +++ b/src/Services/Attachments/FileTypeFilterTools.php @@ -120,6 +120,8 @@ class FileTypeFilterTools $element = '.'.$element; } } + //Prevent weird side effects + unset($element); $elements = array_unique($elements); diff --git a/src/Services/Attachments/PartPreviewGenerator.php b/src/Services/Attachments/PartPreviewGenerator.php index 8fe1c72c..ba6e5db0 100644 --- a/src/Services/Attachments/PartPreviewGenerator.php +++ b/src/Services/Attachments/PartPreviewGenerator.php @@ -25,7 +25,7 @@ namespace App\Services\Attachments; use App\Entity\Parts\Footprint; use App\Entity\ProjectSystem\Project; use App\Entity\Parts\Category; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Manufacturer; use App\Entity\Attachments\Attachment; @@ -88,7 +88,7 @@ class PartPreviewGenerator } foreach ($part->getPartLots() as $lot) { - if ($lot->getStorageLocation() instanceof Storelocation) { + if ($lot->getStorageLocation() instanceof StorageLocation) { $attachment = $lot->getStorageLocation()->getMasterPictureAttachment(); if ($this->isAttachmentValidPicture($attachment)) { $list[] = $attachment; diff --git a/src/Services/Attachments/SVGSanitizer.php b/src/Services/Attachments/SVGSanitizer.php new file mode 100644 index 00000000..9ac5956b --- /dev/null +++ b/src/Services/Attachments/SVGSanitizer.php @@ -0,0 +1,58 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\Attachments; + +use Rhukster\DomSanitizer\DOMSanitizer; + +class SVGSanitizer +{ + + /** + * Sanitizes the given SVG string by removing any potentially harmful content (like inline scripts). + * @param string $input + * @return string + */ + public function sanitizeString(string $input): string + { + return (new DOMSanitizer(DOMSanitizer::SVG))->sanitize($input); + } + + /** + * Sanitizes the given SVG file by removing any potentially harmful content (like inline scripts). + * The sanitized content is written back to the file. + * @param string $filepath + */ + public function sanitizeFile(string $filepath): void + { + //Open the file and read the content + $content = file_get_contents($filepath); + if ($content === false) { + throw new \RuntimeException('Could not read file: ' . $filepath); + } + //Sanitize the content + $sanitizedContent = $this->sanitizeString($content); + //Write the sanitized content back to the file + file_put_contents($filepath, $sanitizedContent); + } +} \ No newline at end of file diff --git a/src/Services/Cache/ElementCacheTagGenerator.php b/src/Services/Cache/ElementCacheTagGenerator.php new file mode 100644 index 00000000..88fca09f --- /dev/null +++ b/src/Services/Cache/ElementCacheTagGenerator.php @@ -0,0 +1,69 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\Cache; + +use Doctrine\Persistence\Proxy; + +/** + * The purpose of this class is to generate cache tags for elements. + * E.g. to easily invalidate all caches for a given element type. + */ +class ElementCacheTagGenerator +{ + private array $cache = []; + + public function __construct() + { + } + + /** + * Returns a cache tag for the given element type, which can be used to invalidate all caches for this element type. + * @param string|object $element + * @return string + */ + public function getElementTypeCacheTag(string|object $element): string + { + //Ensure that the given element is a class name + if (is_object($element)) { + $element = $element::class; + } elseif (!class_exists($element)) { + //And that the class exists + throw new \InvalidArgumentException("The given class '$element' does not exist!"); + } + + //Check if the tag is already cached + if (isset($this->cache[$element])) { + return $this->cache[$element]; + } + + //If the element is a proxy, then get the real class name of the underlying object + if (is_a($element, Proxy::class, true) || str_starts_with($element, 'Proxies\\')) { + $element = get_parent_class($element); + } + + //Replace all backslashes with underscores to prevent problems with the cache and save the result + $this->cache[$element] = str_replace('\\', '_', $element); + return $this->cache[$element]; + } +} \ No newline at end of file diff --git a/src/Services/UserSystem/UserCacheKeyGenerator.php b/src/Services/Cache/UserCacheKeyGenerator.php similarity index 93% rename from src/Services/UserSystem/UserCacheKeyGenerator.php rename to src/Services/Cache/UserCacheKeyGenerator.php index f8aec6a1..ac5487a5 100644 --- a/src/Services/UserSystem/UserCacheKeyGenerator.php +++ b/src/Services/Cache/UserCacheKeyGenerator.php @@ -20,12 +20,12 @@ declare(strict_types=1); -namespace App\Services\UserSystem; +namespace App\Services\Cache; -use Symfony\Bundle\SecurityBundle\Security; -use Symfony\Component\HttpFoundation\Request; use App\Entity\UserSystem\User; use Locale; +use Symfony\Bundle\SecurityBundle\Security; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; /** @@ -60,7 +60,7 @@ class UserCacheKeyGenerator return 'user$_'.User::ID_ANONYMOUS; } - //In the most cases we can just use the username (its unique) - return 'user_'.$user->getUsername().'_'.$locale; + //Use the unique user id and the locale to generate the key + return 'user_'.$user->getID().'_'.$locale; } } diff --git a/src/Services/Misc/DBInfoHelper.php b/src/Services/Doctrine/DBInfoHelper.php similarity index 66% rename from src/Services/Misc/DBInfoHelper.php rename to src/Services/Doctrine/DBInfoHelper.php index 29440d26..160e2d89 100644 --- a/src/Services/Misc/DBInfoHelper.php +++ b/src/Services/Doctrine/DBInfoHelper.php @@ -1,4 +1,22 @@ . + */ declare(strict_types=1); @@ -20,12 +38,13 @@ declare(strict_types=1); * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -namespace App\Services\Misc; +namespace App\Services\Doctrine; -use Doctrine\DBAL\Exception; use Doctrine\DBAL\Connection; +use Doctrine\DBAL\Exception; use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\ORM\EntityManagerInterface; /** @@ -50,10 +69,14 @@ class DBInfoHelper return 'mysql'; } - if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) { + if ($this->connection->getDatabasePlatform() instanceof SQLitePlatform) { return 'sqlite'; } + if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) { + return 'postgresql'; + } + return null; } @@ -67,10 +90,14 @@ class DBInfoHelper return $this->connection->fetchOne('SELECT VERSION()'); } - if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) { + if ($this->connection->getDatabasePlatform() instanceof SQLitePlatform) { return $this->connection->fetchOne('SELECT sqlite_version()'); } + if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) { + return $this->connection->fetchOne('SELECT version()'); + } + return null; } @@ -89,7 +116,7 @@ class DBInfoHelper } } - if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) { + if ($this->connection->getDatabasePlatform() instanceof SQLitePlatform) { try { return (int) $this->connection->fetchOne('SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size();'); } catch (Exception) { @@ -97,6 +124,14 @@ class DBInfoHelper } } + if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) { + try { + return (int) $this->connection->fetchOne('SELECT pg_database_size(current_database())'); + } catch (Exception) { + return null; + } + } + return null; } @@ -105,7 +140,7 @@ class DBInfoHelper */ public function getDatabaseName(): ?string { - return $this->connection->getDatabase() ?? null; + return $this->connection->getDatabase(); } /** @@ -121,9 +156,17 @@ class DBInfoHelper } } - if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) { + if ($this->connection->getDatabasePlatform() instanceof SQLitePlatform) { return 'sqlite'; } + + if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) { + try { + return $this->connection->fetchOne('SELECT current_user'); + } catch (Exception) { + return null; + } + } return null; } diff --git a/src/Services/Doctrine/NatsortDebugHelper.php b/src/Services/Doctrine/NatsortDebugHelper.php new file mode 100644 index 00000000..fe5b77aa --- /dev/null +++ b/src/Services/Doctrine/NatsortDebugHelper.php @@ -0,0 +1,86 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\Doctrine; + +use App\Doctrine\Functions\Natsort; +use App\Entity\Parts\Part; +use Doctrine\ORM\EntityManagerInterface; + +/** + * This service allows to debug the natsort function by showing various information about the current state of + * the natsort function. + */ +class NatsortDebugHelper +{ + public function __construct(private readonly EntityManagerInterface $entityManager) + { + // This is a dummy constructor + } + + /** + * Check if the slow natural sort is allowed on the Natsort function. + * If it is not, then the request handler might need to be adjusted. + * @return bool + */ + public function isSlowNaturalSortAllowed(): bool + { + return Natsort::isSlowNaturalSortAllowed(); + } + + public function getNaturalSortMethod(): string + { + //Construct a dummy query which uses the Natsort function + $query = $this->entityManager->createQuery('SELECT natsort(1) FROM ' . Part::class . ' p'); + $sql = $query->getSQL(); + //Remove the leading SELECT and the trailing semicolon + $sql = substr($sql, 7, -1); + + //Remove AS and everything afterwards + $sql = preg_replace('/\s+AS\s+.*/', '', $sql); + + //If just 1 is returned, then we use normal (non-natural sorting) + if ($sql === '1') { + return 'Disabled'; + } + + if (str_contains( $sql, 'COLLATE numeric')) { + return 'Native (PostgreSQL)'; + } + + if (str_contains($sql, 'NATURAL_SORT_KEY')) { + return 'Native (MariaDB)'; + } + + if (str_contains($sql, 'COLLATE NATURAL_CMP')) { + return 'Emulation via PHP (SQLite)'; + } + + if (str_contains($sql, 'NatSortKey')) { + return 'Emulation via custom function (MySQL)'; + } + + + return 'Unknown ('. $sql . ')'; + } +} \ No newline at end of file diff --git a/src/Services/EDA/KiCadHelper.php b/src/Services/EDA/KiCadHelper.php new file mode 100644 index 00000000..d4cbab34 --- /dev/null +++ b/src/Services/EDA/KiCadHelper.php @@ -0,0 +1,347 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\EDA; + +use App\Entity\Parts\Category; +use App\Entity\Parts\Footprint; +use App\Entity\Parts\Part; +use App\Services\Cache\ElementCacheTagGenerator; +use App\Services\EntityURLGenerator; +use App\Services\Trees\NodesListBuilder; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Contracts\Cache\ItemInterface; +use Symfony\Contracts\Cache\TagAwareCacheInterface; +use Symfony\Contracts\Translation\TranslatorInterface; + +class KiCadHelper +{ + + public function __construct( + private readonly NodesListBuilder $nodesListBuilder, + private readonly TagAwareCacheInterface $kicadCache, + private readonly EntityManagerInterface $em, + private readonly ElementCacheTagGenerator $tagGenerator, + private readonly UrlGeneratorInterface $urlGenerator, + private readonly EntityURLGenerator $entityURLGenerator, + private readonly TranslatorInterface $translator, + /** The maximum level of the shown categories. 0 Means only the top level categories are shown. -1 means only a single one containing */ + private readonly int $category_depth, + ) { + } + + /** + * Returns an array of objects containing all categories in the database in the format required by KiCAD. + * The categories are flattened and sorted by their full path. + * Categories, which contain no parts, are filtered out. + * The result is cached for performance and invalidated on category changes. + * @return array + */ + public function getCategories(): array + { + return $this->kicadCache->get('kicad_categories_' . $this->category_depth, function (ItemInterface $item) { + //Invalidate the cache on category changes + $secure_class_name = $this->tagGenerator->getElementTypeCacheTag(Category::class); + $item->tag($secure_class_name); + + //Invalidate the cache on part changes (as the visibility depends on parts, and the parts can change) + $secure_class_name = $this->tagGenerator->getElementTypeCacheTag(Part::class); + $item->tag($secure_class_name); + + //If the category depth is smaller than 0, create only one dummy category + if ($this->category_depth < 0) { + return [ + [ + 'id' => '0', + 'name' => 'Part-DB', + ] + ]; + } + + //Otherwise just get the categories and filter them + + $categories = $this->nodesListBuilder->typeToNodesList(Category::class); + $repo = $this->em->getRepository(Category::class); + $result = []; + foreach ($categories as $category) { + //Skip invisible categories + if ($category->getEdaInfo()->getVisibility() === false) { + continue; + } + + //Skip categories with a depth greater than the configured one + if ($category->getLevel() > $this->category_depth) { + continue; + } + + //Ensure that the category contains parts + //For the last level, we need to use a recursive query, otherwise we can use a simple query + /** @var Category $category */ + $parts_count = $category->getLevel() >= $this->category_depth ? $repo->getPartsCountRecursive($category) : $repo->getPartsCount($category); + + if ($parts_count < 1) { + continue; + } + + //Check if the category should be visible + if (!$this->shouldCategoryBeVisible($category)) { + continue; + } + + //Format the category for KiCAD + $result[] = [ + 'id' => (string)$category->getId(), + 'name' => $category->getFullPath('/'), + //Show the category link as the category description, this also fixes an segfault in KiCad see issue #878 + 'description' => $this->entityURLGenerator->listPartsURL($category), + ]; + } + + return $result; + }); + } + + /** + * Returns an array of objects containing all parts for the given category in the format required by KiCAD. + * The result is cached for performance and invalidated on category or part changes. + * @param Category|null $category + * @return array + */ + public function getCategoryParts(?Category $category): array + { + return $this->kicadCache->get('kicad_category_parts_'.($category?->getID() ?? 0) . '_' . $this->category_depth, + function (ItemInterface $item) use ($category) { + $item->tag([ + $this->tagGenerator->getElementTypeCacheTag(Category::class), + $this->tagGenerator->getElementTypeCacheTag(Part::class), + //Visibility can change based on the footprint + $this->tagGenerator->getElementTypeCacheTag(Footprint::class) + ]); + + if ($this->category_depth >= 0) { + //Ensure that the category is set + if ($category === null) { + throw new NotFoundHttpException('Category must be set, if category_depth is greater than 1!'); + } + + $category_repo = $this->em->getRepository(Category::class); + if ($category->getLevel() >= $this->category_depth) { + //Get all parts for the category and its children + $parts = $category_repo->getPartsRecursive($category); + } else { + //Get only direct parts for the category (without children), as the category is not collapsed + $parts = $category_repo->getParts($category); + } + } else { + //Get all parts + $parts = $this->em->getRepository(Part::class)->findAll(); + } + + $result = []; + foreach ($parts as $part) { + //If the part is invisible, then skip it + if (!$this->shouldPartBeVisible($part)) { + continue; + } + + $result[] = [ + 'id' => (string)$part->getId(), + 'name' => $part->getName(), + 'description' => $part->getDescription(), + ]; + } + + return $result; + }); + } + + public function getKiCADPart(Part $part): array + { + $result = [ + 'id' => (string)$part->getId(), + 'name' => $part->getName(), + "symbolIdStr" => $part->getEdaInfo()->getKicadSymbol() ?? $part->getCategory()?->getEdaInfo()->getKicadSymbol() ?? "", + "exclude_from_bom" => $this->boolToKicadBool($part->getEdaInfo()->getExcludeFromBom() ?? $part->getCategory()?->getEdaInfo()->getExcludeFromBom() ?? false), + "exclude_from_board" => $this->boolToKicadBool($part->getEdaInfo()->getExcludeFromBoard() ?? $part->getCategory()?->getEdaInfo()->getExcludeFromBoard() ?? false), + "exclude_from_sim" => $this->boolToKicadBool($part->getEdaInfo()->getExcludeFromSim() ?? $part->getCategory()?->getEdaInfo()->getExcludeFromSim() ?? true), + "fields" => [] + ]; + + $result["fields"]["footprint"] = $this->createField($part->getEdaInfo()->getKicadFootprint() ?? $part->getFootprint()?->getEdaInfo()->getKicadFootprint() ?? ""); + $result["fields"]["reference"] = $this->createField($part->getEdaInfo()->getReferencePrefix() ?? $part->getCategory()?->getEdaInfo()->getReferencePrefix() ?? 'U', true); + $result["fields"]["value"] = $this->createField($part->getEdaInfo()->getValue() ?? $part->getName(), true); + $result["fields"]["keywords"] = $this->createField($part->getTags()); + + //Use the part info page as datasheet link. It must be an absolute URL. + $result["fields"]["datasheet"] = $this->createField( + $this->urlGenerator->generate( + 'part_info', + ['id' => $part->getId()], + UrlGeneratorInterface::ABSOLUTE_URL) + ); + + //Add basic fields + $result["fields"]["description"] = $this->createField($part->getDescription()); + if ($part->getCategory() !== null) { + $result["fields"]["Category"] = $this->createField($part->getCategory()->getFullPath('/')); + } + if ($part->getManufacturer() !== null) { + $result["fields"]["Manufacturer"] = $this->createField($part->getManufacturer()->getName()); + } + if ($part->getManufacturerProductNumber() !== "") { + $result['fields']["MPN"] = $this->createField($part->getManufacturerProductNumber()); + } + if ($part->getManufacturingStatus() !== null) { + $result["fields"]["Manufacturing Status"] = $this->createField( + //Always use the english translation + $this->translator->trans($part->getManufacturingStatus()->toTranslationKey(), locale: 'en') + ); + } + if ($part->getFootprint() !== null) { + $result["fields"]["Part-DB Footprint"] = $this->createField($part->getFootprint()->getName()); + } + if ($part->getPartUnit() !== null) { + $unit = $part->getPartUnit()->getName(); + if ($part->getPartUnit()->getUnit() !== "") { + $unit .= ' ('.$part->getPartUnit()->getUnit().')'; + } + $result["fields"]["Part-DB Unit"] = $this->createField($unit); + } + if ($part->getMass()) { + $result["fields"]["Mass"] = $this->createField($part->getMass() . ' g'); + } + $result["fields"]["Part-DB ID"] = $this->createField($part->getId()); + if ($part->getIpn() !== null && $part->getIpn() !== '' && $part->getIpn() !== '0') { + $result["fields"]["Part-DB IPN"] = $this->createField($part->getIpn()); + } + + + return $result; + } + + /** + * Determine if the given part should be visible for the EDA. + * @param Category $category + * @return bool + */ + private function shouldCategoryBeVisible(Category $category): bool + { + $eda_info = $category->getEdaInfo(); + + //If the category visibility is explicitly set, then use it + if ($eda_info->getVisibility() !== null) { + return $eda_info->getVisibility(); + } + + //try to check if the fields were set + if ($eda_info->getKicadSymbol() !== null + || $eda_info->getReferencePrefix() !== null) { + return true; + } + + //Check if there is any part in this category, which should be visible + $category_repo = $this->em->getRepository(Category::class); + if ($category->getLevel() >= $this->category_depth) { + //Get all parts for the category and its children + $parts = $category_repo->getPartsRecursive($category); + } else { + //Get only direct parts for the category (without children), as the category is not collapsed + $parts = $category_repo->getParts($category); + } + + foreach ($parts as $part) { + if ($this->shouldPartBeVisible($part)) { + return true; + } + } + + //Otherwise the category should be not visible + return false; + } + + /** + * Determine if the given part should be visible for the EDA. + * @param Part $part + * @return bool + */ + private function shouldPartBeVisible(Part $part): bool + { + $eda_info = $part->getEdaInfo(); + $category = $part->getCategory(); + + //If the user set a visibility, then use it + if ($eda_info->getVisibility() !== null) { + return $part->getEdaInfo()->getVisibility(); + } + + //If the part has a category, then use the category visibility if possible + if ($category && $category->getEdaInfo()->getVisibility() !== null) { + return $category->getEdaInfo()->getVisibility(); + } + + //If both are null, then we try to determine the visibility based on if fields are set + if ($eda_info->getKicadSymbol() !== null + || $eda_info->getKicadFootprint() !== null + || $eda_info->getReferencePrefix() !== null + || $eda_info->getValue() !== null) { + return true; + } + + //Check also if the fields are set for the category (if it exists) + if ($category && ( + $category->getEdaInfo()->getKicadSymbol() !== null + || $category->getEdaInfo()->getReferencePrefix() !== null + )) { + return true; + } + //And on the footprint + //Otherwise the part should be not visible + return $part->getFootprint() && $part->getFootprint()->getEdaInfo()->getKicadFootprint() !== null; + } + + /** + * Converts a boolean value to the format required by KiCAD. + * @param bool $value + * @return string + */ + private function boolToKicadBool(bool $value): string + { + return $value ? 'True' : 'False'; + } + + /** + * Creates a field array for KiCAD + * @param string|int|float $value + * @param bool $visible + * @return array + */ + private function createField(string|int|float $value, bool $visible = false): array + { + return [ + 'value' => (string)$value, + 'visible' => $this->boolToKicadBool($visible), + ]; + } +} \ No newline at end of file diff --git a/src/Services/ElementTypeNameGenerator.php b/src/Services/ElementTypeNameGenerator.php index f32677eb..14247145 100644 --- a/src/Services/ElementTypeNameGenerator.php +++ b/src/Services/ElementTypeNameGenerator.php @@ -26,8 +26,8 @@ use App\Entity\Attachments\AttachmentContainingDBElement; use App\Entity\Attachments\Attachment; use App\Entity\Attachments\AttachmentType; use App\Entity\Base\AbstractDBElement; -use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Contracts\NamedElementInterface; +use App\Entity\Parts\PartAssociation; use App\Entity\ProjectSystem\Project; use App\Entity\LabelSystem\LabelProfile; use App\Entity\Parameters\AbstractParameter; @@ -37,7 +37,7 @@ use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; use App\Entity\PriceInformations\Orderdetail; @@ -46,8 +46,6 @@ use App\Entity\ProjectSystem\ProjectBOMEntry; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; use App\Exceptions\EntityNotSupportedException; -use Doctrine\ORM\Mapping\Entity; -use function get_class; use Symfony\Contracts\Translation\TranslatorInterface; /** @@ -71,7 +69,7 @@ class ElementTypeNameGenerator MeasurementUnit::class => $this->translator->trans('measurement_unit.label'), Part::class => $this->translator->trans('part.label'), PartLot::class => $this->translator->trans('part_lot.label'), - Storelocation::class => $this->translator->trans('storelocation.label'), + StorageLocation::class => $this->translator->trans('storelocation.label'), Supplier::class => $this->translator->trans('supplier.label'), Currency::class => $this->translator->trans('currency.label'), Orderdetail::class => $this->translator->trans('orderdetail.label'), @@ -80,6 +78,7 @@ class ElementTypeNameGenerator User::class => $this->translator->trans('user.label'), AbstractParameter::class => $this->translator->trans('parameter.label'), LabelProfile::class => $this->translator->trans('label_profile.label'), + PartAssociation::class => $this->translator->trans('part_association.label'), ]; } @@ -131,7 +130,7 @@ class ElementTypeNameGenerator { $type = $this->getLocalizedTypeLabel($entity); if ($use_html) { - return ''.$type.': '.htmlspecialchars((string) $entity->getName()); + return ''.$type.': '.htmlspecialchars($entity->getName()); } return $type.': '.$entity->getName(); diff --git a/src/Services/EntityMergers/EntityMerger.php b/src/Services/EntityMergers/EntityMerger.php new file mode 100644 index 00000000..c0be84ee --- /dev/null +++ b/src/Services/EntityMergers/EntityMerger.php @@ -0,0 +1,76 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\EntityMergers; + +use App\Services\EntityMergers\Mergers\EntityMergerInterface; +use Symfony\Component\DependencyInjection\Attribute\TaggedIterator; + +/** + * This service is used to merge two entities together. + * It automatically finds the correct merger (implementing EntityMergerInterface) for the two entities if one exists. + */ +class EntityMerger +{ + public function __construct(#[TaggedIterator('app.entity_merger')] protected iterable $mergers) + { + } + + /** + * This function finds the first merger that supports merging the other entity into the target entity. + * @param object $target + * @param object $other + * @param array $context + * @return EntityMergerInterface|null + */ + public function findMergerForObject(object $target, object $other, array $context = []): ?EntityMergerInterface + { + foreach ($this->mergers as $merger) { + if ($merger->supports($target, $other, $context)) { + return $merger; + } + } + return null; + } + + /** + * This function merges the other entity into the target entity. If no merger is found an exception is thrown. + * The target entity will be modified and returned. + * @param object $target + * @param object $other + * @param array $context + * @template T of object + * @phpstan-param T $target + * @phpstan-param T $other + * @phpstan-return T + * @return object + */ + public function merge(object $target, object $other, array $context = []): object + { + $merger = $this->findMergerForObject($target, $other, $context); + if ($merger === null) { + throw new \RuntimeException('No merger found for merging '.$other::class.' into '.$target::class); + } + return $merger->merge($target, $other, $context); + } +} \ No newline at end of file diff --git a/src/Services/EntityMergers/Mergers/EntityMergerHelperTrait.php b/src/Services/EntityMergers/Mergers/EntityMergerHelperTrait.php new file mode 100644 index 00000000..64c952a9 --- /dev/null +++ b/src/Services/EntityMergers/Mergers/EntityMergerHelperTrait.php @@ -0,0 +1,358 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\EntityMergers\Mergers; + +use App\Entity\Attachments\Attachment; +use App\Entity\Attachments\AttachmentContainingDBElement; +use App\Entity\Base\AbstractNamedDBElement; +use App\Entity\Base\AbstractStructuralDBElement; +use App\Entity\Parameters\AbstractParameter; +use App\Entity\Parts\Part; +use Doctrine\Common\Collections\Collection; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +use Symfony\Contracts\Service\Attribute\Required; + +use function Symfony\Component\String\u; + +/** + * This trait provides helper methods for entity mergers. + * By default, it uses the value from the target entity, unless it not fullfills a condition. + */ +trait EntityMergerHelperTrait +{ + protected PropertyAccessorInterface $property_accessor; + + #[Required] + public function setPropertyAccessor(PropertyAccessorInterface $property_accessor): void + { + $this->property_accessor = $property_accessor; + } + + /** + * Choice the value to use from the target or the other entity by using a callback function. + * + * @param callable $callback The callback to use. The signature is: function($target_value, $other_value, $target, $other, $field). The callback should return the value to use. + * @param object $target The target entity + * @param object $other The other entity + * @param string $field The field to use + * @return object The target entity with the value set + */ + protected function useCallback(callable $callback, object $target, object $other, string $field): object + { + //Get the values from the entities + $target_value = $this->property_accessor->getValue($target, $field); + $other_value = $this->property_accessor->getValue($other, $field); + + //Call the callback, with the signature: function($target_value, $other_value, $target, $other, $field) + //The callback should return the value to use + $value = $callback($target_value, $other_value, $target, $other, $field); + + //Set the value + $this->property_accessor->setValue($target, $field, $value); + + return $target; + } + + /** + * Use the value from the other entity, if the value from the target entity is null. + * + * @param object $target The target entity + * @param object $other The other entity + * @param string $field The field to use + * @return object The target entity with the value set + */ + protected function useOtherValueIfNotNull(object $target, object $other, string $field): object + { + return $this->useCallback( + fn($target_value, $other_value) => $target_value ?? $other_value, + $target, + $other, + $field + ); + + } + + /** + * Use the value from the other entity, if the value from the target entity is empty. + * + * @param object $target The target entity + * @param object $other The other entity + * @param string $field The field to use + * @return object The target entity with the value set + */ + protected function useOtherValueIfNotEmtpy(object $target, object $other, string $field): object + { + return $this->useCallback( + fn($target_value, $other_value) => empty($target_value) ? $other_value : $target_value, + $target, + $other, + $field + ); + } + + /** + * Use the larger value from the target and the other entity for the given field. + * + * @param object $target + * @param object $other + * @param string $field + * @return object + */ + protected function useLargerValue(object $target, object $other, string $field): object + { + return $this->useCallback( + fn($target_value, $other_value) => max($target_value, $other_value), + $target, + $other, + $field + ); + } + + /** + * Use the smaller value from the target and the other entity for the given field. + * + * @param object $target + * @param object $other + * @param string $field + * @return object + */ + protected function useSmallerValue(object $target, object $other, string $field): object + { + return $this->useCallback( + fn($target_value, $other_value) => min($target_value, $other_value), + $target, + $other, + $field + ); + } + + /** + * Perform an OR operation on the boolean values from the target and the other entity for the given field. + * This effectively means that the value is true, if it is true in at least one of the entities. + * @param object $target + * @param object $other + * @param string $field + * @return object + */ + protected function useTrueValue(object $target, object $other, string $field): object + { + return $this->useCallback( + fn(bool $target_value, bool $other_value): bool => $target_value || $other_value, + $target, + $other, + $field + ); + } + + /** + * Perform a merge of comma separated lists from the target and the other entity for the given field. + * The values are merged and duplicates are removed. + * @param object $target + * @param object $other + * @param string $field + * @return object + */ + protected function mergeTags(object $target, object $other, string $field, string $separator = ','): object + { + return $this->useCallback( + function (string|null $t, string|null $o) use ($separator): string { + //Explode the strings into arrays + $t_array = explode($separator, $t ?? ''); + $o_array = explode($separator, $o ?? ''); + + //Merge the arrays and remove duplicates + $tmp = array_unique(array_merge($t_array, $o_array)); + + //Implode the array back to a string + return implode($separator, $tmp); + }, + $target, + $other, + $field + ); + } + + /** + * Merge the collections from the target and the other entity for the given field and put all items into the target collection. + * @param object $target + * @param object $other + * @param string $field + * @param callable|null $equal_fn A function, which checks if two items are equal. The signature is: function(object $target, object other): bool. + * Return true if the items are equal, false otherwise. If two items are equal, the item from the other collection is not added to the target collection. + * If null, the items are compared by (instance) identity. + * @return object + */ + protected function mergeCollections(object $target, object $other, string $field, ?callable $equal_fn = null): object + { + $target_collection = $this->property_accessor->getValue($target, $field); + $other_collection = $this->property_accessor->getValue($other, $field); + + if (!$target_collection instanceof Collection) { + throw new \InvalidArgumentException("The target field $field is not a collection"); + } + + //Clone the items from the other collection + $clones = []; + foreach ($other_collection as $item) { + //Check if the item is already in the target collection + if ($equal_fn !== null) { + foreach ($target_collection as $target_item) { + if ($equal_fn($target_item, $item)) { + continue 2; + } + } + } elseif ($target_collection->contains($item)) { + continue; + } + + $clones[] = clone $item; + } + + $tmp = array_merge($target_collection->toArray(), $clones); + + //Create a new collection with the clones and merge it into the target collection + $this->property_accessor->setValue($target, $field, $tmp); + + return $target; + } + + /** + * Merge the attachments from the target and the other entity. + * @param AttachmentContainingDBElement $target + * @param AttachmentContainingDBElement $other + * @return object + */ + protected function mergeAttachments(AttachmentContainingDBElement $target, AttachmentContainingDBElement $other): object + { + return $this->mergeCollections($target, $other, 'attachments', fn(Attachment $t, Attachment $o): bool => $t->getName() === $o->getName() + && $t->getAttachmentType() === $o->getAttachmentType() + && $t->getExternalPath() === $o->getExternalPath() + && $t->getInternalPath() === $o->getInternalPath()); + } + + /** + * Merge the parameters from the target and the other entity. + * @param AbstractStructuralDBElement|Part $target + * @param AbstractStructuralDBElement|Part $other + * @return object + */ + protected function mergeParameters(AbstractStructuralDBElement|Part $target, AbstractStructuralDBElement|Part $other): object + { + return $this->mergeCollections($target, $other, 'parameters', fn(AbstractParameter $t, AbstractParameter $o): bool => $t->getName() === $o->getName() + && $t->getSymbol() === $o->getSymbol() + && $t->getUnit() === $o->getUnit() + && $t->getValueMax() === $o->getValueMax() + && $t->getValueMin() === $o->getValueMin() + && $t->getValueTypical() === $o->getValueTypical() + && $t->getValueText() === $o->getValueText() + && $t->getGroup() === $o->getGroup()); + } + + /** + * Check if the two strings have equal content. + * This method is case-insensitive and ignores whitespace. + * @param string|\Stringable $t + * @param string|\Stringable $o + * @return bool + */ + protected function areStringsEqual(string|\Stringable $t, string|\Stringable $o): bool + { + $t_str = u($t)->trim()->folded(); + $o_str = u($o)->trim()->folded(); + + return $t_str->equalsTo($o_str); + } + + /** + * Merge the text from the target and the other entity for the given field by attaching the other text to the target text via the given separator. + * For example, if the target text is "Hello" and the other text is "World", the result is "Hello / World". + * If the text is the same in both entities, the target text is returned. + * @param object $target + * @param object $other + * @param string $field + * @param string $separator + * @return object + */ + protected function mergeTextWithSeparator(object $target, object $other, string $field, string $separator = ' / '): object + { + return $this->useCallback( + function (string $t, string $o) use ($separator): string { + //Check if the strings are equal + if ($this->areStringsEqual($t, $o)) { + return $t; + } + + //Skip empty strings + if (trim($t) === '') { + return trim($o); + } + if (trim($o) === '') { + return trim($t); + } + + return trim($t) . $separator . trim($o); + }, + $target, + $other, + $field + ); + } + + /** + * Merge two comments from the target and the other entity for the given field. + * The comments of the both entities get concated, while the second part get a headline with the name of the old part. + * @param AbstractNamedDBElement $target + * @param AbstractNamedDBElement $other + * @param string $field + * @return object + */ + protected function mergeComment(AbstractNamedDBElement $target, AbstractNamedDBElement $other, string $field = 'comment'): object + { + return $this->useCallback( + function (string $t, string $o) use ($other): string { + //Check if the strings are equal + if ($this->areStringsEqual($t, $o)) { + return $t; + } + + //Skip empty strings + if (trim($t) === '') { + return trim($o); + } + if (trim($o) === '') { + return trim($t); + } + + return sprintf("%s\n\n%s:\n%s", + trim($t), + $other->getName(), + trim($o) + ); + }, + $target, + $other, + $field + ); + } +} \ No newline at end of file diff --git a/src/Services/EntityMergers/Mergers/EntityMergerInterface.php b/src/Services/EntityMergers/Mergers/EntityMergerInterface.php new file mode 100644 index 00000000..046fc0ea --- /dev/null +++ b/src/Services/EntityMergers/Mergers/EntityMergerInterface.php @@ -0,0 +1,58 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\EntityMergers\Mergers; + + +use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; + +/** + * @template T of object + */ +#[AutoconfigureTag('app.entity_merger')] +interface EntityMergerInterface +{ + /** + * Determines if this merger supports merging the other entity into the target entity. + * @param object $target + * @phpstan-param T $target + * @param object $other + * @phpstan-param T $other + * @param array $context + * @return bool True if this merger supports merging the other entity into the target entity, false otherwise + */ + public function supports(object $target, object $other, array $context = []): bool; + + /** + * Merge the other entity into the target entity. + * The target entity will be modified and returned. + * @param object $target + * @phpstan-param T $target + * @param object $other + * @phpstan-param T $other + * @param array $context + * @phpstan-return T + * @return object + */ + public function merge(object $target, object $other, array $context = []): object; +} \ No newline at end of file diff --git a/src/Services/EntityMergers/Mergers/PartMerger.php b/src/Services/EntityMergers/Mergers/PartMerger.php new file mode 100644 index 00000000..4ce779e8 --- /dev/null +++ b/src/Services/EntityMergers/Mergers/PartMerger.php @@ -0,0 +1,186 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\EntityMergers\Mergers; + +use App\Entity\Parts\InfoProviderReference; +use App\Entity\Parts\ManufacturingStatus; +use App\Entity\Parts\Part; +use App\Entity\Parts\PartAssociation; +use App\Entity\PriceInformations\Orderdetail; + +/** + * This class merges two parts together. + * + * @implements EntityMergerInterface + * @see \App\Tests\Services\EntityMergers\Mergers\PartMergerTest + */ +class PartMerger implements EntityMergerInterface +{ + + use EntityMergerHelperTrait; + + public function supports(object $target, object $other, array $context = []): bool + { + return $target instanceof Part && $other instanceof Part; + } + + public function merge(object $target, object $other, array $context = []): Part + { + if (!$target instanceof Part || !$other instanceof Part) { + throw new \InvalidArgumentException('The target and the other entity must be instances of Part'); + } + + //Merge basic fields + $this->mergeTextWithSeparator($target, $other, 'name'); + $this->mergeTextWithSeparator($target, $other, 'description'); + $this->mergeComment($target, $other); + $this->useOtherValueIfNotEmtpy($target, $other, 'manufacturer_product_url'); + $this->useOtherValueIfNotEmtpy($target, $other, 'manufacturer_product_number'); + $this->useOtherValueIfNotEmtpy($target, $other, 'mass'); + $this->useOtherValueIfNotEmtpy($target, $other, 'ipn'); + + //Merge relations to other entities + $this->useOtherValueIfNotNull($target, $other, 'manufacturer'); + $this->useOtherValueIfNotNull($target, $other, 'footprint'); + $this->useOtherValueIfNotNull($target, $other, 'category'); + $this->useOtherValueIfNotNull($target, $other, 'partUnit'); + + //We assume that the higher value is the correct one for minimum instock + $this->useLargerValue($target, $other, 'minamount'); + + //We assume that a part needs review and is a favorite if one of the parts is + $this->useTrueValue($target, $other, 'needs_review'); + $this->useTrueValue($target, $other, 'favorite'); + + //Merge the tags using the tag merger + $this->mergeTags($target, $other, 'tags'); + + //Merge manufacturing status + $this->useCallback(function (?ManufacturingStatus $t, ?ManufacturingStatus $o): ManufacturingStatus { + //Use the other value, if the target value is not set + if ($t === ManufacturingStatus::NOT_SET || $t === null) { + return $o ?? ManufacturingStatus::NOT_SET; + } + + return $t; + }, $target, $other, 'manufacturing_status'); + + //Merge provider reference + $this->useCallback(function (InfoProviderReference $t, InfoProviderReference $o): InfoProviderReference { + if (!$t->isProviderCreated() && $o->isProviderCreated()) { + return $o; + } + return $t; + }, $target, $other, 'providerReference'); + + //Merge the collections + $this->mergeCollectionFields($target, $other, $context); + + return $target; + } + + private function comparePartAssociations(PartAssociation $t, PartAssociation $o): bool { + //We compare the translation keys, as it contains info about the type and other type info + return $t->getOther() === $o->getOther() + && $t->getTypeTranslationKey() === $o->getTypeTranslationKey(); + } + + private function mergeCollectionFields(Part $target, Part $other, array $context): void + { + /******************************************************************************** + * Merge collections + ********************************************************************************/ + + //Lots from different parts are never considered equal, so we just merge them together + $this->mergeCollections($target, $other, 'partLots'); + $this->mergeAttachments($target, $other); + $this->mergeParameters($target, $other); + + //Merge the associations + $this->mergeCollections($target, $other, 'associated_parts_as_owner', $this->comparePartAssociations(...)); + + //We have to recreate the associations towards the other part, as they are not created by the merger + foreach ($other->getAssociatedPartsAsOther() as $association) { + //Clone the association + $clone = clone $association; + //Set the target part as the other part + $clone->setOther($target); + $owner = $clone->getOwner(); + if (!$owner) { + continue; + } + //Ensure that the association is not already present + foreach ($owner->getAssociatedPartsAsOwner() as $existing_association) { + if ($this->comparePartAssociations($existing_association, $clone)) { + continue 2; + } + } + + //Add the association to the owner + $owner->addAssociatedPartsAsOwner($clone); + } + + $this->mergeCollections($target, $other, 'orderdetails', function (Orderdetail $t, Orderdetail $o) { + //First check that the orderdetails infos are equal + $tmp = $t->getSupplier() === $o->getSupplier() + && $t->getSupplierPartNr() === $o->getSupplierPartNr() + && $t->getSupplierProductUrl(false) === $o->getSupplierProductUrl(false); + + if (!$tmp) { + return false; + } + + //Check if the pricedetails are equal + $t_pricedetails = $t->getPricedetails(); + $o_pricedetails = $o->getPricedetails(); + //Ensure that both pricedetails have the same length + if (count($t_pricedetails) !== count($o_pricedetails)) { + return false; + } + + //Check if all pricedetails are equal + for ($n=0, $nMax = count($t_pricedetails); $n< $nMax; $n++) { + $t_price = $t_pricedetails->get($n); + $o_price = $o_pricedetails->get($n); + + if (!$t_price->getPrice()->isEqualTo($o_price->getPrice()) + || $t_price->getCurrency() !== $o_price->getCurrency() + || $t_price->getPriceRelatedQuantity() !== $o_price->getPriceRelatedQuantity() + || $t_price->getMinDiscountQuantity() !== $o_price->getMinDiscountQuantity() + ) { + return false; + } + } + + //If all pricedetails are equal, the orderdetails are equal + return true; + }); + //The pricedetails are not correctly assigned to the new orderdetails, so fix that + foreach ($target->getOrderdetails() as $orderdetail) { + foreach ($orderdetail->getPricedetails() as $pricedetail) { + $pricedetail->setOrderdetail($orderdetail); + } + } + } +} \ No newline at end of file diff --git a/src/Services/EntityURLGenerator.php b/src/Services/EntityURLGenerator.php index 30f56e5d..78db06f0 100644 --- a/src/Services/EntityURLGenerator.php +++ b/src/Services/EntityURLGenerator.php @@ -35,7 +35,7 @@ use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; use App\Entity\PriceInformations\Orderdetail; @@ -44,9 +44,7 @@ use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; use App\Exceptions\EntityNotSupportedException; use App\Services\Attachments\AttachmentURLGenerator; -use DateTime; use function array_key_exists; -use function get_class; use InvalidArgumentException; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -102,7 +100,7 @@ class EntityURLGenerator Project::class => 'project_edit', Supplier::class => 'supplier_edit', Manufacturer::class => 'manufacturer_edit', - Storelocation::class => 'store_location_edit', + StorageLocation::class => 'store_location_edit', Footprint::class => 'footprint_edit', User::class => 'user_edit', Currency::class => 'currency_edit', @@ -158,25 +156,34 @@ class EntityURLGenerator public function viewURL(Attachment $entity): string { - if ($entity->isExternal()) { //For external attachments, return the link to external path - return $entity->getURL() ?? throw new \RuntimeException('External attachment has no URL!'); + //If the underlying file path is invalid, null gets returned, which is not allowed here. + //We still have the chance to use an external path, if it is set. + if ($entity->hasInternal() && ($url = $this->attachmentURLGenerator->getInternalViewURL($entity)) !== null) { + return $url; } - //return $this->urlGenerator->generate('attachment_view', ['id' => $entity->getID()]); - return $this->attachmentURLGenerator->getViewURL($entity) ?? ''; + + if($entity->hasExternal()) { + return $entity->getExternalPath(); + } + + throw new \RuntimeException('Attachment has no internal nor external path!'); } public function downloadURL($entity): string { - if ($entity instanceof Attachment) { - if ($entity->isExternal()) { //For external attachments, return the link to external path - return $entity->getURL() ?? throw new \RuntimeException('External attachment has no URL!'); - } - - return $this->attachmentURLGenerator->getDownloadURL($entity); + if (!($entity instanceof Attachment)) { + throw new EntityNotSupportedException(sprintf('The given entity is not supported yet! Passed class type: %s', $entity::class)); } - //Otherwise throw an error - throw new EntityNotSupportedException(sprintf('The given entity is not supported yet! Passed class type: %s', $entity::class)); + if ($entity->hasInternal()) { + return $this->attachmentURLGenerator->getInternalDownloadURL($entity); + } + + if($entity->hasExternal()) { + return $entity->getExternalPath(); + } + + throw new \RuntimeException('Attachment has not internal or external path!'); } /** @@ -199,7 +206,7 @@ class EntityURLGenerator Project::class => 'project_info', Supplier::class => 'supplier_edit', Manufacturer::class => 'manufacturer_edit', - Storelocation::class => 'store_location_edit', + StorageLocation::class => 'store_location_edit', Footprint::class => 'footprint_edit', User::class => 'user_edit', Currency::class => 'currency_edit', @@ -214,13 +221,13 @@ class EntityURLGenerator /** * Generates an URL to a page, where this entity can be edited. * - * @param mixed $entity The entity for which the edit link should be generated + * @param AbstractDBElement $entity The entity for which the edit link should be generated * * @return string the URL to the edit page * * @throws EntityNotSupportedException If the method is not supported for the given Entity */ - public function editURL(mixed $entity): string + public function editURL(AbstractDBElement $entity): string { $map = [ Part::class => 'part_edit', @@ -229,7 +236,7 @@ class EntityURLGenerator Project::class => 'project_edit', Supplier::class => 'supplier_edit', Manufacturer::class => 'manufacturer_edit', - Storelocation::class => 'store_location_edit', + StorageLocation::class => 'store_location_edit', Footprint::class => 'footprint_edit', User::class => 'user_edit', Currency::class => 'currency_edit', @@ -244,13 +251,14 @@ class EntityURLGenerator /** * Generates an URL to a page, where a entity of this type can be created. * - * @param mixed $entity The entity for which the link should be generated + * @param AbstractDBElement|string $entity The entity (or the entity class) for which the link should be generated + * @phpstan-param AbstractDBElement|class-string $entity * * @return string the URL to the page * * @throws EntityNotSupportedException If the method is not supported for the given Entity */ - public function createURL(mixed $entity): string + public function createURL(AbstractDBElement|string $entity): string { $map = [ Part::class => 'part_new', @@ -259,7 +267,7 @@ class EntityURLGenerator Project::class => 'project_new', Supplier::class => 'supplier_new', Manufacturer::class => 'manufacturer_new', - Storelocation::class => 'store_location_new', + StorageLocation::class => 'store_location_new', Footprint::class => 'footprint_new', User::class => 'user_new', Currency::class => 'currency_new', @@ -290,7 +298,7 @@ class EntityURLGenerator Project::class => 'device_clone', Supplier::class => 'supplier_clone', Manufacturer::class => 'manufacturer_clone', - Storelocation::class => 'store_location_clone', + StorageLocation::class => 'store_location_clone', Footprint::class => 'footprint_clone', User::class => 'user_clone', Currency::class => 'currency_clone', @@ -320,7 +328,7 @@ class EntityURLGenerator Footprint::class => 'part_list_footprint', Manufacturer::class => 'part_list_manufacturer', Supplier::class => 'part_list_supplier', - Storelocation::class => 'part_list_store_location', + StorageLocation::class => 'part_list_store_location', ]; return $this->urlGenerator->generate($this->mapToController($map, $entity), ['id' => $entity->getID()]); @@ -335,7 +343,7 @@ class EntityURLGenerator Project::class => 'project_delete', Supplier::class => 'supplier_delete', Manufacturer::class => 'manufacturer_delete', - Storelocation::class => 'store_location_delete', + StorageLocation::class => 'store_location_delete', Footprint::class => 'footprint_delete', User::class => 'user_delete', Currency::class => 'currency_delete', @@ -352,21 +360,22 @@ class EntityURLGenerator * Throws an exception if the entity class is not known to the map. * * @param array $map The map that should be used for determing the controller - * @param mixed $entity The entity for which the controller name should be determined + * @param AbstractDBElement|string $entity The entity for which the controller name should be determined + * @phpstan-param AbstractDBElement|class-string $entity * * @return string The name of the controller fitting the entity class * * @throws EntityNotSupportedException */ - protected function mapToController(array $map, mixed $entity): string + protected function mapToController(array $map, string|AbstractDBElement $entity): string { - $class = $entity::class; + $class = is_string($entity) ? $entity : $entity::class; //Check if we have an direct mapping for the given class if (!array_key_exists($class, $map)) { //Check if we need to check inheritance by looping through our map foreach (array_keys($map) as $key) { - if (is_a($entity, $key)) { + if (is_a($entity, $key, true)) { return $map[$key]; } } diff --git a/src/Services/Formatters/MoneyFormatter.php b/src/Services/Formatters/MoneyFormatter.php index d49b77cf..44a49cb5 100644 --- a/src/Services/Formatters/MoneyFormatter.php +++ b/src/Services/Formatters/MoneyFormatter.php @@ -46,7 +46,7 @@ class MoneyFormatter public function format(string|float $value, ?Currency $currency = null, int $decimals = 5, bool $show_all_digits = false): string { $iso_code = $this->base_currency; - if ($currency instanceof Currency && ($currency->getIsoCode() !== null && $currency->getIsoCode() !== '')) { + if ($currency instanceof Currency && ($currency->getIsoCode() !== '')) { $iso_code = $currency->getIsoCode(); } diff --git a/src/Services/ImportExportSystem/BOMImporter.php b/src/Services/ImportExportSystem/BOMImporter.php index 89b62660..d4876445 100644 --- a/src/Services/ImportExportSystem/BOMImporter.php +++ b/src/Services/ImportExportSystem/BOMImporter.php @@ -36,12 +36,12 @@ class BOMImporter { private const MAP_KICAD_PCB_FIELDS = [ - 'ID' => 'Id', - 'Bezeichner' => 'Designator', - 'Footprint' => 'Package', - 'Stückzahl' => 'Quantity', - 'Bezeichnung' => 'Designation', - 'Anbieter und Referenz' => 'Supplier and ref', + 0 => 'Id', + 1 => 'Designator', + 2 => 'Package', + 3 => 'Quantity', + 4 => 'Designation', + 5 => 'Supplier and ref', ]; public function __construct() @@ -110,7 +110,7 @@ class BOMImporter foreach ($csv->getRecords() as $offset => $entry) { //Translate the german field names to english - $entry = array_combine(array_map(static fn($key) => self::MAP_KICAD_PCB_FIELDS[$key] ?? $key, array_keys($entry)), $entry); + $entry = $this->normalizeColumnNames($entry); //Ensure that the entry has all required fields if (!isset ($entry['Designator'])) { @@ -137,4 +137,27 @@ class BOMImporter return $bom_entries; } + + /** + * This function uses the order of the fields in the CSV files to make them locale independent. + * @param array $entry + * @return array + */ + private function normalizeColumnNames(array $entry): array + { + $out = []; + + //Map the entry order to the correct column names + foreach (array_values($entry) as $index => $field) { + if ($index > 5) { + break; + } + + //@phpstan-ignore-next-line We want to keep this check just to be safe when something changes + $new_index = self::MAP_KICAD_PCB_FIELDS[$index] ?? throw new \UnexpectedValueException('Invalid field index!'); + $out[$new_index] = $field; + } + + return $out; + } } diff --git a/src/Services/ImportExportSystem/EntityExporter.php b/src/Services/ImportExportSystem/EntityExporter.php index 50b6b7cc..c37db50c 100644 --- a/src/Services/ImportExportSystem/EntityExporter.php +++ b/src/Services/ImportExportSystem/EntityExporter.php @@ -23,8 +23,13 @@ declare(strict_types=1); namespace App\Services\ImportExportSystem; use App\Entity\Base\AbstractNamedDBElement; +use App\Entity\Base\AbstractStructuralDBElement; +use App\Helpers\FilenameSanatizer; +use App\Serializer\APIPlatform\SkippableItemNormalizer; use Symfony\Component\OptionsResolver\OptionsResolver; use InvalidArgumentException; +use Symfony\Component\Serializer\Exception\CircularReferenceException; +use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use function is_array; use ReflectionClass; use ReflectionException; @@ -95,10 +100,28 @@ class EntityExporter 'as_collection' => true, 'csv_delimiter' => $options['csv_delimiter'], 'xml_root_node_name' => 'PartDBExport', + 'partdb_export' => true, + //Skip the item normalizer, so that we dont get IRIs in the output + SkippableItemNormalizer::DISABLE_ITEM_NORMALIZER => true, + //Handle circular references + AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => $this->handleCircularReference(...), ] ); } + private function handleCircularReference(object $object, string $format, array $context): string + { + if ($object instanceof AbstractStructuralDBElement) { + return $object->getFullPath("->"); + } elseif ($object instanceof AbstractNamedDBElement) { + return $object->getName(); + } elseif ($object instanceof \Stringable) { + return $object->__toString(); + } + + throw new CircularReferenceException('Circular reference detected for object of type '.get_class($object)); + } + /** * Exports an Entity or an array of entities to multiple file formats. * @@ -165,6 +188,9 @@ class EntityExporter $filename = 'export_'.$entity_name.'_'.$level.'.'.$format; + //Sanitize the filename + $filename = FilenameSanatizer::sanitizeFilename($filename); + // Create the disposition of the file $disposition = $response->headers->makeDisposition( ResponseHeaderBag::DISPOSITION_ATTACHMENT, diff --git a/src/Services/ImportExportSystem/EntityImporter.php b/src/Services/ImportExportSystem/EntityImporter.php index 0b4e0f17..cecab12d 100644 --- a/src/Services/ImportExportSystem/EntityImporter.php +++ b/src/Services/ImportExportSystem/EntityImporter.php @@ -26,9 +26,10 @@ use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Base\AbstractStructuralDBElement; use App\Entity\Parts\Category; use App\Entity\Parts\Part; -use Composer\Semver\Constraint\Constraint; +use App\Repository\StructuralDBElementRepository; +use App\Serializer\APIPlatform\SkippableItemNormalizer; use Symfony\Component\Validator\ConstraintViolationList; -use Symplify\EasyCodingStandard\ValueObject\Option; +use Symfony\Component\Validator\ConstraintViolationListInterface; use function count; use Doctrine\ORM\EntityManagerInterface; use InvalidArgumentException; @@ -43,6 +44,12 @@ use Symfony\Component\Validator\Validator\ValidatorInterface; */ class EntityImporter { + + /** + * The encodings that are supported by the importer, and that should be autodeceted. + */ + private const ENCODINGS = ["ASCII", "UTF-8", "ISO-8859-1", "ISO-8859-15", "Windows-1252", "UTF-16", "UTF-32"]; + public function __construct(protected SerializerInterface $serializer, protected EntityManagerInterface $em, protected ValidatorInterface $validator) { } @@ -51,15 +58,22 @@ class EntityImporter * Creates many entries at once, based on a (text) list of name. * The created entities are not persisted to database yet, so you have to do it yourself. * + * @template T of AbstractNamedDBElement * @param string $lines The list of names seperated by \n * @param string $class_name The name of the class for which the entities should be created + * @phpstan-param class-string $class_name * @param AbstractStructuralDBElement|null $parent the element which will be used as parent element for new elements * @param array $errors an associative array containing all validation errors + * @param-out list $errors * - * @return AbstractStructuralDBElement[] An array containing all valid imported entities (with the type $class_name) + * @return AbstractNamedDBElement[] An array containing all valid imported entities (with the type $class_name) + * @return T[] */ public function massCreation(string $lines, string $class_name, ?AbstractStructuralDBElement $parent = null, array &$errors = []): array { + //Try to detect the text encoding of the data and convert it to UTF-8 + $lines = mb_convert_encoding($lines, 'UTF-8', mb_detect_encoding($lines, self::ENCODINGS)); + //Expand every line to a single entry: $names = explode("\n", $lines); @@ -70,6 +84,13 @@ class EntityImporter throw new InvalidArgumentException('$parent must have the same type as specified in $class_name!'); } + //Ensure that parent is already persisted. Otherwise the getNewEntityFromPath function will not work. + if ($parent !== null && $parent->getID() === null) { + throw new InvalidArgumentException('The parent must persisted to database!'); + } + + $repo = $this->em->getRepository($class_name); + $errors = []; $valid_entities = []; @@ -79,10 +100,10 @@ class EntityImporter $indentations = [0]; foreach ($names as $name) { - //Count intendation level (whitespace characters at the beginning of the line) + //Count indentation level (whitespace characters at the beginning of the line) $identSize = strlen($name)-strlen(ltrim($name)); - //If the line is intendet more than the last line, we have a new parent element + //If the line is intended more than the last line, we have a new parent element if ($identSize > end($indentations)) { $current_parent = $last_element; //Add the new indentation level to the stack @@ -99,14 +120,27 @@ class EntityImporter //Skip empty lines (StrucuralDBElements must have a name) continue; } + /** @var AbstractStructuralDBElement $entity */ - //Create new element with given name - $entity = new $class_name(); - $entity->setName($name); - //Only set the parent if the entity is a StructuralDBElement - if ($entity instanceof AbstractStructuralDBElement) { - $entity->setParent($current_parent); + //Create new element with given name. Using the function from the repository, to correctly reuse existing elements + + if ($current_parent instanceof AbstractStructuralDBElement) { + $new_path = $current_parent->getFullPath("->") . '->' . $name; + } else { + $new_path = $name; } + //We can only use the getNewEntityFromPath function, if the repository is a StructuralDBElementRepository + if ($repo instanceof StructuralDBElementRepository) { + $entities = $repo->getNewEntityFromPath($new_path); + $entity = end($entities); + if ($entity === false) { + throw new InvalidArgumentException('getNewEntityFromPath returned an empty array!'); + } + } else { //Otherwise just create a new entity + $entity = new $class_name; + $entity->setName($name); + } + //Validate entity $tmp = $this->validator->validate($entity); @@ -131,10 +165,14 @@ class EntityImporter * @param string $data The serialized data which should be imported * @param array $options The options for the import process * @param array $errors An array which will be filled with the validation errors, if any occurs during import + * @param-out array $errors * @return array An array containing all valid imported entities */ public function importString(string $data, array $options = [], array &$errors = []): array { + //Try to detect the text encoding of the data and convert it to UTF-8 + $data = mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data, self::ENCODINGS)); + $resolver = new OptionsResolver(); $this->configureOptions($resolver); $options = $resolver->resolve($options); @@ -156,6 +194,9 @@ class EntityImporter 'csv_delimiter' => $options['csv_delimiter'], 'create_unknown_datastructures' => $options['create_unknown_datastructures'], 'path_delimiter' => $options['path_delimiter'], + 'partdb_import' => true, + //Disable API Platform normalizer, as we don't want to use it here + SkippableItemNormalizer::DISABLE_ITEM_NORMALIZER => true, ]); //Ensure we have an array of entity elements. @@ -188,12 +229,21 @@ class EntityImporter //Iterate over each $entity write it to DB. foreach ($entities as $key => $entity) { + //Ensure that entity is a NamedDBElement + if (!$entity instanceof AbstractNamedDBElement) { + throw new \RuntimeException("Encountered an entity that is not a NamedDBElement!"); + } + //Validate entity $tmp = $this->validator->validate($entity); if (count($tmp) > 0) { //Log validation errors to global log. $name = $entity instanceof AbstractStructuralDBElement ? $entity->getFullPath() : $entity->getName(); + if (trim($name) === '') { + $name = 'Row ' . (string) $key; + } + $errors[$name] = [ 'violations' => $tmp, 'entity' => $entity, @@ -238,9 +288,9 @@ class EntityImporter * * @param File $file the file that should be used for importing * @param array $options options for the import process - * @param AbstractNamedDBElement[] $entities The imported entities are returned in this array + * @param-out AbstractNamedDBElement[] $entities The imported entities are returned in this array * - * @return array An associative array containing an ConstraintViolationList and the entity name as key are returned, + * @return array An associative array containing an ConstraintViolationList and the entity name as key are returned, * if an error happened during validation. When everything was successfully, the array should be empty. */ public function importFileAndPersistToDB(File $file, array $options = [], array &$entities = []): array @@ -272,8 +322,9 @@ class EntityImporter * * @param File $file the file that should be used for importing * @param array $options options for the import process + * @param-out array $errors * - * @return array an array containing the deserialized elements + * @return AbstractNamedDBElement[] an array containing the deserialized elements */ public function importFile(File $file, array $options = [], array &$errors = []): array { @@ -306,7 +357,7 @@ class EntityImporter * @param iterable $entities the list of entities that should be fixed * @param AbstractStructuralDBElement|null $parent the parent, to which the entity should be set */ - protected function correctParentEntites(iterable $entities, AbstractStructuralDBElement $parent = null): void + protected function correctParentEntites(iterable $entities, ?AbstractStructuralDBElement $parent = null): void { foreach ($entities as $entity) { /** @var AbstractStructuralDBElement $entity */ diff --git a/src/Services/ImportExportSystem/PartKeeprImporter/PKDatastructureImporter.php b/src/Services/ImportExportSystem/PartKeeprImporter/PKDatastructureImporter.php index d53566c0..1f842c23 100644 --- a/src/Services/ImportExportSystem/PartKeeprImporter/PKDatastructureImporter.php +++ b/src/Services/ImportExportSystem/PartKeeprImporter/PKDatastructureImporter.php @@ -22,27 +22,19 @@ declare(strict_types=1); */ namespace App\Services\ImportExportSystem\PartKeeprImporter; -use App\Doctrine\Purger\ResetAutoIncrementORMPurger; use App\Entity\Attachments\FootprintAttachment; use App\Entity\Attachments\ManufacturerAttachment; -use App\Entity\Attachments\StorelocationAttachment; -use App\Entity\Base\AbstractDBElement; -use App\Entity\Base\AbstractStructuralDBElement; -use App\Entity\Contracts\TimeStampableInterface; -use App\Entity\Parameters\PartParameter; +use App\Entity\Attachments\StorageLocationAttachment; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; -use App\Entity\Parts\Part; -use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadataInfo; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -use function \count; +use function count; /** * This service is used to import the datastructures (categories, manufacturers, etc.) from a PartKeepr export. @@ -263,10 +255,9 @@ class PKDatastructureImporter public function importStorelocations(array $data): int { - $count = $this->importElementsWithCategory($data, Storelocation::class, 'storagelocation'); + $count = $this->importElementsWithCategory($data, StorageLocation::class, 'storagelocation'); - //Footprints have both attachments and images - $this->importAttachments($data, 'storagelocationimage', Storelocation::class, 'footprint_id', StorelocationAttachment::class); + $this->importAttachments($data, 'storagelocationimage', StorageLocation::class, 'storageLocation_id', StorageLocationAttachment::class); return $count; } diff --git a/src/Services/ImportExportSystem/PartKeeprImporter/PKImportHelperTrait.php b/src/Services/ImportExportSystem/PartKeeprImporter/PKImportHelperTrait.php index 70237114..1e4cd3ba 100644 --- a/src/Services/ImportExportSystem/PartKeeprImporter/PKImportHelperTrait.php +++ b/src/Services/ImportExportSystem/PartKeeprImporter/PKImportHelperTrait.php @@ -30,7 +30,7 @@ use App\Entity\Base\AbstractDBElement; use App\Entity\Base\AbstractStructuralDBElement; use App\Entity\Contracts\TimeStampableInterface; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** @@ -105,7 +105,7 @@ trait PKImportHelperTrait //Next comes the filename plus extension $path .= '/'.$attachment_row['filename'].'.'.$attachment_row['extension']; - $attachment->setPath($path); + $attachment->setInternalPath($path); return $attachment; } @@ -205,14 +205,10 @@ trait PKImportHelperTrait */ protected function setIDOfEntity(AbstractDBElement $element, int|string $id): void { - if (!is_int($id) && !is_string($id)) { - throw new \InvalidArgumentException('ID must be an integer or string'); - } - $id = (int) $id; $metadata = $this->em->getClassMetadata($element::class); - $metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_NONE); + $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_NONE); $metadata->setIdGenerator(new AssignedGenerator()); $metadata->setIdentifierValues($element, ['id' => $id]); } @@ -222,10 +218,10 @@ trait PKImportHelperTrait * @return void * @throws \Exception */ - protected function setCreationDate(TimeStampableInterface $entity, ?string $datetime_str) + protected function setCreationDate(TimeStampableInterface $entity, ?string $datetime_str): void { - if ($datetime_str) { - $date = new \DateTime($datetime_str); + if ($datetime_str !== null && $datetime_str !== '' && $datetime_str !== '0000-00-00 00:00:00') { + $date = new \DateTimeImmutable($datetime_str); } else { $date = null; //Null means "now" at persist time } @@ -235,4 +231,27 @@ trait PKImportHelperTrait $property->setAccessible(true); $property->setValue($entity, $date); } + + /** + * Gets the SI prefix factor for the given prefix ID. + * Used to convert a value from the PartKeepr database to the PartDB database. + * @param array $data + * @param int $prefix_id + * @return float + */ + protected function getSIPrefixFactor(array $data, int $prefix_id): float + { + if ($prefix_id === 0) { + return 1.0; + } + + $prefixes = $data['siprefix']; + foreach ($prefixes as $prefix) { + if ((int) $prefix['id'] === $prefix_id) { + return (int)$prefix['base'] ** (int)$prefix['exponent']; + } + } + + throw new \RuntimeException(sprintf('Could not find SI prefix with ID %s', $prefix_id)); + } } diff --git a/src/Services/ImportExportSystem/PartKeeprImporter/PKOptionalImporter.php b/src/Services/ImportExportSystem/PartKeeprImporter/PKOptionalImporter.php index b8e8272e..fafde29a 100644 --- a/src/Services/ImportExportSystem/PartKeeprImporter/PKOptionalImporter.php +++ b/src/Services/ImportExportSystem/PartKeeprImporter/PKOptionalImporter.php @@ -116,7 +116,7 @@ class PKOptionalImporter //All imported users get assigned to the "PartKeepr Users" group $group_users = $this->em->find(Group::class, 3); $group = $this->em->getRepository(Group::class)->findOneBy(['name' => 'PartKeepr Users', 'parent' => $group_users]); - if (!$group) { + if ($group === null) { $group = new Group(); $group->setName('PartKeepr Users'); $group->setParent($group_users); diff --git a/src/Services/ImportExportSystem/PartKeeprImporter/PKPartImporter.php b/src/Services/ImportExportSystem/PartKeeprImporter/PKPartImporter.php index ab00ba5b..9dd67233 100644 --- a/src/Services/ImportExportSystem/PartKeeprImporter/PKPartImporter.php +++ b/src/Services/ImportExportSystem/PartKeeprImporter/PKPartImporter.php @@ -30,7 +30,7 @@ use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; use App\Entity\PriceInformations\Orderdetail; @@ -93,7 +93,7 @@ class PKPartImporter //Create a part lot to store the stock level and location $lot = new PartLot(); $lot->setAmount((float) ($part['stockLevel'] ?? 0)); - $this->setAssociationField($lot, 'storage_location', Storelocation::class, $part['storageLocation_id']); + $this->setAssociationField($lot, 'storage_location', StorageLocation::class, $part['storageLocation_id']); $entity->addPartLot($lot); //For partCondition, productionsRemarks and Status, create a custom parameter @@ -173,20 +173,20 @@ class PKPartImporter $entity->setName($name); $entity->setValueText($partparameter['stringValue'] ?? ''); - if ($partparameter['unit_id'] === null) { + if ($partparameter['unit_id'] !== null && (int) $partparameter['unit_id'] !== 0) { $entity->setUnit($this->getUnitSymbol($data, (int)$partparameter['unit_id'])); } else { $entity->setUnit(""); } - if ($partparameter['normalizedMinValue'] !== null) { - $entity->setValueMin((float) $partparameter['normalizedMinValue']); + if ($partparameter['value'] !== null) { + $entity->setValueTypical((float) $partparameter['value'] * $this->getSIPrefixFactor($data, (int) $partparameter['siPrefix_id'])); } - if ($partparameter['normalizedValue'] !== null) { - $entity->setValueTypical((float) $partparameter['normalizedValue']); + if ($partparameter['minimumValue'] !== null) { + $entity->setValueMin((float) $partparameter['minimumValue'] * $this->getSIPrefixFactor($data, (int) $partparameter['minSiPrefix_id'])); } - if ($partparameter['normalizedMaxValue'] !== null) { - $entity->setValueMax((float) $partparameter['normalizedMaxValue']); + if ($partparameter['maximumValue'] !== null) { + $entity->setValueMax((float) $partparameter['maximumValue'] * $this->getSIPrefixFactor($data, (int) $partparameter['maxSiPrefix_id'])); } $part = $this->em->find(Part::class, (int) $partparameter['part_id']); @@ -218,7 +218,7 @@ class PKPartImporter 'iso_code' => $currency_iso_code, ]); - if (!$currency) { + if ($currency === null) { $currency = new Currency(); $currency->setIsoCode($currency_iso_code); $currency->setName(Currencies::getName($currency_iso_code)); @@ -255,7 +255,7 @@ class PKPartImporter } elseif (!empty($partdistributor['orderNumber']) && !empty($partdistributor['sku'])) { $spn = $partdistributor['orderNumber'] . ' (' . $partdistributor['sku'] . ')'; } else { - $spn = 'PartKeepr Import'; + $spn = ''; } $orderdetail = $this->em->getRepository(Orderdetail::class)->findOneBy([ @@ -265,7 +265,7 @@ class PKPartImporter ]); //When no orderdetail exists, create one - if (!$orderdetail) { + if ($orderdetail === null) { $orderdetail = new Orderdetail(); $orderdetail->setSupplier($supplier); $orderdetail->setSupplierpartnr($spn); @@ -273,8 +273,8 @@ class PKPartImporter $this->em->persist($orderdetail); } - //Add the price information to the orderdetail - if (!empty($partdistributor['price'])) { + //Add the price information to the orderdetail (only if the price is not zero, as this was a placeholder in PartKeepr) + if (!empty($partdistributor['price']) && !BigDecimal::of($partdistributor['price'])->isZero()) { $pricedetail = new Pricedetail(); $orderdetail->addPricedetail($pricedetail); //Partkeepr stores the price per item, we need to convert it to the price per packaging unit diff --git a/src/Services/InfoProviderSystem/DTOs/FileDTO.php b/src/Services/InfoProviderSystem/DTOs/FileDTO.php index 516ab949..0d1db76a 100644 --- a/src/Services/InfoProviderSystem/DTOs/FileDTO.php +++ b/src/Services/InfoProviderSystem/DTOs/FileDTO.php @@ -26,17 +26,28 @@ namespace App\Services\InfoProviderSystem\DTOs; /** * This DTO represents a file that can be downloaded from a URL. * This could be a datasheet, a 3D model, a picture or similar. + * @see \App\Tests\Services\InfoProviderSystem\DTOs\FileDTOTest */ class FileDTO { + /** + * @var string The URL where to get this file + */ + public readonly string $url; + /** * @param string $url The URL where to get this file * @param string|null $name Optionally the name of this file */ public function __construct( - public readonly string $url, + string $url, public readonly ?string $name = null, - ) {} + ) { + //Find all occurrences of non URL safe characters and replace them with their URL encoded version. + //We only want to replace characters which can not have a valid meaning in a URL (what would break the URL). + //Digikey provided some wrong URLs with a ^ in them, which is not a valid URL character. (https://github.com/Part-DB/Part-DB-server/issues/521) + $this->url = preg_replace_callback('/[^a-zA-Z0-9_\-.$+!*();\/?:@=&#%]/', static fn($matches) => rawurlencode($matches[0]), $url); + } } \ No newline at end of file diff --git a/src/Services/InfoProviderSystem/DTOs/ParameterDTO.php b/src/Services/InfoProviderSystem/DTOs/ParameterDTO.php index f2a0d978..0b54d1a9 100644 --- a/src/Services/InfoProviderSystem/DTOs/ParameterDTO.php +++ b/src/Services/InfoProviderSystem/DTOs/ParameterDTO.php @@ -26,6 +26,7 @@ namespace App\Services\InfoProviderSystem\DTOs; /** * This DTO represents a parameter of a part (similar to the AbstractParameter entity). * This could be a voltage, a current, a temperature or similar. + * @see \App\Tests\Services\InfoProviderSystem\DTOs\ParameterDTOTest */ class ParameterDTO { @@ -44,7 +45,10 @@ class ParameterDTO /** * This function tries to decide on the value, if it is a numerical value (which is then stored in one of the value_*) fields) or a text value (which is stored in value_text). - * It is possible to give ranges like 1...2 here, which will be parsed as value_min: 1.0, value_max: 2.0. + * It is possible to give ranges like 1...2 (or 1~2) here, which will be parsed as value_min: 1.0, value_max: 2.0. + * + * For certain expressions (like ranges) the unit is automatically extracted from the value, if no unit is given + * @TODO Rework that, so that the difference between parseValueField and parseValueIncludingUnit is clearer or merge them * @param string $name * @param string|float $value * @param string|null $unit @@ -54,23 +58,66 @@ class ParameterDTO */ public static function parseValueField(string $name, string|float $value, ?string $unit = null, ?string $symbol = null, ?string $group = null): self { - if (is_float($value) || is_numeric($value)) { - return new self($name, value_typ: (float) $value, unit: $unit, symbol: $symbol, group: $group); + //If we encounter something like 2.5@text, then put the "@text" into text_value and continue with the number parsing + if (is_string($value) && preg_match('/^(.+)(@.+)$/', $value, $matches) === 1) { + $value = $matches[1]; + $value_text = $matches[2]; + } else { + $value_text = null; } - //Try to parse as range - if (str_contains($value, '...')) { - $parts = explode('...', $value); - if (count($parts) === 2) { + //If the value is just a number, we assume thats the typical value + if (is_float($value) || is_numeric($value)) { + return new self($name, value_text: $value_text, value_typ: (float) $value, unit: $unit, symbol: $symbol, + group: $group); + } - //Ensure that both parts are numerical - if (is_numeric($parts[0]) && is_numeric($parts[1])) { - return new self($name, value_min: (float) $parts[0], value_max: (float) $parts[1], unit: $unit, symbol: $symbol, group: $group); + //If the attribute contains ".." or "..." or a tilde we assume it is a range + if (preg_match('/(\.{2,3}|~)/', $value) === 1) { + $parts = preg_split('/\s*(\.{2,3}|~)\s*/', $value); + if (count($parts) === 2) { + //Try to extract number and unit from value (allow leading +) + if ($unit === null || trim($unit) === '') { + [$number, $unit] = self::splitIntoValueAndUnit(ltrim($parts[0], " +")) ?? [$parts[0], null]; + } else { + $number = $parts[0]; + } + + // If the second part has some extra info, we'll save that into value_text + if (!empty($unit) && preg_match('/^(.+' . preg_quote($unit, '/') . ')\s*(.+)$/', $parts[1], $matches) > 0) { + $parts[1] = $matches[1]; + $value_text2 = $matches[2]; + } else { + $value_text2 = null; + } + [$number2, $unit2] = self::splitIntoValueAndUnit(ltrim($parts[1], " +")) ?? [$parts[1], $unit]; + + //If both parts have the same unit and both values are numerical, we'll save it as range + if ($unit === $unit2 && is_numeric($number) && is_numeric($number2)) { + return new self(name: $name, value_text: $value_text2, value_min: (float) $number, + value_max: (float) $number2, unit: $unit, symbol: $symbol, group: $group); } } + //If it's a plus/minus value, we'll also treat it as a range + } elseif (str_starts_with($value, '±')) { + [$number, $unit] = self::splitIntoValueAndUnit(ltrim($value, " ±")) ?? [ltrim($value, ' ±'), $unit]; + if (is_numeric($number)) { + return new self(name: $name, value_min: -abs((float) $number), value_max: abs((float) $number), unit: $unit, symbol: $symbol, group: $group); + } } - return new self($name, value_text: $value, unit: $unit, symbol: $symbol, group: $group); + //If no unit was passed to us, try to extract it from the value + if (empty($unit)) { + [$value, $unit] = self::splitIntoValueAndUnit($value) ?? [$value, null]; + } + + //Were we successful in trying to reduce the value to a number? + if ($value_text !== null && is_numeric($value)) { + return new self($name, value_text: $value_text, value_typ: (float) $value, unit: $unit, symbol: $symbol, + group: $group); + } + + return new self($name, value_text: $value.$value_text, unit: $unit, symbol: $symbol, group: $group); } /** @@ -87,14 +134,32 @@ class ParameterDTO { //Try to extract unit from value $unit = null; - if (is_string($value) && preg_match('/^(?[0-9.]+)\s*(?[°a-zA-Z_]+\s?\w{0,4})$/u', $value, $matches)) { - $value = $matches['value']; - $unit = $matches['unit']; + if (is_string($value)) { + [$number, $unit] = self::splitIntoValueAndUnit($value) ?? [$value, null]; - return self::parseValueField(name: $name, value: $value, unit: $unit, symbol: $symbol, group: $group); + return self::parseValueField(name: $name, value: $number, unit: $unit, symbol: $symbol, group: $group); } //Otherwise we assume that no unit is given return self::parseValueField(name: $name, value: $value, unit: null, symbol: $symbol, group: $group); } -} \ No newline at end of file + + /** + * Splits the given value into a value and a unit part if possible. + * If the value is not in the expected format, null is returned. + * @param string $value The value to split + * @return array|null An array with the value and the unit part or null if the value is not in the expected format + * @phpstan-return array{0: string, 1: string}|null + */ + public static function splitIntoValueAndUnit(string $value): ?array + { + if (preg_match('/^(?-?[0-9\.]+)\s*(?[%Ωµ°℃a-z_\/]+\s?\w{0,4})$/iu', $value, $matches)) { + $value = $matches['value']; + $unit = $matches['unit']; + + return [$value, $unit]; + } + + return null; + } +} diff --git a/src/Services/InfoProviderSystem/DTOs/PriceDTO.php b/src/Services/InfoProviderSystem/DTOs/PriceDTO.php index 8c563149..f1eb28f7 100644 --- a/src/Services/InfoProviderSystem/DTOs/PriceDTO.php +++ b/src/Services/InfoProviderSystem/DTOs/PriceDTO.php @@ -41,6 +41,8 @@ class PriceDTO public readonly ?string $currency_iso_code, /** @var bool If the price includes tax */ public readonly ?bool $includes_tax = true, + /** @var float the price related quantity */ + public readonly ?float $price_related_quantity = 1.0, ) { $this->price_as_big_decimal = BigDecimal::of($this->price); @@ -54,4 +56,4 @@ class PriceDTO { return $this->price_as_big_decimal; } -} \ No newline at end of file +} diff --git a/src/Services/InfoProviderSystem/DTOs/PurchaseInfoDTO.php b/src/Services/InfoProviderSystem/DTOs/PurchaseInfoDTO.php index 6073cc5f..bcd8be43 100644 --- a/src/Services/InfoProviderSystem/DTOs/PurchaseInfoDTO.php +++ b/src/Services/InfoProviderSystem/DTOs/PurchaseInfoDTO.php @@ -25,6 +25,7 @@ namespace App\Services\InfoProviderSystem\DTOs; /** * This DTO represents a purchase information for a part (supplier name, order number and prices). + * @see \App\Tests\Services\InfoProviderSystem\DTOs\PurchaseInfoDTOTest */ class PurchaseInfoDTO { diff --git a/src/Services/InfoProviderSystem/DTOs/SearchResultDTO.php b/src/Services/InfoProviderSystem/DTOs/SearchResultDTO.php index 355041bf..28943702 100644 --- a/src/Services/InfoProviderSystem/DTOs/SearchResultDTO.php +++ b/src/Services/InfoProviderSystem/DTOs/SearchResultDTO.php @@ -27,9 +27,15 @@ use App\Entity\Parts\ManufacturingStatus; /** * This DTO represents a search result for a part. + * @see \App\Tests\Services\InfoProviderSystem\DTOs\SearchResultDTOTest */ class SearchResultDTO { + /** @var string|null An URL to a preview image */ + public readonly ?string $preview_image_url; + /** @var FileDTO|null The preview image as FileDTO object */ + public readonly ?FileDTO $preview_image_file; + public function __construct( /** @var string The provider key (e.g. "digikey") */ public readonly string $provider_key, @@ -46,7 +52,7 @@ class SearchResultDTO /** @var string|null The manufacturer part number */ public readonly ?string $mpn = null, /** @var string|null An URL to a preview image */ - public readonly ?string $preview_image_url = null, + ?string $preview_image_url = null, /** @var ManufacturingStatus|null The manufacturing status of the part */ public readonly ?ManufacturingStatus $manufacturing_status = null, /** @var string|null A link to the part on the providers page */ @@ -55,5 +61,14 @@ class SearchResultDTO public readonly ?string $footprint = null, ) { + if ($preview_image_url !== null) { + //Utilize the escaping mechanism of FileDTO to ensure that the preview image URL is correctly encoded + //See issue #521: https://github.com/Part-DB/Part-DB-server/issues/521 + $this->preview_image_file = new FileDTO($preview_image_url); + $this->preview_image_url = $this->preview_image_file->url; + } else { + $this->preview_image_file = null; + $this->preview_image_url = null; + } } } \ No newline at end of file diff --git a/src/Services/InfoProviderSystem/DTOtoEntityConverter.php b/src/Services/InfoProviderSystem/DTOtoEntityConverter.php index 881d5f20..40f69498 100644 --- a/src/Services/InfoProviderSystem/DTOtoEntityConverter.php +++ b/src/Services/InfoProviderSystem/DTOtoEntityConverter.php @@ -26,8 +26,8 @@ namespace App\Services\InfoProviderSystem; use App\Entity\Attachments\AttachmentType; use App\Entity\Attachments\PartAttachment; use App\Entity\Base\AbstractStructuralDBElement; -use App\Entity\Parameters\AbstractParameter; use App\Entity\Parameters\PartParameter; +use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\InfoProviderReference; use App\Entity\Parts\Manufacturer; @@ -37,16 +37,17 @@ use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; use App\Entity\PriceInformations\Orderdetail; use App\Entity\PriceInformations\Pricedetail; +use App\Repository\Parts\CategoryRepository; use App\Services\InfoProviderSystem\DTOs\FileDTO; use App\Services\InfoProviderSystem\DTOs\ParameterDTO; use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; use App\Services\InfoProviderSystem\DTOs\PriceDTO; use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; -use Brick\Math\BigDecimal; use Doctrine\ORM\EntityManagerInterface; /** * This class converts DTOs to entities which can be persisted in the DB + * @see \App\Tests\Services\InfoProviderSystem\DTOtoEntityConverterTest */ final class DTOtoEntityConverter { @@ -87,6 +88,7 @@ final class DTOtoEntityConverter { $entity->setMinDiscountQuantity($dto->minimum_discount_amount); $entity->setPrice($dto->getPriceAsBigDecimal()); + $entity->setPriceRelatedQuantity($dto->price_related_quantity); //Currency TODO if ($dto->currency_iso_code !== null) { @@ -95,7 +97,6 @@ final class DTOtoEntityConverter $entity->setCurrency(null); } - return $entity; } @@ -129,7 +130,7 @@ final class DTOtoEntityConverter $entity->setAttachmentType($type); //If no name is given, try to extract the name from the URL - if (empty($dto->name)) { + if ($dto->name === null || $dto->name === '' || $dto->name === '0') { $entity->setName($this->getAttachmentNameFromURL($dto->url)); } else { $entity->setName($dto->name); @@ -157,6 +158,12 @@ final class DTOtoEntityConverter $entity->setMass($dto->mass); + //Try to map the category to an existing entity (but never create a new one) + if ($dto->category) { + //@phpstan-ignore-next-line For some reason php does not recognize the repo returns a category + $entity->setCategory($this->em->getRepository(Category::class)->findForInfoProvider($dto->category)); + } + $entity->setManufacturer($this->getOrCreateEntity(Manufacturer::class, $dto->manufacturer)); $entity->setFootprint($this->getOrCreateEntity(Footprint::class, $dto->footprint)); @@ -167,9 +174,21 @@ final class DTOtoEntityConverter //Set the provider reference on the part $entity->setProviderReference(InfoProviderReference::fromPartDTO($dto)); + $param_groups = []; + //Add parameters foreach ($dto->parameters ?? [] as $parameter) { - $entity->addParameter($this->convertParameter($parameter)); + $new_param = $this->convertParameter($parameter); + + $key = $new_param->getName() . '##' . $new_param->getGroup(); + //If there is already an parameter with the same name and group, rename the new parameter, by suffixing a number + if (count($param_groups[$key] ?? []) > 0) { + $new_param->setName($new_param->getName() . ' (' . (count($param_groups[$key]) + 1) . ')'); + } + + $param_groups[$key][] = $new_param; + + $entity->addParameter($new_param); } //Add preview image @@ -185,21 +204,39 @@ final class DTOtoEntityConverter $entity->setMasterPictureAttachment($preview_image); } + $attachments_grouped = []; + //Add other images - foreach ($dto->images ?? [] as $image) { + $images = $this->files_unique($dto->images ?? []); + foreach ($images as $image) { //Ensure that the image is not the same as the preview image if ($image->url === $dto->preview_image_url) { continue; } - $entity->addAttachment($this->convertFile($image, $image_type)); - } + $attachment = $this->convertFile($image, $image_type); + $attachments_grouped[$attachment->getName()][] = $attachment; + if (count($attachments_grouped[$attachment->getName()] ?? []) > 1) { + $attachment->setName($attachment->getName() . ' (' . (count($attachments_grouped[$attachment->getName()]) + 1) . ')'); + } + + + $entity->addAttachment($attachment); + } //Add datasheets $datasheet_type = $this->getDatasheetType(); - foreach ($dto->datasheets ?? [] as $datasheet) { - $entity->addAttachment($this->convertFile($datasheet, $datasheet_type)); + $datasheets = $this->files_unique($dto->datasheets ?? []); + foreach ($datasheets as $datasheet) { + $attachment = $this->convertFile($datasheet, $datasheet_type); + + $attachments_grouped[$attachment->getName()][] = $attachment; + if (count($attachments_grouped[$attachment->getName()] ?? []) > 1) { + $attachment->setName($attachment->getName() . ' (' . (count($attachments_grouped[$attachment->getName()])) . ')'); + } + + $entity->addAttachment($attachment); } //Add orderdetails and prices @@ -210,6 +247,27 @@ final class DTOtoEntityConverter return $entity; } + /** + * Returns the given array of files with all duplicates removed. + * @param FileDTO[] $files + * @return FileDTO[] + */ + private function files_unique(array $files): array + { + $unique = []; + //We use the URL and name as unique identifier. If two file DTO have the same URL and name, they are considered equal + //and get filtered out, if it already exists in the array + foreach ($files as $file) { + //Skip already existing files, to preserve the order. The second condition ensure that we keep the version with a name over the one without a name + if (isset($unique[$file->url]) && $unique[$file->url]->name !== null) { + continue; + } + $unique[$file->url] = $file; + } + + return array_values($unique); + } + /** * Get the existing entity of the given class with the given name or create it if it does not exist. * If the name is null, null is returned. @@ -289,7 +347,7 @@ final class DTOtoEntityConverter //If the entity was newly created, set the file filter if ($tmp->getID() === null) { $tmp->setFiletypeFilter('image/*'); - $tmp->setAlternativeNames(self::TYPE_DATASHEETS_NAME); + $tmp->setAlternativeNames(self::TYPE_IMAGE_NAME); } return $tmp; diff --git a/src/Services/InfoProviderSystem/ExistingPartFinder.php b/src/Services/InfoProviderSystem/ExistingPartFinder.php new file mode 100644 index 00000000..762c1517 --- /dev/null +++ b/src/Services/InfoProviderSystem/ExistingPartFinder.php @@ -0,0 +1,77 @@ +findAllExisting($dto); + return count($results) > 0 ? $results[0] : null; + } + + /** + * Returns all existing local parts that match the search result. + * If no part is found, return an empty array. + * @param SearchResultDTO $dto + * @return Part[] + */ + public function findAllExisting(SearchResultDTO $dto): array + { + $qb = $this->em->getRepository(Part::class)->createQueryBuilder('part'); + $qb->select('part') + ->leftJoin('part.manufacturer', 'manufacturer') + ->Orwhere($qb->expr()->andX( + 'part.providerReference.provider_key = :providerKey', + 'part.providerReference.provider_id = :providerId', + )) + + //Or the manufacturer (allowing for alternative names) and the MPN (or part name) must match + ->OrWhere( + $qb->expr()->andX( + $qb->expr()->orX( + "ILIKE(manufacturer.name, :manufacturerName) = TRUE", + "ILIKE(manufacturer.alternative_names, :manufacturerAltNames) = TRUE", + ), + $qb->expr()->orX( + "ILIKE(part.manufacturer_product_number, :mpn) = TRUE", + "ILIKE(part.name, :mpn) = TRUE", + ) + ) + ) + ; + + $qb->setParameter('providerKey', $dto->provider_key); + $qb->setParameter('providerId', $dto->provider_id); + + $qb->setParameter('manufacturerName', $dto->manufacturer); + $qb->setParameter('manufacturerAltNames', '%'.$dto->manufacturer.'%'); + $qb->setParameter('mpn', $dto->mpn); + + return $qb->getQuery()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/InfoProviderSystem/PartInfoRetriever.php b/src/Services/InfoProviderSystem/PartInfoRetriever.php index 1a31b197..0eb74642 100644 --- a/src/Services/InfoProviderSystem/PartInfoRetriever.php +++ b/src/Services/InfoProviderSystem/PartInfoRetriever.php @@ -27,6 +27,7 @@ use App\Entity\Parts\Part; use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; use App\Services\InfoProviderSystem\Providers\InfoProviderInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; @@ -34,10 +35,12 @@ final class PartInfoRetriever { private const CACHE_DETAIL_EXPIRATION = 60 * 60 * 24 * 4; // 4 days - private const CACHE_RESULT_EXPIRATION = 60 * 60 * 24 * 7; // 7 days + private const CACHE_RESULT_EXPIRATION = 60 * 60 * 24 * 4; // 7 days public function __construct(private readonly ProviderRegistry $provider_registry, - private readonly DTOtoEntityConverter $dto_to_entity_converter, private readonly CacheInterface $partInfoCache) + private readonly DTOtoEntityConverter $dto_to_entity_converter, private readonly CacheInterface $partInfoCache, + #[Autowire(param: "kernel.debug")] + private readonly bool $debugMode = false) { } @@ -56,6 +59,11 @@ final class PartInfoRetriever $provider = $this->provider_registry->getProviderByKey($provider); } + //Ensure that the provider is active + if (!$provider->isActive()) { + throw new \RuntimeException("The provider with key {$provider->getProviderKey()} is not active!"); + } + if (!$provider instanceof InfoProviderInterface) { throw new \InvalidArgumentException("The provider must be either a provider key or a provider instance!"); } @@ -77,7 +85,7 @@ final class PartInfoRetriever $escaped_keyword = urlencode($keyword); return $this->partInfoCache->get("search_{$provider->getProviderKey()}_{$escaped_keyword}", function (ItemInterface $item) use ($provider, $keyword) { //Set the expiration time - $item->expiresAfter(self::CACHE_RESULT_EXPIRATION); + $item->expiresAfter(!$this->debugMode ? self::CACHE_RESULT_EXPIRATION : 1); return $provider->searchByKeyword($keyword); }); @@ -94,11 +102,16 @@ final class PartInfoRetriever { $provider = $this->provider_registry->getProviderByKey($provider_key); + //Ensure that the provider is active + if (!$provider->isActive()) { + throw new \RuntimeException("The provider with key $provider_key is not active!"); + } + //Generate key and escape reserved characters from the provider id $escaped_part_id = urlencode($part_id); return $this->partInfoCache->get("details_{$provider_key}_{$escaped_part_id}", function (ItemInterface $item) use ($provider, $part_id) { //Set the expiration time - $item->expiresAfter(self::CACHE_DETAIL_EXPIRATION); + $item->expiresAfter(!$this->debugMode ? self::CACHE_DETAIL_EXPIRATION : 1); return $provider->getDetails($part_id); }); diff --git a/src/Services/InfoProviderSystem/ProviderRegistry.php b/src/Services/InfoProviderSystem/ProviderRegistry.php index acfbdc1e..f6c398d2 100644 --- a/src/Services/InfoProviderSystem/ProviderRegistry.php +++ b/src/Services/InfoProviderSystem/ProviderRegistry.php @@ -27,6 +27,7 @@ use App\Services\InfoProviderSystem\Providers\InfoProviderInterface; /** * This class keeps track of all registered info providers and allows to find them by their key + * @see \App\Tests\Services\InfoProviderSystem\ProviderRegistryTest */ final class ProviderRegistry { diff --git a/src/Services/InfoProviderSystem/Providers/DigikeyProvider.php b/src/Services/InfoProviderSystem/Providers/DigikeyProvider.php index 31b9cb41..b20368ce 100644 --- a/src/Services/InfoProviderSystem/Providers/DigikeyProvider.php +++ b/src/Services/InfoProviderSystem/Providers/DigikeyProvider.php @@ -45,6 +45,14 @@ class DigikeyProvider implements InfoProviderInterface private readonly HttpClientInterface $digikeyClient; + /** + * A list of parameter IDs, that are always assumed as text only and will never be converted to a numerical value. + * This allows to fix issues like #682, where the "Supplier Device Package" was parsed as a numerical value. + */ + private const TEXT_ONLY_PARAMETERS = [ + 1291, //Supplier Device Package + 39246, //Package / Case + ]; public function __construct(HttpClientInterface $httpClient, private readonly OAuthTokenManager $authTokenManager, private readonly string $currency, private readonly string $clientId, @@ -93,19 +101,22 @@ class DigikeyProvider implements InfoProviderInterface public function isActive(): bool { //The client ID has to be set and a token has to be available (user clicked connect) - return !empty($this->clientId) && $this->authTokenManager->hasToken(self::OAUTH_APP_NAME); + return $this->clientId !== '' && $this->authTokenManager->hasToken(self::OAUTH_APP_NAME); } public function searchByKeyword(string $keyword): array { $request = [ 'Keywords' => $keyword, - 'RecordCount' => 50, - 'RecordStartPosition' => 0, - 'ExcludeMarketPlaceProducts' => 'true', + 'Limit' => 50, + 'Offset' => 0, + 'FilterOptionsRequest' => [ + 'MarketPlaceFilter' => 'ExcludeMarketPlace', + ], ]; - $response = $this->digikeyClient->request('POST', '/Search/v3/Products/Keyword', [ + //$response = $this->digikeyClient->request('POST', '/Search/v3/Products/Keyword', [ + $response = $this->digikeyClient->request('POST', '/products/v4/search/keyword', [ 'json' => $request, 'auth_bearer' => $this->authTokenManager->getAlwaysValidTokenString(self::OAUTH_APP_NAME) ]); @@ -116,18 +127,21 @@ class DigikeyProvider implements InfoProviderInterface $result = []; $products = $response_array['Products']; foreach ($products as $product) { - $result[] = new SearchResultDTO( - provider_key: $this->getProviderKey(), - provider_id: $product['DigiKeyPartNumber'], - name: $product['ManufacturerPartNumber'], - description: $product['DetailedDescription'] ?? $product['ProductDescription'], - category: $this->getCategoryString($product), - manufacturer: $product['Manufacturer']['Value'] ?? null, - mpn: $product['ManufacturerPartNumber'], - preview_image_url: $product['PrimaryPhoto'] ?? null, - manufacturing_status: $this->productStatusToManufacturingStatus($product['ProductStatus']), - provider_url: $product['ProductUrl'], - ); + foreach ($product['ProductVariations'] as $variation) { + $result[] = new SearchResultDTO( + provider_key: $this->getProviderKey(), + provider_id: $variation['DigiKeyProductNumber'], + name: $product['ManufacturerProductNumber'], + description: $product['Description']['DetailedDescription'] ?? $product['Description']['ProductDescription'], + category: $this->getCategoryString($product), + manufacturer: $product['Manufacturer']['Name'] ?? null, + mpn: $product['ManufacturerProductNumber'], + preview_image_url: $product['PhotoUrl'] ?? null, + manufacturing_status: $this->productStatusToManufacturingStatus($product['ProductStatus']['Id']), + provider_url: $product['ProductUrl'], + footprint: $variation['PackageType']['Name'], //Use the footprint field, to show the user the package type (Tape & Reel, etc., as digikey has many different package types) + ); + } } return $result; @@ -135,63 +149,79 @@ class DigikeyProvider implements InfoProviderInterface public function getDetails(string $id): PartDetailDTO { - $response = $this->digikeyClient->request('GET', '/Search/v3/Products/' . urlencode($id), [ + $response = $this->digikeyClient->request('GET', '/products/v4/search/' . urlencode($id) . '/productdetails', [ 'auth_bearer' => $this->authTokenManager->getAlwaysValidTokenString(self::OAUTH_APP_NAME) ]); - $product = $response->toArray(); + $response_array = $response->toArray(); + $product = $response_array['Product']; $footprint = null; $parameters = $this->parametersToDTOs($product['Parameters'] ?? [], $footprint); - $media = $this->mediaToDTOs($product['MediaLinks']); + $media = $this->mediaToDTOs($id); + + // Get the price_breaks of the selected variation + $price_breaks = []; + foreach ($product['ProductVariations'] as $variation) { + if ($variation['DigiKeyProductNumber'] == $id) { + $price_breaks = $variation['StandardPricing'] ?? []; + break; + } + } return new PartDetailDTO( provider_key: $this->getProviderKey(), - provider_id: $product['DigiKeyPartNumber'], - name: $product['ManufacturerPartNumber'], - description: $product['DetailedDescription'] ?? $product['ProductDescription'], + provider_id: $id, + name: $product['ManufacturerProductNumber'], + description: $product['Description']['DetailedDescription'] ?? $product['Description']['ProductDescription'], category: $this->getCategoryString($product), - manufacturer: $product['Manufacturer']['Value'] ?? null, - mpn: $product['ManufacturerPartNumber'], - preview_image_url: $product['PrimaryPhoto'] ?? null, - manufacturing_status: $this->productStatusToManufacturingStatus($product['ProductStatus']), + manufacturer: $product['Manufacturer']['Name'] ?? null, + mpn: $product['ManufacturerProductNumber'], + preview_image_url: $product['PhotoUrl'] ?? null, + manufacturing_status: $this->productStatusToManufacturingStatus($product['ProductStatus']['Id']), provider_url: $product['ProductUrl'], footprint: $footprint, datasheets: $media['datasheets'], images: $media['images'], parameters: $parameters, - vendor_infos: $this->pricingToDTOs($product['StandardPricing'] ?? [], $product['DigiKeyPartNumber'], $product['ProductUrl']), + vendor_infos: $this->pricingToDTOs($price_breaks, $id, $product['ProductUrl']), ); } /** * Converts the product status from the Digikey API to the manufacturing status used in Part-DB - * @param string|null $dk_status + * @param int|null $dk_status * @return ManufacturingStatus|null */ - private function productStatusToManufacturingStatus(?string $dk_status): ?ManufacturingStatus + private function productStatusToManufacturingStatus(?int $dk_status): ?ManufacturingStatus { + // The V4 can use strings to get the status, but if you have changed the PROVIDER_DIGIKEY_LANGUAGE it will not match. + // Using the Id instead which should be fixed. + // + // The API is not well documented and the ID are not there yet, so were extracted using "trial and error". + // The 'Preliminary' id was not found in several categories so I was unable to extract it. Disabled for now. return match ($dk_status) { null => null, - 'Active' => ManufacturingStatus::ACTIVE, - 'Obsolete' => ManufacturingStatus::DISCONTINUED, - 'Discontinued at Digi-Key' => ManufacturingStatus::EOL, - 'Last Time Buy' => ManufacturingStatus::EOL, - 'Not For New Designs' => ManufacturingStatus::NRFND, - 'Preliminary' => ManufacturingStatus::ANNOUNCED, + 0 => ManufacturingStatus::ACTIVE, + 1 => ManufacturingStatus::DISCONTINUED, + 2, 4 => ManufacturingStatus::EOL, + 7 => ManufacturingStatus::NRFND, + //'Preliminary' => ManufacturingStatus::ANNOUNCED, default => ManufacturingStatus::NOT_SET, }; } private function getCategoryString(array $product): string { - $category = $product['Category']['Value']; - $sub_category = $product['Family']['Value']; + $category = $product['Category']['Name']; + $sub_category = current($product['Category']['ChildCategories']); - //Replace the ' - ' category separator with ' -> ' - $sub_category = str_replace(' - ', ' -> ', $sub_category); + if ($sub_category) { + //Replace the ' - ' category separator with ' -> ' + $category = $category . ' -> ' . str_replace(' - ', ' -> ', $sub_category["Name"]); + } - return $category . ' -> ' . $sub_category; + return $category; } /** @@ -208,10 +238,19 @@ class DigikeyProvider implements InfoProviderInterface foreach ($parameters as $parameter) { if ($parameter['ParameterId'] === 1291) { //Meaning "Manufacturer given footprint" - $footprint_name = $parameter['Value']; + $footprint_name = $parameter['ValueText']; } - $results[] = ParameterDTO::parseValueIncludingUnit($parameter['Parameter'], $parameter['Value']); + if (in_array(trim((string) $parameter['ValueText']), ['', '-'], true)) { + continue; + } + + //If the parameter was marked as text only, then we do not try to parse it as a numerical value + if (in_array($parameter['ParameterId'], self::TEXT_ONLY_PARAMETERS, true)) { + $results[] = new ParameterDTO(name: $parameter['ParameterText'], value_text: $parameter['ValueText']); + } else { //Otherwise try to parse it as a numerical value + $results[] = ParameterDTO::parseValueIncludingUnit($parameter['ParameterText'], $parameter['ValueText']); + } } return $results; @@ -238,16 +277,22 @@ class DigikeyProvider implements InfoProviderInterface } /** - * @param array $media_links + * @param string $id The Digikey product number, to get the media for * @return FileDTO[][] * @phpstan-return array */ - private function mediaToDTOs(array $media_links): array + private function mediaToDTOs(string $id): array { $datasheets = []; $images = []; - foreach ($media_links as $media_link) { + $response = $this->digikeyClient->request('GET', '/products/v4/search/' . urlencode($id) . '/media', [ + 'auth_bearer' => $this->authTokenManager->getAlwaysValidTokenString(self::OAUTH_APP_NAME) + ]); + + $media_array = $response->toArray(); + + foreach ($media_array['MediaLinks'] as $media_link) { $file = new FileDTO(url: $media_link['Url'], name: $media_link['Title']); switch ($media_link['MediaType']) { @@ -266,4 +311,4 @@ class DigikeyProvider implements InfoProviderInterface ]; } -} \ No newline at end of file +} diff --git a/src/Services/InfoProviderSystem/Providers/Element14Provider.php b/src/Services/InfoProviderSystem/Providers/Element14Provider.php index 7cc6693b..b942b929 100644 --- a/src/Services/InfoProviderSystem/Providers/Element14Provider.php +++ b/src/Services/InfoProviderSystem/Providers/Element14Provider.php @@ -24,20 +24,19 @@ declare(strict_types=1); namespace App\Services\InfoProviderSystem\Providers; use App\Entity\Parts\ManufacturingStatus; -use App\Form\InfoProviderSystem\ProviderSelectType; use App\Services\InfoProviderSystem\DTOs\FileDTO; use App\Services\InfoProviderSystem\DTOs\ParameterDTO; use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; use App\Services\InfoProviderSystem\DTOs\PriceDTO; -use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; +use Composer\CaBundle\CaBundle; use Symfony\Contracts\HttpClient\HttpClientInterface; class Element14Provider implements InfoProviderInterface { private const ENDPOINT_URL = 'https://api.element14.com/catalog/products'; - private const API_VERSION_NUMBER = '1.2'; + private const API_VERSION_NUMBER = '1.4'; private const NUMBER_OF_RESULTS = 20; public const DISTRIBUTOR_NAME = 'Farnell'; @@ -45,9 +44,19 @@ class Element14Provider implements InfoProviderInterface private const COMPLIANCE_ATTRIBUTES = ['euEccn', 'hazardous', 'MSL', 'productTraceability', 'rohsCompliant', 'rohsPhthalatesCompliant', 'SVHC', 'tariffCode', 'usEccn', 'hazardCode']; - public function __construct(private readonly HttpClientInterface $element14Client, private readonly string $api_key, private readonly string $store_id) - { + private readonly HttpClientInterface $element14Client; + public function __construct(HttpClientInterface $element14Client, private readonly string $api_key, private readonly string $store_id) + { + /* We use the mozilla CA from the composer ca bundle directly, as some debian systems seems to have problems + * with the SSL.COM CA, element14 uses. See https://github.com/Part-DB/Part-DB-server/issues/866 + * + * This is a workaround until the issue is resolved in debian (or never). + * As this only affects this provider, this should have no negative impact and the CA bundle is still secure. + */ + $this->element14Client = $element14Client->withOptions([ + 'cafile' => CaBundle::getBundledCaBundlePath(), + ]); } public function getProviderInfo(): array @@ -67,7 +76,7 @@ class Element14Provider implements InfoProviderInterface public function isActive(): bool { - return !empty($this->api_key); + return $this->api_key !== ''; } /** @@ -85,7 +94,7 @@ class Element14Provider implements InfoProviderInterface 'resultsSettings.responseGroup' => 'large', 'callInfo.apiKey' => $this->api_key, 'callInfo.responseDataFormat' => 'json', - 'callInfo.version' => self::API_VERSION_NUMBER, + 'versionNumber' => self::API_VERSION_NUMBER, ], ]); @@ -109,23 +118,20 @@ class Element14Provider implements InfoProviderInterface mpn: $product['translatedManufacturerPartNumber'], preview_image_url: $this->toImageUrl($product['image'] ?? null), manufacturing_status: $this->releaseStatusCodeToManufacturingStatus($product['releaseStatusCode'] ?? null), - provider_url: $this->generateProductURL($product['sku']), + provider_url: $product['productURL'], + notes: $product['productOverview']['description'] ?? null, datasheets: $this->parseDataSheets($product['datasheets'] ?? null), parameters: $this->attributesToParameters($product['attributes'] ?? null), - vendor_infos: $this->pricesToVendorInfo($product['sku'], $product['prices'] ?? []) + vendor_infos: $this->pricesToVendorInfo($product['sku'], $product['prices'] ?? [], $product['productURL']), + ); } return $result; } - private function generateProductURL($sku): string - { - return 'https://' . $this->store_id . '/' . $sku; - } - /** - * @param mixed[]|null $datasheets + * @param array|null $datasheets * @return FileDTO[]|null Array of FileDTOs */ private function parseDataSheets(?array $datasheets): ?array @@ -163,7 +169,7 @@ class Element14Provider implements InfoProviderInterface * @param array $prices * @return array */ - private function pricesToVendorInfo(string $sku, array $prices): array + private function pricesToVendorInfo(string $sku, array $prices, string $product_url): array { $price_dtos = []; @@ -181,7 +187,7 @@ class Element14Provider implements InfoProviderInterface distributor_name: self::DISTRIBUTOR_NAME, order_number: $sku, prices: $price_dtos, - product_url: $this->generateProductURL($sku) + product_url: $product_url ) ]; } @@ -190,41 +196,20 @@ class Element14Provider implements InfoProviderInterface { //Decide based on the shop ID return match ($this->store_id) { - 'bg.farnell.com' => 'EUR', + 'bg.farnell.com', 'at.farnell.com', 'si.farnell.com', 'sk.farnell.com', 'ro.farnell.com', 'pt.farnell.com', 'nl.farnell.com', 'be.farnell.com', 'lv.farnell.com', 'lt.farnell.com', 'it.farnell.com', 'fr.farnell.com', 'fi.farnell.com', 'ee.farnell.com', 'es.farnell.com', 'ie.farnell.com', 'cpcireland.farnell.com', 'de.farnell.com' => 'EUR', 'cz.farnell.com' => 'CZK', 'dk.farnell.com' => 'DKK', - 'at.farnell.com' => 'EUR', 'ch.farnell.com' => 'CHF', - 'de.farnell.com' => 'EUR', - 'cpc.farnell.com' => 'GBP', - 'cpcireland.farnell.com' => 'EUR', - 'export.farnell.com' => 'GBP', - 'onecall.farnell.com' => 'GBP', - 'ie.farnell.com' => 'EUR', - 'il.farnell.com' => 'USD', - 'uk.farnell.com' => 'GBP', - 'es.farnell.com' => 'EUR', - 'ee.farnell.com' => 'EUR', - 'fi.farnell.com' => 'EUR', - 'fr.farnell.com' => 'EUR', + 'cpc.farnell.com', 'uk.farnell.com', 'onecall.farnell.com', 'export.farnell.com' => 'GBP', + 'il.farnell.com', 'www.newark.com' => 'USD', 'hu.farnell.com' => 'HUF', - 'it.farnell.com' => 'EUR', - 'lt.farnell.com' => 'EUR', - 'lv.farnell.com' => 'EUR', - 'be.farnell.com' => 'EUR', - 'nl.farnell.com' => 'EUR', 'no.farnell.com' => 'NOK', 'pl.farnell.com' => 'PLN', - 'pt.farnell.com' => 'EUR', - 'ro.farnell.com' => 'EUR', 'ru.farnell.com' => 'RUB', - 'sk.farnell.com' => 'EUR', - 'si.farnell.com' => 'EUR', 'se.farnell.com' => 'SEK', 'tr.farnell.com' => 'TRY', 'canada.newark.com' => 'CAD', 'mexico.newark.com' => 'MXN', - 'www.newark.com' => 'USD', 'cn.element14.com' => 'CNY', 'au.element14.com' => 'AUD', 'nz.element14.com' => 'NZD', diff --git a/src/Services/InfoProviderSystem/Providers/LCSCProvider.php b/src/Services/InfoProviderSystem/Providers/LCSCProvider.php new file mode 100755 index 00000000..d903a8dd --- /dev/null +++ b/src/Services/InfoProviderSystem/Providers/LCSCProvider.php @@ -0,0 +1,366 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\InfoProviderSystem\Providers; + +use App\Services\InfoProviderSystem\DTOs\FileDTO; +use App\Services\InfoProviderSystem\DTOs\ParameterDTO; +use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; +use App\Services\InfoProviderSystem\DTOs\PriceDTO; +use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class LCSCProvider implements InfoProviderInterface +{ + + private const ENDPOINT_URL = 'https://wmsc.lcsc.com/ftps/wm'; + + public const DISTRIBUTOR_NAME = 'LCSC'; + + public function __construct(private readonly HttpClientInterface $lcscClient, private readonly string $currency, private readonly bool $enabled = true) + { + + } + + public function getProviderInfo(): array + { + return [ + 'name' => 'LCSC', + 'description' => 'This provider uses the (unofficial) LCSC API to search for parts.', + 'url' => 'https://www.lcsc.com/', + 'disabled_help' => 'Set PROVIDER_LCSC_ENABLED to 1 (or true) in your environment variable config.' + ]; + } + + public function getProviderKey(): string + { + return 'lcsc'; + } + + // This provider is always active + public function isActive(): bool + { + return $this->enabled; + } + + /** + * @param string $id + * @return PartDetailDTO + */ + private function queryDetail(string $id): PartDetailDTO + { + $response = $this->lcscClient->request('GET', self::ENDPOINT_URL . "/product/detail", [ + 'headers' => [ + 'Cookie' => new Cookie('currencyCode', $this->currency) + ], + 'query' => [ + 'productCode' => $id, + ], + ]); + + $arr = $response->toArray(); + $product = $arr['result'] ?? null; + + if ($product === null) { + throw new \RuntimeException('Could not find product code: ' . $id); + } + + return $this->getPartDetail($product); + } + + /** + * @param string $url + * @return String + */ + private function getRealDatasheetUrl(?string $url): string + { + if ($url !== null && trim($url) !== '' && preg_match("/^https:\/\/(datasheet\.lcsc\.com|www\.lcsc\.com\/datasheet)\/.*(C\d+)\.pdf$/", $url, $matches) > 0) { + if (preg_match("/^https:\/\/datasheet\.lcsc\.com\/lcsc\/(.*\.pdf)$/", $url, $rewriteMatches) > 0) { + $url = 'https://www.lcsc.com/datasheet/lcsc_datasheet_' . $rewriteMatches[1]; + } + $response = $this->lcscClient->request('GET', $url, [ + 'headers' => [ + 'Referer' => 'https://www.lcsc.com/product-detail/_' . $matches[2] . '.html' + ], + ]); + if (preg_match('/(previewPdfUrl): ?("[^"]+wmsc\.lcsc\.com[^"]+\.pdf")/', $response->getContent(), $matches) > 0) { + //HACKY: The URL string contains escaped characters like \u002F, etc. To decode it, the JSON decoding is reused + //See https://github.com/Part-DB/Part-DB-server/pull/582#issuecomment-2033125934 + $jsonObj = json_decode('{"' . $matches[1] . '": ' . $matches[2] . '}'); + $url = $jsonObj->previewPdfUrl; + } + } + return $url; + } + + /** + * @param string $term + * @return PartDetailDTO[] + */ + private function queryByTerm(string $term): array + { + $response = $this->lcscClient->request('GET', self::ENDPOINT_URL . "/search/global", [ + 'headers' => [ + 'Cookie' => new Cookie('currencyCode', $this->currency) + ], + 'query' => [ + 'keyword' => $term, + ], + ]); + + $arr = $response->toArray(); + + // Get products list + $products = $arr['result']['productSearchResultVO']['productList'] ?? []; + // Get product tip + $tipProductCode = $arr['result']['tipProductDetailUrlVO']['productCode'] ?? null; + + $result = []; + + // LCSC does not display LCSC codes in the search, instead taking you directly to the + // detailed product listing. It does so utilizing a product tip field. + // If product tip exists and there are no products in the product list try a detail query + if (count($products) === 0 && $tipProductCode !== null) { + $result[] = $this->queryDetail($tipProductCode); + } + + foreach ($products as $product) { + $result[] = $this->getPartDetail($product); + } + + return $result; + } + + /** + * Sanitizes a field by removing any HTML tags and other unwanted characters + * @param string|null $field + * @return string|null + */ + private function sanitizeField(?string $field): ?string + { + if ($field === null) { + return null; + } + + return strip_tags($field); + } + + + /** + * Takes a deserialized json object of the product and returns a PartDetailDTO + * @param array $product + * @return PartDetailDTO + */ + private function getPartDetail(array $product): PartDetailDTO + { + // Get product images in advance + $product_images = $this->getProductImages($product['productImages'] ?? null); + $product['productImageUrl'] ??= null; + + // If the product does not have a product image but otherwise has attached images, use the first one. + if (count($product_images) > 0) { + $product['productImageUrl'] ??= $product_images[0]->url; + } + + // LCSC puts HTML in footprints and descriptions sometimes randomly + $footprint = $product["encapStandard"] ?? null; + //If the footprint just consists of a dash, we'll assume it's empty + if ($footprint === '-') { + $footprint = null; + } + + //Build category by concatenating the catalogName and parentCatalogName + $category = $product['parentCatalogName'] ?? null; + if (isset($product['catalogName'])) { + $category = ($category ?? '') . ' -> ' . $product['catalogName']; + + // Replace the / with a -> for better readability + $category = str_replace('/', ' -> ', $category); + } + + return new PartDetailDTO( + provider_key: $this->getProviderKey(), + provider_id: $product['productCode'], + name: $product['productModel'], + description: $this->sanitizeField($product['productIntroEn']), + category: $this->sanitizeField($category ?? null), + manufacturer: $this->sanitizeField($product['brandNameEn'] ?? null), + mpn: $this->sanitizeField($product['productModel'] ?? null), + preview_image_url: $product['productImageUrl'], + manufacturing_status: null, + provider_url: $this->getProductShortURL($product['productCode']), + footprint: $this->sanitizeField($footprint), + datasheets: $this->getProductDatasheets($product['pdfUrl'] ?? null), + images: $product_images, + parameters: $this->attributesToParameters($product['paramVOList'] ?? []), + vendor_infos: $this->pricesToVendorInfo($product['productCode'], $this->getProductShortURL($product['productCode']), $product['productPriceList'] ?? []), + mass: $product['weight'] ?? null, + ); + } + + /** + * Converts the price array to a VendorInfoDTO array to be used in the PartDetailDTO + * @param string $sku + * @param string $url + * @param array $prices + * @return array + */ + private function pricesToVendorInfo(string $sku, string $url, array $prices): array + { + $price_dtos = []; + + foreach ($prices as $price) { + $price_dtos[] = new PriceDTO( + minimum_discount_amount: $price['ladder'], + price: $price['productPrice'], + currency_iso_code: $this->getUsedCurrency($price['currencySymbol']), + includes_tax: false, + ); + } + + return [ + new PurchaseInfoDTO( + distributor_name: self::DISTRIBUTOR_NAME, + order_number: $sku, + prices: $price_dtos, + product_url: $url, + ) + ]; + } + + /** + * Converts LCSC currency symbol to an ISO code. + * @param string $currency + * @return string + */ + private function getUsedCurrency(string $currency): string + { + //Decide based on the currency symbol + return match ($currency) { + 'US$', '$' => 'USD', + '€' => 'EUR', + 'A$' => 'AUD', + 'C$' => 'CAD', + '£' => 'GBP', + 'HK$' => 'HKD', + 'JP¥' => 'JPY', + 'RM' => 'MYR', + 'S$' => 'SGD', + '₽' => 'RUB', + 'kr' => 'SEK', + 'kr.' => 'DKK', + '₹' => 'INR', + //Fallback to the configured currency + default => $this->currency, + }; + } + + /** + * Returns a valid LCSC product short URL from product code + * @param string $product_code + * @return string + */ + private function getProductShortURL(string $product_code): string + { + return 'https://www.lcsc.com/product-detail/' . $product_code .'.html'; + } + + /** + * Returns a product datasheet FileDTO array from a single pdf url + * @param string $url + * @return FileDTO[] + */ + private function getProductDatasheets(?string $url): array + { + if ($url === null) { + return []; + } + + $realUrl = $this->getRealDatasheetUrl($url); + + return [new FileDTO($realUrl, null)]; + } + + /** + * Returns a FileDTO array with a list of product images + * @param array|null $images + * @return FileDTO[] + */ + private function getProductImages(?array $images): array + { + return array_map(static fn($image) => new FileDTO($image), $images ?? []); + } + + /** + * @param array|null $attributes + * @return ParameterDTO[] + */ + private function attributesToParameters(?array $attributes): array + { + $result = []; + + foreach ($attributes as $attribute) { + + //Skip this attribute if it's empty + if (in_array(trim((string) $attribute['paramValueEn']), ['', '-'], true)) { + continue; + } + + $result[] = ParameterDTO::parseValueIncludingUnit(name: $attribute['paramNameEn'], value: $attribute['paramValueEn'], group: null); + } + + return $result; + } + + public function searchByKeyword(string $keyword): array + { + return $this->queryByTerm($keyword); + } + + public function getDetails(string $id): PartDetailDTO + { + $tmp = $this->queryByTerm($id); + if (count($tmp) === 0) { + throw new \RuntimeException('No part found with ID ' . $id); + } + + if (count($tmp) > 1) { + throw new \RuntimeException('Multiple parts found with ID ' . $id); + } + + return $tmp[0]; + } + + public function getCapabilities(): array + { + return [ + ProviderCapabilities::BASIC, + ProviderCapabilities::PICTURE, + ProviderCapabilities::DATASHEET, + ProviderCapabilities::PRICE, + ProviderCapabilities::FOOTPRINT, + ]; + } +} diff --git a/src/Services/InfoProviderSystem/Providers/MouserProvider.php b/src/Services/InfoProviderSystem/Providers/MouserProvider.php new file mode 100644 index 00000000..90bad263 --- /dev/null +++ b/src/Services/InfoProviderSystem/Providers/MouserProvider.php @@ -0,0 +1,350 @@ +. + */ + +/* +* This file provide an interface with the Mouser API V2 (also compatible with the V1) +* +* Copyright (C) 2023 Pasquale D'Orsi (https://github.com/pdo59) +* +* TODO: Obtain an API keys with an US Mouser user (currency $) and test the result of prices +* +*/ + +declare(strict_types=1); + + +namespace App\Services\InfoProviderSystem\Providers; + +use App\Entity\Parts\ManufacturingStatus; +use App\Services\InfoProviderSystem\DTOs\FileDTO; +use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; +use App\Services\InfoProviderSystem\DTOs\PriceDTO; +use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + + +class MouserProvider implements InfoProviderInterface +{ + + private const ENDPOINT_URL = 'https://api.mouser.com/api/v2/search'; + + public const DISTRIBUTOR_NAME = 'Mouser'; + + public function __construct( + private readonly HttpClientInterface $mouserClient, + private readonly string $api_key, + private readonly string $language, + private readonly string $options, + private readonly int $search_limit + ) { + } + + public function getProviderInfo(): array + { + return [ + 'name' => 'Mouser', + 'description' => 'This provider uses the Mouser API to search for parts.', + 'url' => 'https://www.mouser.com/', + 'disabled_help' => 'Configure the API key in the PROVIDER_MOUSER_KEY environment variable to enable.' + ]; + } + + public function getProviderKey(): string + { + return 'mouser'; + } + + public function isActive(): bool + { + return $this->api_key !== ''; + } + + public function searchByKeyword(string $keyword): array + { + /* + SearchByKeywordRequest description: + Search parts by keyword and return a maximum of 50 parts. + + keyword* string + Used for keyword part search. + + records integer($int32) + Used to specify how many records the method should return. + + startingRecord integer($int32) + Indicates where in the total recordset the return set should begin. + From the startingRecord, the number of records specified will be returned up to the end of the recordset. + This is useful for paging through the complete recordset of parts matching keyword. + + + searchOptions string + Optional. + If not provided, the default is None. + Refers to options supported by the search engine. + Only one value at a time is supported. + Available options: None | Rohs | InStock | RohsAndInStock - can use string representations or integer IDs: 1[None] | 2[Rohs] | 4[InStock] | 8[RohsAndInStock]. + + searchWithYourSignUpLanguage string + Optional. + If not provided, the default is false. + Used when searching for keywords in the language specified when you signed up for Search API. + Can use string representation: true. + { + "SearchByKeywordRequest": { + "keyword": "BC557", + "records": 0, + "startingRecord": 0, + "searchOptions": "", + "searchWithYourSignUpLanguage": "" + } + } + */ + + $response = $this->mouserClient->request('POST', self::ENDPOINT_URL."/keyword", [ + 'query' => [ + 'apiKey' => $this->api_key, + ], + 'json' => [ + 'SearchByKeywordRequest' => [ + 'keyword' => $keyword, + 'records' => $this->search_limit, //self::NUMBER_OF_RESULTS, + 'startingRecord' => 0, + 'searchOptions' => $this->options, + 'searchWithYourSignUpLanguage' => $this->language, + ] + ], + ]); + + return $this->responseToDTOArray($response); + } + + public function getDetails(string $id): PartDetailDTO + { + /* + SearchByPartRequest description: + Search parts by part number and return a maximum of 50 parts. + + mouserPartNumber string + Used to search parts by the specific Mouser part number with a maximum input of 10 part numbers, separated by a pipe symbol for the search. + Each part number must be a minimum of 3 characters and a maximum of 40 characters. For example: 494-JANTX2N2222A|610-2N2222-TL|637-2N2222A + + partSearchOptions string + Optional. + If not provided, the default is None. Refers to options supported by the search engine. Only one value at a time is supported. + The following values are valid: None | Exact - can use string representations or integer IDs: 1[None] | 2[Exact] + + { + "SearchByPartRequest": { + "mouserPartNumber": "string", + "partSearchOptions": "string" + } + } + */ + + $response = $this->mouserClient->request('POST', self::ENDPOINT_URL."/partnumber", [ + 'query' => [ + 'apiKey' => $this->api_key, + ], + 'json' => [ + 'SearchByPartRequest' => [ + 'mouserPartNumber' => $id, + 'partSearchOptions' => 2 + ] + ], + ]); + $tmp = $this->responseToDTOArray($response); + + //Ensure that we have exactly one result + if (count($tmp) === 0) { + throw new \RuntimeException('No part found with ID '.$id); + } + + //Manually filter out the part with the correct ID + $tmp = array_filter($tmp, fn(PartDetailDTO $part) => $part->provider_id === $id); + if (count($tmp) === 0) { + throw new \RuntimeException('No part found with ID '.$id); + } + if (count($tmp) > 1) { + throw new \RuntimeException('Multiple parts found with ID '.$id); + } + + return reset($tmp); + } + + public function getCapabilities(): array + { + return [ + ProviderCapabilities::BASIC, + ProviderCapabilities::PICTURE, + ProviderCapabilities::DATASHEET, + ProviderCapabilities::PRICE, + ]; + } + + + /** + * @param ResponseInterface $response + * @return PartDetailDTO[] + */ + private function responseToDTOArray(ResponseInterface $response): array + { + $arr = $response->toArray(); + + if (isset($arr['SearchResults'])) { + $products = $arr['SearchResults']['Parts'] ?? []; + } else { + throw new \RuntimeException('Unknown response format: ' .json_encode($arr, JSON_THROW_ON_ERROR)); + } + + $result = []; + foreach ($products as $product) { + + //Check if we have a valid product number. We assume that a product number, must have at least 4 characters + //Otherwise filter it out + if (strlen($product['MouserPartNumber']) < 4) { + continue; + } + + //Check if we have a mass field available + $mass = null; + if (isset($product['UnitWeightKg']['UnitWeight'])) { + $mass = (float) $product['UnitWeightKg']['UnitWeight']; + //The mass is given in kg, we want it in g + $mass *= 1000; + } + + + $result[] = new PartDetailDTO( + provider_key: $this->getProviderKey(), + provider_id: $product['MouserPartNumber'], + name: $product['ManufacturerPartNumber'], + description: $product['Description'], + category: $product['Category'], + manufacturer: $product['Manufacturer'], + mpn: $product['ManufacturerPartNumber'], + preview_image_url: $product['ImagePath'], + manufacturing_status: $this->releaseStatusCodeToManufacturingStatus( + $product['LifecycleStatus'] ?? null, + (int) ($product['AvailabilityInStock'] ?? 0) + ), + provider_url: $product['ProductDetailUrl'], + datasheets: $this->parseDataSheets($product['DataSheetUrl'] ?? null, + $product['MouserPartNumber'] ?? null), + vendor_infos: $this->pricingToDTOs($product['PriceBreaks'] ?? [], $product['MouserPartNumber'], + $product['ProductDetailUrl']), + mass: $mass, + ); + } + return $result; + } + + + private function parseDataSheets(?string $sheetUrl, ?string $sheetName): ?array + { + if ($sheetUrl === null || $sheetUrl === '' || $sheetUrl === '0') { + return null; + } + $result = []; + $result[] = new FileDTO(url: $sheetUrl, name: $sheetName); + return $result; + } + + /* + * Mouser API price is a string in the form "n[.,]nnn[.,] currency" + * then this convert it to a number + * Austria has a format like "€ 2,10" + */ + private function priceStrToFloat($val): float + { + //Remove any character that is not a number, dot or comma (like currency symbols) + $val = preg_replace('/[^0-9.,]/', '', $val); + + //Trim the string + $val = trim($val); + + //Convert commas to dots + $val = str_replace(",", ".", $val); + //Remove any dot that is not the last one (to avoid problems with thousands separators) + $val = preg_replace('/\.(?=.*\.)/', '', $val); + return (float)$val; + } + + /** + * Converts the pricing (StandardPricing field) from the Mouser API to an array of PurchaseInfoDTOs + * @param array $price_breaks + * @param string $order_number + * @param string $product_url + * @return PurchaseInfoDTO[] + */ + private function pricingToDTOs(array $price_breaks, string $order_number, string $product_url): array + { + $prices = []; + + foreach ($price_breaks as $price_break) { + $number = $this->priceStrToFloat($price_break['Price']); + $prices[] = new PriceDTO( + minimum_discount_amount: $price_break['Quantity'], + price: (string)$number, + currency_iso_code: $price_break['Currency'] + ); + } + + return [ + new PurchaseInfoDTO(distributor_name: self::DISTRIBUTOR_NAME, order_number: $order_number, prices: $prices, + product_url: $product_url) + ]; + } + + + /* Converts the product status from the MOUSER API to the manufacturing status used in Part-DB: + Factory Special Order - Ordine speciale in fabbrica + Not Recommended for New Designs - Non raccomandato per nuovi progetti + New Product - Nuovo prodotto + End of Life - Fine vita + -vuoto- - Attivo + + TODO: Probably need to review the values of field Lifecyclestatus + */ + /** + * Converts the lifecycle status from the Mouser API to a ManufacturingStatus + * @param string|null $productStatus The lifecycle status from the Mouser API + * @param int $availableInStock The number of parts available in stock + * @return ManufacturingStatus|null + */ + private function releaseStatusCodeToManufacturingStatus(?string $productStatus, int $availableInStock = 0): ?ManufacturingStatus + { + $tmp = match ($productStatus) { + null => null, + "New Product" => ManufacturingStatus::ANNOUNCED, + "Not Recommended for New Designs" => ManufacturingStatus::NRFND, + "Factory Special Order", "Obsolete" => ManufacturingStatus::DISCONTINUED, + "End of Life" => ManufacturingStatus::EOL, + default => ManufacturingStatus::ACTIVE, + }; + + //If the part would be assumed to be announced, check if it is in stock, then it is active + if ($tmp === ManufacturingStatus::ANNOUNCED && $availableInStock > 0) { + $tmp = ManufacturingStatus::ACTIVE; + } + + return $tmp; + } +} \ No newline at end of file diff --git a/src/Services/InfoProviderSystem/Providers/OEMSecretsProvider.php b/src/Services/InfoProviderSystem/Providers/OEMSecretsProvider.php new file mode 100644 index 00000000..ccf800f8 --- /dev/null +++ b/src/Services/InfoProviderSystem/Providers/OEMSecretsProvider.php @@ -0,0 +1,1471 @@ +. + */ + +/** + * OEMSecretsProvider Class + * + * This class is responsible for interfacing with the OEMSecrets API (version 3.0.1) to retrieve and manage information + * about electronic components. Since the API does not provide a unique identifier for each part, the class aggregates + * results based on "part_number" and "manufacturer_id". It also transforms unstructured descriptions into structured + * parameters and aggregates datasheets and images provided by multiple distributors. + * The OEMSecrets API returns results by matching the provided part number not only with the original part number + * but also with the distributor-assigned part number and/or the part description. + * + * Key functionalities: + * - Aggregation of results based on part_number and manufacturer_id to ensure unique identification of parts. + * - Conversion of component descriptions into structured parameters (ParameterDTO) for better clarity and searchability. + * - Aggregation of datasheets and images from multiple distributors, ensuring that all available resources are collected. + * - Price handling, including filtering of distributors that offer zero prices, controlled by the `zero_price` configuration variable. + * - A sorting algorithm that first prioritizes exact matches with the keyword, followed by alphabetical sorting of items + * with the same prefix (e.g., "BC546", "BC546A", "BC546B"), and finally, sorts by either manufacturer or completeness + * based on the specified criteria. + * - Sorting the distributors: + * 1. Environment's country_code first. + * 2. Region matching environment's country_code, prioritizing "Global" ('XX'). + * 3. Distributors with null country_code/region are placed last. + * 4. Final fallback is alphabetical sorting by region and country_code. + * + * Configuration: + * - The ZERO_PRICE variable must be set in the `.env.local` file. If is set to 0, the class will skip distributors + * that do not offer valid prices for the components. + * - Currency and country settings can also be specified for localized pricing and distributor filtering. + * - Generation of parameters: if SET_PARAM is set to 1 the parameters for the part are generated from the description + * transforming unstructured descriptions into structured parameters; each parameter in description should have the form: + * "...;name1:value1;name2:value2" + * - Sorting is guided by SORT_CRITERIA variable. The sorting process first arranges items based on the provided keyword. + * Then, if set to 'C', it further sorts by completeness (prioritizing items with the most detailed information). + * If set to 'M', it further sorts by manufacturer name. If unset or set to any other value, no sorting is performed. + * Distributors within each item are further sorted based on country_code and region, following the rules explained + * in the previous comment. + * + * Data Handling: + * - The class divides and stores component information across multiple session arrays: + * - `basic_info_results`: Stores basic information like name, description, manufacturer, and category. + * - `datasheets_results`: Aggregates datasheets provided by distributors, ensuring no duplicates. + * - `images_results`: Collects images of components from various sources, preventing duplication. + * - `parameters_results`: Extracts and stores key parameters parsed from component descriptions. + * - `purchase_info_results`: Contains detailed purchasing information like pricing and distributor details. + * + * - By splitting the data into separate session arrays, the class optimizes memory usage and simplifies retrieval + * of specific details without loading the entire dataset at once. + * + * Technical Details: + * - Uses OEMSecrets API (version 3.0.1) to retrieve component data. + * - Data processing includes sanitizing input, avoiding duplicates, and dynamically adjusting information as new distributor + * data becomes available (e.g., adding missing datasheets or parameters from subsequent API responses). + * + * @package App\Services\InfoProviderSystem\Providers + * @author Pasquale D'Orsi (https://github.com/pdo59) + * @version 1.2.0 + * @since 2024 August + */ + + +declare(strict_types=1); + +namespace App\Services\InfoProviderSystem\Providers; + +use App\Entity\Parts\ManufacturingStatus; +use App\Services\InfoProviderSystem\DTOs\FileDTO; +use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; +use App\Services\InfoProviderSystem\DTOs\PriceDTO; +use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; +use App\Services\InfoProviderSystem\DTOs\ParameterDTO; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Psr\Cache\CacheItemPoolInterface; + + +class OEMSecretsProvider implements InfoProviderInterface +{ + + private const ENDPOINT_URL = 'https://oemsecretsapi.com/partsearch'; + + public function __construct( + private readonly HttpClientInterface $oemsecretsClient, + private readonly string $api_key, + private readonly string $country_code, + private readonly string $currency, + private readonly string $zero_price, + private readonly string $set_param, + private readonly string $sort_criteria, + private readonly CacheItemPoolInterface $partInfoCache + ) + { + } + + private array $countryNameToCodeMap = [ + 'Andorra' => 'AD', + 'United Arab Emirates' => 'AE', + 'Antarctica' => 'AQ', + 'Argentina' => 'AR', + 'Austria' => 'AT', + 'Australia' => 'AU', + 'Belgium' => 'BE', + 'Bolivia' => 'BO', + 'Brazil' => 'BR', + 'Bouvet Island' => 'BV', + 'Belarus' => 'BY', + 'Canada' => 'CA', + 'Switzerland' => 'CH', + 'Chile' => 'CL', + 'China' => 'CN', + 'Colombia' => 'CO', + 'Czech Republic' => 'CZ', + 'Germany' => 'DE', + 'Denmark' => 'DK', + 'Ecuador' => 'EC', + 'Estonia' => 'EE', + 'Western Sahara' => 'EH', + 'Spain' => 'ES', + 'Finland' => 'FI', + 'Falkland Islands' => 'FK', + 'Faroe Islands' => 'FO', + 'France' => 'FR', + 'United Kingdom' => 'GB', + 'Georgia' => 'GE', + 'French Guiana' => 'GF', + 'Guernsey' => 'GG', + 'Gibraltar' => 'GI', + 'Greenland' => 'GL', + 'Greece' => 'GR', + 'South Georgia and the South Sandwich Islands' => 'GS', + 'Guyana' => 'GY', + 'Hong Kong' => 'HK', + 'Heard Island and McDonald Islands' => 'HM', + 'Croatia' => 'HR', + 'Hungary' => 'HU', + 'Ireland' => 'IE', + 'Isle of Man' => 'IM', + 'India' => 'IN', + 'Iceland' => 'IS', + 'Italy' => 'IT', + 'Jamaica' => 'JM', + 'Japan' => 'JP', + 'North Korea' => 'KP', + 'South Korea' => 'KR', + 'Kazakhstan' => 'KZ', + 'Liechtenstein' => 'LI', + 'Sri Lanka' => 'LK', + 'Lithuania' => 'LT', + 'Luxembourg' => 'LU', + 'Monaco' => 'MC', + 'Moldova' => 'MD', + 'Montenegro' => 'ME', + 'North Macedonia' => 'MK', + 'Malta' => 'MT', + 'Netherlands' => 'NL', + 'Norway' => 'NO', + 'New Zealand' => 'NZ', + 'Peru' => 'PE', + 'Philippines' => 'PH', + 'Poland' => 'PL', + 'Portugal' => 'PT', + 'Paraguay' => 'PY', + 'Romania' => 'RO', + 'Serbia' => 'RS', + 'Russia' => 'RU', + 'Solomon Islands' => 'SB', + 'Sudan' => 'SD', + 'Sweden' => 'SE', + 'Singapore' => 'SG', + 'Slovenia' => 'SI', + 'Svalbard and Jan Mayen' => 'SJ', + 'Slovakia' => 'SK', + 'San Marino' => 'SM', + 'Somalia' => 'SO', + 'Suriname' => 'SR', + 'Syria' => 'SY', + 'Eswatini' => 'SZ', + 'Turks and Caicos Islands' => 'TC', + 'French Southern Territories' => 'TF', + 'Togo' => 'TG', + 'Thailand' => 'TH', + 'Tajikistan' => 'TJ', + 'Tokelau' => 'TK', + 'Turkmenistan' => 'TM', + 'Tunisia' => 'TN', + 'Tonga' => 'TO', + 'Turkey' => 'TR', + 'Trinidad and Tobago' => 'TT', + 'Tuvalu' => 'TV', + 'Taiwan' => 'TW', + 'Tanzania' => 'TZ', + 'Ukraine' => 'UA', + 'Uganda' => 'UG', + 'United States Minor Outlying Islands' => 'UM', + 'United States' => 'US', + 'Uruguay' => 'UY', + 'Uzbekistan' => 'UZ', + 'Vatican City' => 'VA', + 'Venezuela' => 'VE', + 'British Virgin Islands' => 'VG', + 'U.S. Virgin Islands' => 'VI', + 'Vietnam' => 'VN', + 'Vanuatu' => 'VU', + 'Wallis and Futuna' => 'WF', + 'Yemen' => 'YE', + 'South Africa' => 'ZA', + 'Zambia' => 'ZM', + 'Zimbabwe' => 'ZW', + 'Global' => 'XX' + ]; + + private array $distributorCountryCodes = []; + private array $countryCodeToRegionMap = []; + + /** + * Get information about this provider + * + * @return array An associative array with the following keys (? means optional): + * - name: The (user friendly) name of the provider (e.g. "Digikey"), will be translated + * - description?: A short description of the provider (e.g. "Digikey is a ..."), will be translated + * - logo?: The logo of the provider (e.g. "digikey.png") + * - url?: The url of the provider (e.g. "https://www.digikey.com") + * - disabled_help?: A help text which is shown when the provider is disabled, explaining how to enable it + * - oauth_app_name?: The name of the OAuth app which is used for authentication (e.g. "ip_digikey_oauth"). If this is set a connect button will be shown + * + * @phpstan-return array{ name: string, description?: string, logo?: string, url?: string, disabled_help?: string, oauth_app_name?: string } + */ + public function getProviderInfo(): array + { + return [ + 'name' => 'OEMSecrets', + 'description' => 'This provider uses the OEMSecrets API to search for parts.', + 'url' => 'https://www.oemsecrets.com/', + 'disabled_help' => 'Configure the API key in the PROVIDER_OEMSECRETS_KEY environment variable to enable.' + ]; + } + /** + * Returns a unique key for this provider, which will be saved into the database + * and used to identify the provider + * @return string A unique key for this provider (e.g. "digikey") + */ + public function getProviderKey(): string + { + return 'oemsecrets'; + } + + /** + * Checks if this provider is enabled or not (meaning that it can be used for searching) + * @return bool True if the provider is enabled, false otherwise + */ + public function isActive(): bool + { + return $this->api_key !== ''; + } + + + /** + * Searches for products based on a given keyword using the OEMsecrets Part Search API. + * + * This method queries the OEMsecrets API to retrieve distributor data for the provided part number, + * including details such as pricing, compliance, and inventory. It supports both direct API queries + * and debugging with local JSON files. The results are processed, cached, and then sorted based + * on the keyword and specified criteria. + * + * @param string $keyword The part number to search for + * @return array An array of processed product details, sorted by relevance and additional criteria. + * + * @throws \Exception If the JSON file used for debugging is not found or contains errors. + */ + public function searchByKeyword(string $keyword): array + { + /* + oemsecrets Part Search API 3.0.1 + + "https://oemsecretsapi.com/partsearch? + searchTerm=BC547 + &apiKey=icawpb0bspoo2c6s64uv4vpdfp2vgr7e27bxw0yct2bzh87mpl027x353uelpq2x + ¤cy=EUR + &countryCode=IT" + + partsearch description: + Use the Part Search API to find distributor data for a full or partial manufacturer + part number including part details, pricing, compliance and inventory. + + Required Parameter Format Description + searchTerm string Part number you are searching for + apiKey string Your unique API key provided to you by OEMsecrets + + Additional Parameter Format Description + countryCode string The country you want to output for + currency string / array The currency you want the prices to be displayed as + + To display the output for GB and to view prices in USD, add [ countryCode=GB ] and [ currency=USD ] + as seen below: + oemsecretsapi.com/partsearch?apiKey=abcexampleapikey123&searchTerm=bd04&countryCode=GB¤cy=USD + + To view prices in both USD and GBP add [ currency[]=USD¤cy[]=GBP ] + oemsecretsapi.com/partsearch?searchTerm=bd04&apiKey=abcexampleapikey123¤cy[]=USD¤cy[]=GBP + + */ + + + // Activate this block when querying the real APIs + //------------------ + + $response = $this->oemsecretsClient->request('GET', self::ENDPOINT_URL, [ + 'query' => [ + 'searchTerm' => $keyword, + 'apiKey' => $this->api_key, + 'currency' => $this->currency, + 'countryCode' => $this->country_code, + ], + ]); + + $response_array = $response->toArray(); + //------------------*/ + + // Or activate this block when we use json file for debugging + /*/------------------ + $jsonFilePath = ''; + if (!file_exists($jsonFilePath)) { + throw new \Exception("JSON file not found."); + } + $jsonContent = file_get_contents($jsonFilePath); + $response_array = json_decode($jsonContent, true); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \Exception("JSON file decode failed: " . json_last_error_msg()); + } + //------------------*/ + + $products = $response_array['stock'] ?? []; + + $results = []; + $basicInfoResults = []; + $datasheetsResults = []; + $imagesResults = []; + $parametersResults = []; + $purchaseInfoResults = []; + + foreach ($products as $product) { + if (!isset($product['part_number'], $product['manufacturer'])) { + continue; // Skip invalid product entries + } + $provider_id = $this->generateProviderId($product['part_number'], $product['manufacturer']); + + $partDetailDTO = $this->processBatch( + $product, + $provider_id, + $basicInfoResults, + $datasheetsResults, + $imagesResults, + $parametersResults, + $purchaseInfoResults + ); + + if ($partDetailDTO !== null) { + $results[$provider_id] = $partDetailDTO; + $cacheKey = $this->getCacheKey($provider_id); + $cacheItem = $this->partInfoCache->getItem($cacheKey); + $cacheItem->set($partDetailDTO); + $cacheItem->expiresAfter(3600 * 24); + $this->partInfoCache->save($cacheItem); + } + } + + //Force garbage collection to free up memory + gc_collect_cycles(); + + // Sort of the results + $this->sortResultsData($results, $keyword); + + //Force garbage collection to free up memory + gc_collect_cycles(); + + return $results; + + } + + /** + * Generates a cache key for storing part details based on the provided provider ID. + * + * This method creates a unique cache key by prefixing the provider ID with 'part_details_' + * and hashing the provider ID using MD5 to ensure a consistent and compact key format. + * + * @param string $provider_id The unique identifier of the provider or part. + * @return string The generated cache key. + */ + private function getCacheKey(string $provider_id): string { + return 'oemsecrets_part_' . md5($provider_id); + } + + + /** + * Retrieves detailed information about the part with the given provider ID from the cache. + * + * This method checks the cache for the details of the specified part. If the details are + * found in the cache, they are returned. If not, an exception is thrown indicating that + * the details could not be found. + * + * @param string $id The unique identifier of the provider or part. + * @return PartDetailDTO The detailed information about the part. + * + * @throws \Exception If no details are found for the given provider ID. + */ + public function getDetails(string $id): PartDetailDTO + { + $cacheKey = $this->getCacheKey($id); + $cacheItem = $this->partInfoCache->getItem($cacheKey); + + if ($cacheItem->isHit()) { + return $cacheItem->get(); + } + //If we have no cached result yet, we extract the part number (first part of our ID) and search for it + $partNumber = explode('|', $id)[0]; + + //The searchByKeyword method will write the results to cache, so we can just try it again afterwards + $this->searchByKeyword($partNumber); + + $cacheItem = $this->partInfoCache->getItem($cacheKey); + if ($cacheItem->isHit()) { + return $cacheItem->get(); + } + + // If the details still are not found in the cache, throw an exception + throw new \RuntimeException("Details not found for provider_id $id"); + } + + + /** + * A list of capabilities this provider supports (which kind of data it can provide). + * Not every part have to contain all of these data, but the provider should be able to provide them in general. + * Currently, this list is purely informational and not used in functional checks. + * @return ProviderCapabilities[] + */ + public function getCapabilities(): array + { + return [ + ProviderCapabilities::BASIC, + ProviderCapabilities::PICTURE, + ProviderCapabilities::DATASHEET, + ProviderCapabilities::PRICE, + ]; + } + + + /** + * Processes a single product and updates arrays for basic information, datasheets, images, parameters, + * and purchase information. Aggregates and organizes data received for a specific `part_number` and `manufacturer_id`. + * Distributors within the product are also sorted based on country_code and region. + * + * @param array $product The product data received from the OEMSecrets API. + * @param string $provider_id A string that contains the unique key created for the part + * @param array &$basicInfoResults Array containing the basic product information (e.g., name, description, category). + * @param array &$datasheetsResults Array containing datasheets collected from various distributors for the product. + * @param array &$imagesResults Array containing images of the product collected from various distributors. + * @param array &$parametersResults Array containing technical parameters extracted from the product descriptions. + * @param array &$purchaseInfoResults Array containing purchase information, including distributors and pricing details. + * + * @return PartDetailDTO|null Returns a PartDetailDTO object if the product is processed successfully, otherwise null. + * + * @throws \Exception If a required key in the product data is missing or if there is an issue creating the DTO. + * + * @see createOrUpdateBasicInfo() Creates or updates the basic product information. + * @see getPrices() Extracts the pricing information for the product. + * @see parseDataSheets() Parses and prevents duplication of datasheets. + * @see getImages() Extracts and avoids duplication of images. + * @see getParameters() Extracts technical parameters from the product description. + * @see createPurchaseInfoDTO() Creates a PurchaseInfoDTO containing distributor and price information. + * + * @note Distributors within the product are sorted by country_code and region: + * 1. Distributors with the environment's country_code come first. + * 2. Distributors in the same region as the environment's country_code are next, + * with "Global" ('XX') prioritized within this region. + * 3. Distributors with null country_code or region are placed last. + * 4. Remaining distributors are sorted alphabetically by region and country_code. + + */ + private function processBatch( + array $product, + string $provider_id, + array &$basicInfoResults, + array &$datasheetsResults, + array &$imagesResults, + array &$parametersResults, + array &$purchaseInfoResults + ): ?PartDetailDTO + { + if (!isset($product['manufacturer'], $product['part_number'])) { + throw new \InvalidArgumentException("Missing required product data: 'manufacturer' or 'part_number'"); + } + + // Retrieve the country_code associated with the distributor and store it in the $distributorCountryCodes array. + $distributorCountry = $product['distributor']['distributor_country'] ?? null; + $distributorName = $product['distributor']['distributor_name'] ?? null; + $distributorRegion = $product['distributor']['distributor_region'] ?? null; + + if ($distributorCountry && $distributorName) { + $countryCode = $this->mapCountryNameToCode($distributorCountry); + if ($countryCode) { + $this->distributorCountryCodes[$distributorName] = $countryCode; + } + if ($distributorRegion) { + $this->countryCodeToRegionMap[$countryCode] = $distributorRegion; + } + } + + // Truncate the description and handle notes + $thenotes = ''; + $description = $product['description'] ?? ''; + if (strlen($description) > 100) { + $thenotes = $description; // Save the complete description + $description = substr($description, 0, 100) . '...'; // Truncate the description + } + + // Extract prices + $priceDTOs = $this->getPrices($product); + if (empty($priceDTOs) && (int)$this->zero_price === 0) { + return null; // Skip products without valid prices + } + + $existingBasicInfo = isset($basicInfoResults[$provider_id]) && is_array($basicInfoResults[$provider_id]) + ? $basicInfoResults[$provider_id] + : []; + + $basicInfoResults[$provider_id] = $this->createOrUpdateBasicInfo( + $provider_id, + $product, + $description, + $thenotes, + $existingBasicInfo + ); + + // Update images, datasheets, and parameters + + $newDatasheets = $this->parseDataSheets($product['datasheet_url'] ?? null, null, $datasheetsResults[$provider_id] ?? []); + if ($newDatasheets !== null) { + $datasheetsResults[$provider_id] = array_merge($datasheetsResults[$provider_id] ?? [], $newDatasheets); + } + + $imagesResults[$provider_id] = $this->getImages($product, $imagesResults[$provider_id] ?? []); + if ($this->set_param == 1) { + $parametersResults[$provider_id] = $this->getParameters($product, $parametersResults[$provider_id] ?? []); + } else { + $parametersResults[$provider_id] = []; + } + + // Handle purchase information + $currentDistributor = $this->createPurchaseInfoDTO($product, $priceDTOs, $purchaseInfoResults[$provider_id] ?? []); + if ($currentDistributor !== null) { + $purchaseInfoResults[$provider_id][] = $currentDistributor; + } + + // If there is data in $purchaseInfoResults, sort it before creating the PartDetailDTO + if (!empty($purchaseInfoResults[$provider_id])) { + usort($purchaseInfoResults[$provider_id], function ($a, $b) { + $nameA = $a->distributor_name; + $nameB = $b->distributor_name; + + $countryCodeA = $this->distributorCountryCodes[$nameA] ?? null; + $countryCodeB = $this->distributorCountryCodes[$nameB] ?? null; + + $regionA = $this->countryCodeToRegionMap[$countryCodeA] ?? ''; + $regionB = $this->countryCodeToRegionMap[$countryCodeB] ?? ''; + + // If the map is empty or doesn't contain the key for $this->country_code, assign a placeholder region. + $regionForEnvCountry = $this->countryCodeToRegionMap[$this->country_code] ?? ''; + + // Convert to string before comparison to avoid mixed types + $countryCodeA = (string) $countryCodeA; + $countryCodeB = (string) $countryCodeB; + $regionA = (string) $regionA; + $regionB = (string) $regionB; + + + // Step 0: If either country code is null, place it at the end + if ($countryCodeA === '' || $regionA === '') { + return 1; // Metti A dopo B + } elseif ($countryCodeB === '' || $regionB === '') { + return -1; // Metti B dopo A + } + + // Step 1: country_code from the environment + if ($countryCodeA === $this->country_code && $countryCodeB !== $this->country_code) { + return -1; + } elseif ($countryCodeA !== $this->country_code && $countryCodeB === $this->country_code) { + return 1; + } + + // Step 2: Sort by environment's region, prioritizing "Global" (XX) + if ($regionA === $regionForEnvCountry && $regionB !== $regionForEnvCountry) { + return -1; + } elseif ($regionA !== $regionForEnvCountry && $regionB === $regionForEnvCountry) { + return 1; + } + + // Step 3: If regions are the same, prioritize "Global" (XX) + if ($regionA === $regionB) { + if ($countryCodeA === 'XX' && $countryCodeB !== 'XX') { + return -1; + } elseif ($countryCodeA !== 'XX' && $countryCodeB === 'XX') { + return 1; + } + } + + // Step 4: Alphabetical sorting by region and country_code + $regionComparison = strcasecmp($regionA , $regionB); + if ($regionComparison !== 0) { + return $regionComparison; + } + + // Alphabetical sorting as a fallback + return strcasecmp($countryCodeA, $countryCodeB); + }); + } + // Convert the gathered data into a PartDetailDTO + + $partDetailDTO = new PartDetailDTO( + provider_key: $basicInfoResults[$provider_id]['provider_key'], + provider_id: $provider_id, + name: $basicInfoResults[$provider_id]['name'], + description: $basicInfoResults[$provider_id]['description'], + category: $basicInfoResults[$provider_id]['category'], + manufacturer: $basicInfoResults[$provider_id]['manufacturer'], + mpn: $basicInfoResults[$provider_id]['mpn'], + preview_image_url: $basicInfoResults[$provider_id]['preview_image_url'], + manufacturing_status: $basicInfoResults[$provider_id]['manufacturing_status'], + provider_url: $basicInfoResults[$provider_id]['provider_url'], + footprint: $basicInfoResults[$provider_id]['footprint'] ?? null, + notes: $basicInfoResults[$provider_id]['notes'] ?? null, + datasheets: $datasheetsResults[$provider_id] ?? [], + images: $imagesResults[$provider_id] ?? [], + parameters: $parametersResults[$provider_id] ?? [], + vendor_infos: $purchaseInfoResults[$provider_id] ?? [] + ); + + return $partDetailDTO; + } + + + /** + * Extracts pricing information from the product data, converts it to PriceDTO objects, + * and returns them as an array. + * + * @param array{ + * prices?: array>, + * source_currency?: string + * } $product The product data from the OEMSecrets API containing price details. + * + * @return PriceDTO[] Array of PriceDTO objects representing different price tiers for the product. + */ + private function getPrices(array $product): array + { + $prices = $product['prices'] ?? []; + $sourceCurrency = $product['source_currency'] ?? null; + $priceDTOs = []; + + // Flag to check if we have added prices in the preferred currency + $foundPreferredCurrency = false; + + if (is_array($prices)) { + // Step 1: Check if prices exist in the preferred currency + if (isset($prices[$this->currency]) && is_array($prices[$this->currency])) { + $priceDetails = $prices[$this->currency]; + foreach ($priceDetails as $priceDetail) { + if ( + is_array($priceDetail) && + isset($priceDetail['unit_break'], $priceDetail['unit_price']) && + is_numeric($priceDetail['unit_break']) && + is_string($priceDetail['unit_price']) && + $priceDetail['unit_price'] !== "0.0000" + ) { + $priceDTOs[] = new PriceDTO( + minimum_discount_amount: (float)$priceDetail['unit_break'], + price: (string)$priceDetail['unit_price'], + currency_iso_code: $this->currency, + includes_tax: false, + price_related_quantity: 1.0 + ); + $foundPreferredCurrency = true; + } + } + } + + // Step 2: If no prices in the preferred currency, use source currency + if (!$foundPreferredCurrency && $sourceCurrency && isset($prices[$sourceCurrency]) && is_array($prices[$sourceCurrency])) { + $priceDetails = $prices[$sourceCurrency]; + foreach ($priceDetails as $priceDetail) { + if ( + is_array($priceDetail) && + isset($priceDetail['unit_break'], $priceDetail['unit_price']) && + is_numeric($priceDetail['unit_break']) && + is_string($priceDetail['unit_price']) && + $priceDetail['unit_price'] !== "0.0000" + ) { + $priceDTOs[] = new PriceDTO( + minimum_discount_amount: (float)$priceDetail['unit_break'], + price: (string)$priceDetail['unit_price'], + currency_iso_code: $sourceCurrency, + includes_tax: false, + price_related_quantity: 1.0 + ); + } + } + } + } + + return $priceDTOs; + } + + + /** + * Retrieves product images provided by the distributor. Prevents duplicates based on the image name. + * @param array{ + * image_url?: string + * } $product The product data from the OEMSecrets API containing image URLs. + * @param FileDTO[] $existingImages Optional. Existing images for the product to avoid duplicates. + * + * @return FileDTO[] Array of FileDTO objects representing the product images. + */ + private function getImages(array $product, array $existingImages = []): array + { + $images = $existingImages; + $imageUrl = $product['image_url'] ?? null; + + if ($imageUrl) { + $imageName = basename(parse_url($imageUrl, PHP_URL_PATH)); + if (!in_array($imageName, array_column($images, 'name'), true)) { + $images[] = new FileDTO(url: $imageUrl, name: $imageName); + } + } + return $images; + } + + /** + * Extracts technical parameters from the product description, ensures no duplicates, and returns them as an array. + * + * @param array{ + * description?: string + * } $product The product data from the OEMSecrets API containing product descriptions. + * @param ParameterDTO[] $existingParameters Optional. Existing parameters for the product to avoid duplicates. + * + * @return ParameterDTO[] Array of ParameterDTO objects representing technical parameters extracted from the product description. + */ + private function getParameters(array $product, array $existingParameters = []): array + { + $parameters = $existingParameters; + $description = $product['description'] ?? ''; + + // Logic to extract parameters from the description + $extractedParameters = $this->parseDescriptionToParameters($description) ?? []; + + foreach ($extractedParameters as $newParam) { + $isDuplicate = false; + foreach ($parameters as $existingParam) { + if ($existingParam->name === $newParam->name) { + $isDuplicate = true; + break; + } + } + if (!$isDuplicate) { + $parameters[] = $newParam; + } + } + + return $parameters; + } + + /** + * Creates a PurchaseInfoDTO object containing distributor and pricing information for a product. + * Ensures that the distributor name is valid and prices are available. + * + * @param array{ + * distributor?: array{ + * distributor_name?: string + * }, + * sku?: string, + * source_part_number: string, + * buy_now_url?: string, + * lead_time_weeks?: mixed + * } $product The product data from the OEMSecrets API. + * @param PriceDTO[] $priceDTOs Array of PriceDTO objects representing pricing tiers. + * @param PurchaseInfoDTO[] $existingPurchaseInfos Optional. Existing purchase information for the product to avoid duplicates. + * + * @return PurchaseInfoDTO|null A PurchaseInfoDTO object containing the distributor information, or null if invalid. + */ + private function createPurchaseInfoDTO(array $product, array $priceDTOs, array $existingPurchaseInfos = []): ?PurchaseInfoDTO + { + $distributor_name = $product['distributor']['distributor_name'] ?? null; + if ($distributor_name && !empty($priceDTOs)) { + $sku = isset($product['sku']) ? (string)$product['sku'] : null; + $order_number_base = $sku ?: (string)$product['source_part_number']; + $order_number = $order_number_base; + + // Remove duplicates from the quantity/price tiers + $uniquePriceDTOs = []; + foreach ($priceDTOs as $priceDTO) { + $key = $priceDTO->minimum_discount_amount . '-' . $priceDTO->price; + $uniquePriceDTOs[$key] = $priceDTO; + } + $priceDTOs = array_values($uniquePriceDTOs); + + // Differentiate $order_number if duplicated + if ($this->isDuplicateOrderNumber($order_number, $distributor_name, $existingPurchaseInfos)) { + $lead_time_weeks = isset($product['lead_time_weeks']) ? (string)$product['lead_time_weeks'] : ''; + $order_number = $order_number_base . '-' . $lead_time_weeks; + + // If there is still a duplicate after adding lead_time_weeks + $counter = 1; + while ($this->isDuplicateOrderNumber($order_number, $distributor_name, $existingPurchaseInfos)) { + $order_number = $order_number_base . '-' . $lead_time_weeks . '-' . $counter; + $counter++; + } + } + + return new PurchaseInfoDTO( + distributor_name: $distributor_name, + order_number: $order_number, + prices: $priceDTOs, + product_url: $this->unwrapURL($product['buy_now_url'] ?? null) + ); + } + return null; // Return null if no valid distributor exists + } + + /** + * Checks if an order number already exists for a given distributor in the existing purchase infos. + * + * @param string $order_number The order number to check. + * @param string $distributor_name The name of the distributor. + * @param PurchaseInfoDTO[] $existingPurchaseInfos The existing purchase information to check against. + * @return bool True if a duplicate order number is found, otherwise false. + */ + private function isDuplicateOrderNumber(string $order_number, string $distributor_name, array $existingPurchaseInfos): bool + { + foreach ($existingPurchaseInfos as $purchaseInfo) { + if ($purchaseInfo->distributor_name === $distributor_name && $purchaseInfo->order_number === $order_number) { + return true; + } + } + return false; + } + + /** + * Creates or updates the basic information of a product, including the description, category, manufacturer, + * and other metadata. This function manages the PartDetailDTO creation or update. + * + * @param string $provider_id The unique identifier for the product based on part_number and manufacturer. + * * @param array{ + * part_number: string, + * category: string, + * manufacturer: string, + * source_part_number: string, + * image_url?: string, + * life_cycle?: string, + * quantity_in_stock?: int + * } $product The product data from the OEMSecrets API. + * @param string $description The truncated description for the product. + * @param string $thenotes The full description saved as notes for the product. + * + * @return array The updated or newly created PartDetailDTO containing basic product information. + */ + private function createOrUpdateBasicInfo( + string $provider_id, + array $product, + string $description, + string $thenotes, + ?array $existingBasicInfo + ): array { + // If there is no existing basic info array, we create a new one + if (is_null($existingBasicInfo)) { + return [ + 'provider_key' => $this->getProviderKey(), + 'provider_id' => $provider_id, + 'name' => $product['part_number'], + 'description' => $description, + 'category' => $product['category'], + 'manufacturer' => $product['manufacturer'], + 'mpn' => $product['source_part_number'], + 'preview_image_url' => $product['image_url'] ?? null, + 'manufacturing_status' => $this->releaseStatusCodeToManufacturingStatus( + $product['life_cycle'] ?? null, + (int)($product['quantity_in_stock'] ?? 0) + ), + 'provider_url' => $this->generateInquiryUrl($product['part_number']), + 'notes' => $thenotes, + 'footprint' => null + ]; + } + + // Update fields only if empty or undefined, with additional check for preview_image_url + return [ + 'provider_key' => $existingBasicInfo['provider_key'] ?? $this->getProviderKey(), + 'provider_id' => $existingBasicInfo['provider_id'] ?? $provider_id, + 'name' => $existingBasicInfo['name'] ?? $product['part_number'], + // Update description if it's null/empty + 'description' => !empty($existingBasicInfo['description']) + ? $existingBasicInfo['description'] + : $description, + // Update category if it's null/empty + 'category' => !empty($existingBasicInfo['category']) + ? $existingBasicInfo['category'] + : $product['category'], + 'manufacturer' => $existingBasicInfo['manufacturer'] ?? $product['manufacturer'], + 'mpn' => $existingBasicInfo['mpn'] ?? $product['source_part_number'], + 'preview_image_url' => !empty($existingBasicInfo['preview_image_url']) + ? $existingBasicInfo['preview_image_url'] + : ($product['image_url'] ?? null), + 'manufacturing_status' => !empty($existingBasicInfo['manufacturing_status']) + ? $existingBasicInfo['manufacturing_status'] + : $this->releaseStatusCodeToManufacturingStatus( + $product['life_cycle'] ?? null, + (int)($product['quantity_in_stock'] ?? 0) + ), + 'provider_url' => $existingBasicInfo['provider_url'] ?? $this->generateInquiryUrl($product['part_number']), // ?? $product['buy_now_url'], + 'notes' => $existingBasicInfo['notes'] ?? $thenotes, + 'footprint' => null + ]; + } + + /** + * Parses the datasheet URL and returns an array of FileDTO objects representing the datasheets. + * If the datasheet name is not provided, it attempts to extract the file name from the URL. + * If multiple datasheets with the same default name are encountered, the function appends a + * numeric suffix to ensure uniqueness. + * The query parameter used to extract the event link can be customized. + * + * URL Requirements: + * - The URL should be a valid URL string. + * - The URL can include a query parameter named "event_link", which contains a sub-URL where the + * actual datasheet file name is located (e.g., a link to a PDF file). + * - If "event_link" is not present, the function attempts to extract the file name directly from + * the URL path. + * - The URL path should ideally end with a valid file extension (e.g., .pdf, .doc, .xls, etc.). + * + * Example 1: + * Given URL: `https://example.com/datasheet.php?event_link=https%3A%2F%2Ffiles.example.com%2Fdatasheet.pdf` + * Extracted name: `datasheet.pdf` + * + * Example 2: + * Given URL: `https://example.com/files/datasheet.pdf` + * Extracted name: `datasheet.pdf` + * + * Example 3 (default name fallback): + * Given URL: `https://example.com/files/noextensionfile` + * Extracted name: `datasheet.pdf` + * + * @param string|null $sheetUrl The URL of the datasheet. + * @param string|null $sheetName The optional name of the datasheet. If null, the name is extracted from the URL. + * @param array $existingDatasheets The array of existing datasheets to check for duplicates. + * + * @return FileDTO[]|null Returns an array containing the new datasheet if unique, or null if the datasheet is a duplicate or invalid. + * + * @see FileDTO Used to create datasheet objects with a URL and name. + */ + private function parseDataSheets(?string $sheetUrl, ?string $sheetName, array $existingDatasheets = []): ?array + { + if ($sheetUrl === null || $sheetUrl === '' || $sheetUrl === '0') { + return null; + } + + //Unwrap the URL (remove analytics part) + $sheetUrl = $this->unwrapURL($sheetUrl); + + // If the datasheet name is not provided, extract it from the URL + if ($sheetName === null) { + $urlPath = parse_url($sheetUrl, PHP_URL_PATH); + if ($urlPath === false) { + throw new \RuntimeException("Invalid URL path: $sheetUrl"); + } + + // If "event_link" does not exist, try to extract the name from the main URL path + $sheetName = basename($urlPath); + if (!str_contains($sheetName, '.') || !preg_match('/\.(pdf|doc|docx|xls|xlsx|ppt|pptx)$/i', $sheetName)) { + // If the name does not have a valid extension, assign a default name + $sheetName = 'datasheet_' . uniqid('', true) . '.pdf'; + } + } + + // Create an array of existing file names + $existingNames = array_map(static function ($existingDatasheet) { + return $existingDatasheet->name; + }, $existingDatasheets); + + // Check if the name already exists + if (in_array($sheetName, $existingNames, true)) { + // The name already exists, so do not add the datasheet + return null; + } + + // Create an array with the datasheet data if it does not already exist + $result = []; + $result[] = new FileDTO(url: $sheetUrl, name: $sheetName); + return $result; + } + + /** + * Converts the lifecycle status from the API to a ManufacturingStatus + * - "Factory Special Order" / "Ordine speciale in fabbrica" + * - "Not Recommended for New Designs" / "Non raccomandato per nuovi progetti" + * - "New Product" / "Nuovo prodotto" (if availableInStock > 0 else ANNOUNCED) + * - "End of Life" / "Fine vita" + * - vuoto / "Attivo" + * + * @param string|null $productStatus The lifecycle status from the Mouser API. Expected values are: + * - "Factory Special Order" + * - "Not Recommended for New Designs" + * - "New Product" + * - "End of Life" + * - "Obsolete" + * @param int $availableInStock The number of parts available in stock. + * @return ManufacturingStatus|null Returns the corresponding ManufacturingStatus or null if the status is unknown. + * + * @todo Probably need to review the values of field Lifecyclestatus. + */ + private function releaseStatusCodeToManufacturingStatus(?string $productStatus, int $availableInStock = 0): ?ManufacturingStatus + { + $tmp = match ($productStatus) { + null => null, + "New Product" => ManufacturingStatus::ANNOUNCED, + "Not Recommended for New Designs" => ManufacturingStatus::NRFND, + "Factory Special Order", "Obsolete" => ManufacturingStatus::DISCONTINUED, + "End of Life" => ManufacturingStatus::EOL, + default => null, //ManufacturingStatus::ACTIVE, + }; + + //If the part would be assumed to be announced, check if it is in stock, then it is active + if ($tmp === ManufacturingStatus::ANNOUNCED && $availableInStock > 0) { + $tmp = ManufacturingStatus::ACTIVE; + } + + return $tmp; + } + + /** + * Parses the given product description to extract parameters and convert them into `ParameterDTO` objects. + * If the description contains only a single `:`, it is considered unstructured and ignored. + * The function processes the description by searching for key-value pairs in the format `name: value`, + * ignoring any parts of the description that do not follow this format. Parameters are split using either + * `;` or `,` as separators. + * + * The extraction logic handles typical values, ranges, units, and textual information from the description. + * If the description is empty or cannot be processed into valid parameters, the function returns null. + * + * @param string|null $description The description text from which parameters are to be extracted. + * + * @return ParameterDTO[]|null Returns an array of `ParameterDTO` objects if parameters are successfully extracted, + * or null if no valid parameters can be extracted from the description. + */ + private function parseDescriptionToParameters(?string $description): ?array + { + // If the description is null or empty, return null + if ($description === null || trim($description) === '') { + return null; + } + + // If the description contains only a single ':', return null + if (substr_count($description, ':') === 1) { + return null; + } + + // Array to store parsed parameters + $parameters = []; + + // Split the description using the ';' separator + $parts = preg_split('/[;,]/', $description); //explode(';', $description); + + // Process each part of the description + foreach ($parts as $part) { + $part = trim($part); + + // Check if the part contains a key-value structure + if (str_contains($part, ':')) { + [$name, $value] = explode(':', $part, 2); + $name = trim($name); + $value = trim($value); + + // Attempt to parse the value, handling ranges, units, and additional information + $parsedValue = $this->customParseValueIncludingUnit($name, $value); + + // If the value was successfully parsed, create a ParameterDTO + if ($parsedValue) { + // Convert numeric values to float + $value_typ = isset($parsedValue['value_typ']) ? (float)$parsedValue['value_typ'] : null; + $value_min = isset($parsedValue['value_min']) ? (float)$parsedValue['value_min'] : null; + $value_max = isset($parsedValue['value_max']) ? (float)$parsedValue['value_max'] : null; + + $parameters[] = new ParameterDTO( + name: $parsedValue['name'], + value_text: $parsedValue['value_text'] ?? null, + value_typ: $value_typ, + value_min: $value_min, + value_max: $value_max, + unit: $parsedValue['unit'] ?? null, // Add extracted unit + symbol: $parsedValue['symbol'] ?? null // Add extracted symbol + ); + } + } + } + + return !empty($parameters) ? $parameters : null; + } + + /** + * Parses a value that may contain both a numerical value and its corresponding unit. + * This function splits the value into its numerical part and its unit, handling cases + * where the value includes symbols, ranges, or additional text. It also detects and + * processes plus/minus ranges, typical values, and other special formats. + * + * Example formats that can be handled: + * - "2.5V" + * - "±5%" + * - "1-10A" + * - "2.5 @text" + * - "~100 Ohm" + * + * @param string $value The value string to be parsed, which may contain a number, unit, or both. + * + * @return array An associative array with parsed components: + * - 'name' => string (the name of the parameter) + * - 'value_typ' => float|null (the typical or parsed value) + * - 'range_min' => float|null (the minimum value if it's a range) + * - 'range_max' => float|null (the maximum value if it's a range) + * - 'value_text' => string|null (any additional text or symbol) + * - 'unit' => string|null (the detected or default unit) + * - 'symbol' => string|null (any special symbol or additional text) + */ + private function customParseValueIncludingUnit(string $name, string $value): array + { + // Parse using logic for units, ranges, and other elements + $result = [ + 'name' => $name, + 'value_typ' => null, + 'value_min' => null, + 'value_max' => null, + 'value_text' => null, + 'unit' => null, + 'symbol' => null, + ]; + + // Trim any whitespace from the value + $value = trim($value); + + // Handle ranges and plus/minus signs + if (str_contains($value, '...') || str_contains($value, '~') || str_contains($value, '±')) { + // Handle ranges + $value = str_replace(['...', '~'], '...', $value); // Normalize range separators + $rangeParts = preg_split('/\s*[\.\~]\s*/', $value); + + if (count($rangeParts) === 2) { + // Splitting the values and units + $parsedMin = $this->customSplitIntoValueAndUnit($rangeParts[0]); + $parsedMax = $this->customSplitIntoValueAndUnit($rangeParts[1]); + + // Assigning the parsed values + $result['value_min'] = $parsedMin['value_typ']; + $result['value_max'] = $parsedMax['value_typ']; + + // Determine the unit + $result['unit'] = $parsedMax['unit'] ?? $parsedMin['unit']; + } + + } elseif (str_contains($value, '@')) { + // If we find "@", we treat it as additional textual information + [$numericValue, $textValue] = explode('@', $value); + $result['value_typ'] = (float) $numericValue; + $result['value_text'] = trim($textValue); + } else { + // Check if the value is numeric with a unit + if (preg_match('/^([\+\-]?\d+(\.\d+)?)([a-zA-Z%°]+)?$/u', $value, $matches)) { + // It is a number with or without a unit + $result['value_typ'] = (float) $matches[1]; + $result['unit'] = $matches[3] ?? null; + } else { + // It's not a number, so we treat it as text + $result['value_text'] = $value; + } + } + + return $result; + } + + /** + * Splits a string into a numerical value and its associated unit. The function attempts to separate + * a number from its unit, handling common formats where the unit follows the number (e.g., "50kHz", "10A"). + * The function assumes the unit is the non-numeric part of the string. + * + * Example formats that can be handled: + * - "100 Ohm" + * - "10 MHz" + * - "5kV" + * - "±5%" + * + * @param string $value1 The input string containing both a numerical value and a unit. + * @param string|null $value2 Optional. A second value string, typically used for ranges (e.g., "10-20A"). + * + * @return array An associative array with the following elements: + * - 'value_typ' => string|null The first numerical part of the string. + * - 'unit' => string|null The unit part of the string, or null if no unit is detected. + * - 'value_min' => string|null The minimum value in a range, if applicable. + * - 'value_max' => string|null The maximum value in a range, if applicable. + */ + private function customSplitIntoValueAndUnit(string $value1, ?string $value2 = null): array + { + // Separate numbers and units (basic parsing handling) + $unit = null; + $value_typ = null; + + // Search for the number + unit pattern + if (preg_match('/^([\+\-]?\d+(\.\d+)?)([a-zA-Z%°]+)?$/u', $value1, $matches)) { + $value_typ = $matches[1]; + $unit = $matches[3] ?? null; + } + + $result = [ + 'value_typ' => $value_typ, + 'unit' => $unit, + ]; + + if ($value2 !== null) { + if (preg_match('/^([\+\-]?\d+(\.\d+)?)([a-zA-Z%°]+)?$/u', $value2, $matches2)) { + $result['value_min'] = $value_typ; + $result['value_max'] = $matches2[1]; + $result['unit'] = $matches2[3] ?? $unit; // If both values have the same unit, we keep it + } + } + + return $result; + } + + /** + * Generates the API URL to fetch product information for the specified part number from OEMSecrets. + * Ensures that the base API URL and any query parameters are properly formatted. + * + * @param string $partNumber The part number to include in the URL. + * @param string $oemInquiry The inquiry path for the OEMSecrets API, with a default value of 'compare/'. + * This parameter represents the specific API endpoint to query. + * + * @return string The complete provider URL including the base provider URL, the inquiry path, and the part number. + * + * Example: + * If the base URL is "https://www.oemsecrets.com/", the inquiry path is "compare/", and the part number is "NE555", + * the resulting URL will be: "https://www.oemsecrets.com/compare/NE555" + */ + private function generateInquiryUrl(string $partNumber, string $oemInquiry = 'compare/'): string + { + $baseUrl = rtrim($this->getProviderInfo()['url'], '/') . '/'; + $inquiryPath = trim($oemInquiry, '/') . '/'; + $encodedPartNumber = urlencode(trim($partNumber)); + return $baseUrl . $inquiryPath . $encodedPartNumber; + } + + /** + * Sorts the results data array based on the specified search keyword and sorting criteria. + * The sorting process involves multiple phases: + * 1. Exact match with the search keyword. + * 2. Prefix match with the search keyword. + * 3. Alphabetical order of the suffix following the keyword. + * 4. Optional sorting by completeness or manufacturer based on the sort criteria. + * + * The sorting criteria (`sort_criteria`) is an environment variable configured in the `.env.local` file: + * PROVIDER_OEMSECRETS_SORT_CRITERIA + * It determines the final sorting phase: + * - 'C': Sort by completeness. + * - 'M': Sort by manufacturer. + * + * @param array $resultsData The array of result objects to be sorted. Each object should have 'name' and 'manufacturer' properties. + * @param string $searchKeyword The search keyword used for sorting the results. + * + * @return void + */ + private function sortResultsData(array &$resultsData, string $searchKeyword): void + { + // If the SORT_CRITERIA is not 'C' or 'M', do not sort + if ($this->sort_criteria !== 'C' && $this->sort_criteria !== 'M') { + return; + } + usort($resultsData, function ($a, $b) use ($searchKeyword) { + $nameA = trim($a->name); + $nameB = trim($b->name); + + // First phase: Sorting by exact match with the keyword + $exactMatchA = strcasecmp($nameA, $searchKeyword) === 0; + $exactMatchB = strcasecmp($nameB, $searchKeyword) === 0; + + if ($exactMatchA && !$exactMatchB) { + return -1; + } elseif (!$exactMatchA && $exactMatchB) { + return 1; + } + + // Second phase: Sorting by prefix (name starting with the keyword) + $startsWithKeywordA = stripos($nameA, $searchKeyword) === 0; + $startsWithKeywordB = stripos($nameB, $searchKeyword) === 0; + + if ($startsWithKeywordA && !$startsWithKeywordB) { + return -1; + } elseif (!$startsWithKeywordA && $startsWithKeywordB) { + return 1; + } + + if ($startsWithKeywordA && $startsWithKeywordB) { + // Alphabetical sorting of suffixes + $suffixA = substr($nameA, strlen($searchKeyword)); + $suffixB = substr($nameB, strlen($searchKeyword)); + $suffixComparison = strcasecmp($suffixA, $suffixB); + + if ($suffixComparison !== 0) { + return $suffixComparison; + } + } + + // Final sorting: by completeness or manufacturer, if necessary + if ($this->sort_criteria === 'C') { + return $this->compareByCompleteness($a, $b); + } elseif ($this->sort_criteria === 'M') { + return strcasecmp($a->manufacturer, $b->manufacturer); + } + + }); + } + + /** + * Compares two objects based on their "completeness" score. + * The completeness score is calculated by the `calculateCompleteness` method, which assigns a numeric score + * based on the amount of information (such as parameters, datasheets, images, etc.) available for each object. + * The comparison is done in descending order, giving priority to the objects with higher completeness. + * + * @param object $a The first object to compare. + * @param object $b The second object to compare. + * + * @return int A negative value if $b is more complete than $a, zero if they are equally complete, + * or a positive value if $a is more complete than $b. + */ + private function compareByCompleteness(object $a, object $b): int + { + // Calculate the completeness score for each object + $completenessA = $this->calculateCompleteness($a); + $completenessB = $this->calculateCompleteness($b); + + // Sort in descending order by completeness (higher score is better) + return $completenessB - $completenessA; + } + + + /** + * Calculates a "completeness" score for a given part object based on the presence and count of various attributes. + * The completeness score is used to prioritize parts that have more detailed information. + * + * The score is calculated as follows: + * - Counts the number of elements in the `parameters`, `datasheets`, `images`, and `vendor_infos` arrays. + * - Adds 1 point for the presence of `category`, `description`, `mpn`, `preview_image_url`, and `footprint`. + * - Adds 1 or 2 points based on the presence or absence of `manufacturing_status` (higher score if `null`). + * + * @param object $part The part object for which the completeness score is calculated. The object is expected + * to have properties like `parameters`, `datasheets`, `images`, `vendor_infos`, `category`, + * `description`, `mpn`, `preview_image_url`, `footprint`, and `manufacturing_status`. + * + * @return int The calculated completeness score, with a higher score indicating more complete information. + */ + private function calculateCompleteness(object $part): int + { + // Counts the number of elements in each field that can have multiple values + $paramsCount = is_array($part->parameters) ? count($part->parameters) : 0; + $datasheetsCount = is_array($part->datasheets) ? count($part->datasheets) : 0; + $imagesCount = is_array($part->images) ? count($part->images) : 0; + $vendorInfosCount = is_array($part->vendor_infos) ? count($part->vendor_infos) : 0; + + // Check for the presence of single fields and assign a score + $categoryScore = !empty($part->category) ? 1 : 0; + $descriptionScore = !empty($part->description) ? 1 : 0; + $mpnScore = !empty($part->mpn) ? 1 : 0; + $previewImageScore = !empty($part->preview_image_url) ? 1 : 0; + $footprintScore = !empty($part->footprint) ? 1 : 0; + + // Weight for manufacturing_status: higher if null + $manufacturingStatusScore = is_null($part->manufacturing_status) ? 2 : 1; + + // Sum the counts and scores to obtain a completeness score + return $paramsCount + + $datasheetsCount + + $imagesCount + + $vendorInfosCount + + $categoryScore + + $descriptionScore + + $mpnScore + + $previewImageScore + + $footprintScore + + $manufacturingStatusScore; + } + + + /** + * Generates a unique provider ID by concatenating the part number and manufacturer name, + * separated by a pipe (`|`). The generated ID is typically used to uniquely identify + * a specific part from a particular manufacturer. + * + * @param string $partNumber The part number of the product. + * @param string $manufacturer The name of the manufacturer. + * + * @return string The generated provider ID, in the format "partNumber|manufacturer". + */ + private function generateProviderId(string $partNumber, string $manufacturer): string + { + return trim($partNumber) . '|' . trim($manufacturer); + } + + /** + * Maps the name of a country to its corresponding ISO 3166-1 alpha-2 code. + * + * @param string|null $countryName The name of the country to map. + * @return string|null The ISO code for the country, or null if not found. + */ + private function mapCountryNameToCode(?string $countryName): ?string + { + return $this->countryNameToCodeMap[$countryName] ?? null; + } + + /** + * Removes the analytics tracking parts from the URLs returned by the API. + * + * @param string|null $url + * @return string|null + */ + private function unwrapURL(?string $url): ?string + { + if ($url === null) { + return null; + } + + //Check if the URL is a one redirected via analytics + if (str_contains($url, 'analytics.oemsecrets.com/main.php')) { + //Extract the URL from the analytics URL + $queryParams = []; + parse_str(parse_url($url, PHP_URL_QUERY), $queryParams); + + //The real URL is stored in the 'event_link' query parameter + if (isset($queryParams['event_link']) && trim($queryParams['event_link']) !== '') { + $url = $queryParams['event_link']; + + //Replace any spaces in the URL by %20 to avoid invalid URLs + return str_replace(' ', '%20', $url); + } + } + + //Otherwise return the URL as it is + return $url; + } + +} \ No newline at end of file diff --git a/src/Services/InfoProviderSystem/Providers/OctopartProvider.php b/src/Services/InfoProviderSystem/Providers/OctopartProvider.php index 721830c3..e28162ba 100644 --- a/src/Services/InfoProviderSystem/Providers/OctopartProvider.php +++ b/src/Services/InfoProviderSystem/Providers/OctopartProvider.php @@ -31,7 +31,6 @@ use App\Services\InfoProviderSystem\DTOs\PriceDTO; use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; use App\Services\OAuth\OAuthTokenManager; use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\HttpClient\HttpOptions; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -184,7 +183,7 @@ class OctopartProvider implements InfoProviderInterface { //The client ID has to be set and a token has to be available (user clicked connect) //return /*!empty($this->clientId) && */ $this->authTokenManager->hasToken(self::OAUTH_APP_NAME); - return !empty($this->clientId) && !empty($this->secret); + return $this->clientId !== '' && $this->secret !== ''; } private function mapLifeCycleStatus(?string $value): ?ManufacturingStatus @@ -210,7 +209,7 @@ class OctopartProvider implements InfoProviderInterface $item = $this->partInfoCache->getItem($key); $item->set($part); - $item->expiresAfter(3600 * 24 * 1); //Cache for 1 day + $item->expiresAfter(3600 * 24); //Cache for 1 day $this->partInfoCache->save($item); } @@ -244,11 +243,14 @@ class OctopartProvider implements InfoProviderInterface //If we encounter the mass spec, we save it for later if ($spec['attribute']['shortname'] === "weight") { $mass = (float) $spec['siValue']; - } else if ($spec['attribute']['shortname'] === "case_package") { //Package + } elseif ($spec['attribute']['shortname'] === "case_package") { + //Package $package = $spec['value']; - } else if ($spec['attribute']['shortname'] === "numberofpins") { //Pin Count + } elseif ($spec['attribute']['shortname'] === "numberofpins") { + //Pin Count $pinCount = $spec['value']; - } else if ($spec['attribute']['shortname'] === "lifecyclestatus") { //LifeCycleStatus + } elseif ($spec['attribute']['shortname'] === "lifecyclestatus") { + //LifeCycleStatus $mStatus = $this->mapLifeCycleStatus($spec['value']); } @@ -295,8 +297,8 @@ class OctopartProvider implements InfoProviderInterface //Built the category full path $category = null; if (!empty($part['category']['name'])) { - $category = implode(' -> ', array_map(fn($c) => $c['name'], $part['category']['ancestors'] ?? [])); - if (!empty($category)) { + $category = implode(' -> ', array_map(static fn($c) => $c['name'], $part['category']['ancestors'] ?? [])); + if ($category !== '' && $category !== '0') { $category .= ' -> '; } $category .= $part['category']['name']; diff --git a/src/Services/InfoProviderSystem/Providers/PollinProvider.php b/src/Services/InfoProviderSystem/Providers/PollinProvider.php new file mode 100644 index 00000000..09ab8fd4 --- /dev/null +++ b/src/Services/InfoProviderSystem/Providers/PollinProvider.php @@ -0,0 +1,249 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\InfoProviderSystem\Providers; + +use App\Entity\Parts\ManufacturingStatus; +use App\Entity\Parts\Part; +use App\Services\InfoProviderSystem\DTOs\FileDTO; +use App\Services\InfoProviderSystem\DTOs\ParameterDTO; +use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; +use App\Services\InfoProviderSystem\DTOs\PriceDTO; +use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; +use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class PollinProvider implements InfoProviderInterface +{ + + public function __construct(private readonly HttpClientInterface $client, + #[Autowire(env: 'bool:PROVIDER_POLLIN_ENABLED')] + private readonly bool $enabled = true, + ) + { + } + + public function getProviderInfo(): array + { + return [ + 'name' => 'Pollin', + 'description' => 'Webscraping from pollin.de to get part information', + 'url' => 'https://www.pollin.de/', + 'disabled_help' => 'Set PROVIDER_POLLIN_ENABLED env to 1' + ]; + } + + public function getProviderKey(): string + { + return 'pollin'; + } + + public function isActive(): bool + { + return $this->enabled; + } + + public function searchByKeyword(string $keyword): array + { + $response = $this->client->request('GET', 'https://www.pollin.de/search', [ + 'query' => [ + 'search' => $keyword + ] + ]); + + $content = $response->getContent(); + + //If the response has us redirected to the product page, then just return the single item + if ($response->getInfo('redirect_count') > 0) { + return [$this->parseProductPage($content)]; + } + + $dom = new Crawler($content); + + $results = []; + + //Iterate over each div.product-box + $dom->filter('div.product-box')->each(function (Crawler $node) use (&$results) { + $results[] = new SearchResultDTO( + provider_key: $this->getProviderKey(), + provider_id: $node->filter('meta[itemprop="productID"]')->attr('content'), + name: $node->filter('a.product-name')->text(), + description: '', + preview_image_url: $node->filter('img.product-image')->attr('src'), + manufacturing_status: $this->mapAvailability($node->filter('link[itemprop="availability"]')->attr('href')), + provider_url: $node->filter('a.product-name')->attr('href') + ); + }); + + return $results; + } + + private function mapAvailability(string $availabilityURI): ManufacturingStatus + { + return match( $availabilityURI) { + 'http://schema.org/InStock' => ManufacturingStatus::ACTIVE, + 'http://schema.org/OutOfStock' => ManufacturingStatus::DISCONTINUED, + default => ManufacturingStatus::NOT_SET + }; + } + + public function getDetails(string $id): PartDetailDTO + { + //Ensure that $id is numeric + if (!is_numeric($id)) { + throw new \InvalidArgumentException("The id must be numeric!"); + } + + $response = $this->client->request('GET', 'https://www.pollin.de/search', [ + 'query' => [ + 'search' => $id + ] + ]); + + //The response must have us redirected to the product page + if ($response->getInfo('redirect_count') > 0) { + throw new \RuntimeException("Could not resolve the product page for the given id!"); + } + + $content = $response->getContent(); + + return $this->parseProductPage($content); + } + + private function parseProductPage(string $content): PartDetailDTO + { + $dom = new Crawler($content); + + $productPageUrl = $dom->filter('meta[property="product:product_link"]')->attr('content'); + $orderId = trim($dom->filter('span[itemprop="sku"]')->text()); //Text is important here + + //Calculate the mass + $massStr = $dom->filter('meta[itemprop="weight"]')->attr('content'); + //Remove the unit + $massStr = str_replace('kg', '', $massStr); + //Convert to float and convert to grams + $mass = (float) $massStr * 1000; + + //Parse purchase info + $purchaseInfo = new PurchaseInfoDTO('Pollin', $orderId, $this->parsePrices($dom), $productPageUrl); + + return new PartDetailDTO( + provider_key: $this->getProviderKey(), + provider_id: $orderId, + name: trim($dom->filter('meta[property="og:title"]')->attr('content')), + description: $dom->filter('meta[property="og:description"]')->attr('content'), + category: $this->parseCategory($dom), + manufacturer: $dom->filter('meta[property="product:brand"]')->count() > 0 ? $dom->filter('meta[property="product:brand"]')->attr('content') : null, + preview_image_url: $dom->filter('meta[property="og:image"]')->attr('content'), + manufacturing_status: $this->mapAvailability($dom->filter('link[itemprop="availability"]')->attr('href')), + provider_url: $productPageUrl, + notes: $this->parseNotes($dom), + datasheets: $this->parseDatasheets($dom), + parameters: $this->parseParameters($dom), + vendor_infos: [$purchaseInfo], + mass: $mass, + ); + } + + private function parseDatasheets(Crawler $dom): array + { + //Iterate over each a element withing div.pol-product-detail-download-files + $datasheets = []; + $dom->filter('div.pol-product-detail-download-files a')->each(function (Crawler $node) use (&$datasheets) { + $datasheets[] = new FileDTO($node->attr('href'), $node->text()); + }); + + return $datasheets; + } + + private function parseParameters(Crawler $dom): array + { + $parameters = []; + + //Iterate over each tr.properties-row inside table.product-detail-properties-table + $dom->filter('table.product-detail-properties-table tr.properties-row')->each(function (Crawler $node) use (&$parameters) { + $parameters[] = ParameterDTO::parseValueIncludingUnit( + name: rtrim($node->filter('th.properties-label')->text(), ':'), + value: trim($node->filter('td.properties-value')->text()) + ); + }); + + return $parameters; + } + + private function parseCategory(Crawler $dom): string + { + $category = ''; + + //Iterate over each li.breadcrumb-item inside ol.breadcrumb + $dom->filter('ol.breadcrumb li.breadcrumb-item')->each(function (Crawler $node) use (&$category) { + //Skip if it has breadcrumb-item-home class + if (str_contains($node->attr('class'), 'breadcrumb-item-home')) { + return; + } + + + $category .= $node->text() . ' -> '; + }); + + //Remove the last ' -> ' + return substr($category, 0, -4); + } + + private function parseNotes(Crawler $dom): string + { + //Concat product highlights and product description + return $dom->filter('div.product-detail-top-features')->html('') . '

' . $dom->filter('div.product-detail-description-text')->html(''); + } + + private function parsePrices(Crawler $dom): array + { + //TODO: Properly handle multiple prices, for now we just look at the price for one piece + + //We assume the currency is always the same + $currency = $dom->filter('meta[property="product:price:currency"]')->attr('content'); + + //If there is meta[property=highPrice] then use this as the price + if ($dom->filter('meta[itemprop="highPrice"]')->count() > 0) { + $price = $dom->filter('meta[itemprop="highPrice"]')->attr('content'); + } else { + $price = $dom->filter('meta[property="product:price:amount"]')->attr('content'); + } + + return [ + new PriceDTO(1.0, $price, $currency) + ]; + } + + public function getCapabilities(): array + { + return [ + ProviderCapabilities::BASIC, + ProviderCapabilities::PICTURE, + ProviderCapabilities::PRICE, + ProviderCapabilities::DATASHEET + ]; + } +} \ No newline at end of file diff --git a/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php b/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php new file mode 100644 index 00000000..0c31c411 --- /dev/null +++ b/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php @@ -0,0 +1,285 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\InfoProviderSystem\Providers; + +use App\Services\InfoProviderSystem\DTOs\FileDTO; +use App\Services\InfoProviderSystem\DTOs\ParameterDTO; +use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; +use App\Services\InfoProviderSystem\DTOs\PriceDTO; +use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; +use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class ReicheltProvider implements InfoProviderInterface +{ + + public const DISTRIBUTOR_NAME = "Reichelt"; + + public function __construct(private readonly HttpClientInterface $client, + #[Autowire(env: "bool:PROVIDER_REICHELT_ENABLED")] + private readonly bool $enabled = true, + #[Autowire(env: "PROVIDER_REICHELT_LANGUAGE")] + private readonly string $language = "en", + #[Autowire(env: "PROVIDER_REICHELT_COUNTRY")] + private readonly string $country = "DE", + #[Autowire(env: "PROVIDER_REICHELT_INCLUDE_VAT")] + private readonly bool $includeVAT = false, + #[Autowire(env: "PROVIDER_REICHELT_CURRENCY")] + private readonly string $currency = "EUR", + ) + { + } + + public function getProviderInfo(): array + { + return [ + 'name' => 'Reichelt', + 'description' => 'Webscraping from reichelt.com to get part information', + 'url' => 'https://www.reichelt.com/', + 'disabled_help' => 'Set PROVIDER_REICHELT_ENABLED env to 1' + ]; + } + + public function getProviderKey(): string + { + return 'reichelt'; + } + + public function isActive(): bool + { + return $this->enabled; + } + + public function searchByKeyword(string $keyword): array + { + $response = $this->client->request('GET', sprintf($this->getBaseURL() . '/shop/search/%s', $keyword)); + $html = $response->getContent(); + + //Parse the HTML and return the results + $dom = new Crawler($html); + //Iterate over all div.al_gallery_article elements + $results = []; + $dom->filter('div.al_gallery_article')->each(function (Crawler $element) use (&$results) { + + //Extract product id from data-product attribute + $artId = json_decode($element->attr('data-product'), true, 2, JSON_THROW_ON_ERROR)['artid']; + + $productID = $element->filter('meta[itemprop="productID"]')->attr('content'); + $name = $element->filter('meta[itemprop="name"]')->attr('content'); + $sku = $element->filter('meta[itemprop="sku"]')->attr('content'); + + //Try to extract a picture URL: + $pictureURL = $element->filter("div.al_artlogo img")->attr('src'); + + $results[] = new SearchResultDTO( + provider_key: $this->getProviderKey(), + provider_id: $artId, + name: $productID, + description: $name, + category: null, + manufacturer: $sku, + preview_image_url: $pictureURL, + provider_url: $element->filter('a.al_artinfo_link')->attr('href') + ); + }); + + return $results; + } + + public function getDetails(string $id): PartDetailDTO + { + //Check that the ID is a number + if (!is_numeric($id)) { + throw new \InvalidArgumentException("Invalid ID"); + } + + //Use this endpoint to resolve the artID to a product page + $response = $this->client->request('GET', + sprintf( + 'https://www.reichelt.com/?ACTION=514&id=74&article=%s&LANGUAGE=%s&CCOUNTRY=%s', + $id, + strtoupper($this->language), + strtoupper($this->country) + ) + ); + $json = $response->toArray(); + + //Retrieve the product page from the response + $productPage = $this->getBaseURL() . '/shop/product' . $json[0]['article_path']; + + + $response = $this->client->request('GET', $productPage, [ + 'query' => [ + 'CCTYPE' => $this->includeVAT ? 'private' : 'business', + 'currency' => $this->currency, + ], + ]); + $html = $response->getContent(); + $dom = new Crawler($html); + + //Extract the product notes + $notes = $dom->filter('p[itemprop="description"]')->html(); + + //Extract datasheets + $datasheets = []; + $dom->filter('div.articleDatasheet a')->each(function (Crawler $element) use (&$datasheets) { + $datasheets[] = new FileDTO($element->attr('href'), $element->filter('span')->text()); + }); + + //Determine price for one unit + $priceString = $dom->filter('meta[itemprop="price"]')->attr('content'); + $currency = $dom->filter('meta[itemprop="priceCurrency"]')->attr('content', 'EUR'); + + //Create purchase info + $purchaseInfo = new PurchaseInfoDTO( + distributor_name: self::DISTRIBUTOR_NAME, + order_number: $json[0]['article_artnr'], + prices: array_merge( + [new PriceDTO(1.0, $priceString, $currency, $this->includeVAT)] + , $this->parseBatchPrices($dom, $currency)), + product_url: $productPage + ); + + //Create part object + return new PartDetailDTO( + provider_key: $this->getProviderKey(), + provider_id: $id, + name: $json[0]['article_artnr'], + description: $json[0]['article_besch'], + category: $this->parseCategory($dom), + manufacturer: $json[0]['manufacturer_name'], + mpn: $this->parseMPN($dom), + preview_image_url: $json[0]['article_picture'], + provider_url: $productPage, + notes: $notes, + datasheets: $datasheets, + parameters: $this->parseParameters($dom), + vendor_infos: [$purchaseInfo] + ); + + } + + private function parseMPN(Crawler $dom): string + { + //Find the small element directly after meta[itemprop="url"] element + $element = $dom->filter('meta[itemprop="url"] + small'); + //If the text contains GTIN text, take the small element afterwards + if (str_contains($element->text(), 'GTIN')) { + $element = $dom->filter('meta[itemprop="url"] + small + small'); + } + + //The MPN is contained in the span inside the element + return $element->filter('span')->text(); + } + + private function parseBatchPrices(Crawler $dom, string $currency): array + { + //Iterate over each a.inline-block element in div.discountValue + $prices = []; + $dom->filter('div.discountValue a.inline-block')->each(function (Crawler $element) use (&$prices, $currency) { + //The minimum amount is the number in the span.block element + $minAmountText = $element->filter('span.block')->text(); + + //Extract a integer from the text + $matches = []; + if (!preg_match('/\d+/', $minAmountText, $matches)) { + return; + } + + $minAmount = (int) $matches[0]; + + //The price is the text of the p.productPrice element + $priceString = $element->filter('p.productPrice')->text(); + //Replace comma with dot + $priceString = str_replace(',', '.', $priceString); + //Strip any non-numeric characters + $priceString = preg_replace('/[^0-9.]/', '', $priceString); + + $prices[] = new PriceDTO($minAmount, $priceString, $currency, $this->includeVAT); + }); + + return $prices; + } + + + private function parseCategory(Crawler $dom): string + { + // Look for ol.breadcrumb and iterate over the li elements + $category = ''; + $dom->filter('ol.breadcrumb li.triangle-left')->each(function (Crawler $element) use (&$category) { + //Do not include the .breadcrumb-showmore element + if ($element->attr('id') === 'breadcrumb-showmore') { + return; + } + + $category .= $element->text() . ' -> '; + }); + //Remove the trailing ' -> ' + $category = substr($category, 0, -4); + + return $category; + } + + /** + * @param Crawler $dom + * @return ParameterDTO[] + */ + private function parseParameters(Crawler $dom): array + { + $parameters = []; + //Iterate over each ul.articleTechnicalData which contains the specifications of each group + $dom->filter('ul.articleTechnicalData')->each(function (Crawler $groupElement) use (&$parameters) { + $groupName = $groupElement->filter('li.articleTechnicalHeadline')->text(); + + //Iterate over each second li in ul.articleAttribute, which contains the specifications + $groupElement->filter('ul.articleAttribute li:nth-child(2n)')->each(function (Crawler $specElement) use (&$parameters, $groupName) { + $parameters[] = ParameterDTO::parseValueIncludingUnit( + name: $specElement->previousAll()->text(), + value: $specElement->text(), + group: $groupName + ); + }); + }); + + return $parameters; + } + + private function getBaseURL(): string + { + //Without the trailing slash + return 'https://www.reichelt.com/' . strtolower($this->country) . '/' . strtolower($this->language); + } + + public function getCapabilities(): array + { + return [ + ProviderCapabilities::BASIC, + ProviderCapabilities::PICTURE, + ProviderCapabilities::DATASHEET, + ProviderCapabilities::PRICE, + ]; + } +} \ No newline at end of file diff --git a/src/Services/InfoProviderSystem/Providers/TMEClient.php b/src/Services/InfoProviderSystem/Providers/TMEClient.php index 8c2a4430..d4df133e 100644 --- a/src/Services/InfoProviderSystem/Providers/TMEClient.php +++ b/src/Services/InfoProviderSystem/Providers/TMEClient.php @@ -23,10 +23,8 @@ declare(strict_types=1); namespace App\Services\InfoProviderSystem\Providers; -use Symfony\Component\HttpClient\DecoratorTrait; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; -use Symfony\Contracts\HttpClient\ResponseStreamInterface; class TMEClient { @@ -49,13 +47,19 @@ class TMEClient public function isUsable(): bool { - if ($this->token === '' || $this->secret === '') { - return false; - } - - return true; + return $this->token !== '' && $this->secret !== ''; } + /** + * Returns true if the client is using a private (account related token) instead of a deprecated anonymous token + * to authenticate with TME. + * @return bool + */ + public function isUsingPrivateToken(): bool + { + //Private tokens are longer than anonymous ones (50 instead of 45 characters) + return strlen($this->token) > 45; + } /** * Generates the signature for the given action and parameters. diff --git a/src/Services/InfoProviderSystem/Providers/TMEProvider.php b/src/Services/InfoProviderSystem/Providers/TMEProvider.php index 2d12b222..32fc0c72 100644 --- a/src/Services/InfoProviderSystem/Providers/TMEProvider.php +++ b/src/Services/InfoProviderSystem/Providers/TMEProvider.php @@ -24,26 +24,31 @@ declare(strict_types=1); namespace App\Services\InfoProviderSystem\Providers; use App\Entity\Parts\ManufacturingStatus; -use App\Entity\Parts\Part; use App\Services\InfoProviderSystem\DTOs\FileDTO; use App\Services\InfoProviderSystem\DTOs\ParameterDTO; use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; use App\Services\InfoProviderSystem\DTOs\PriceDTO; use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; -use Symfony\Contracts\HttpClient\HttpClientInterface; class TMEProvider implements InfoProviderInterface { private const VENDOR_NAME = 'TME'; + /** @var bool If true, the prices are gross prices. If false, the prices are net prices. */ + private readonly bool $get_gross_prices; + public function __construct(private readonly TMEClient $tmeClient, private readonly string $country, private readonly string $language, private readonly string $currency, - /** @var bool If true, the prices are gross prices. If false, the prices are net prices. */ - private readonly bool $get_gross_prices) + bool $get_gross_prices) { - + //If we have a private token, set get_gross_prices to false, as it is automatically determined by the account type then + if ($this->tmeClient->isUsingPrivateToken()) { + $this->get_gross_prices = false; + } else { + $this->get_gross_prices = $get_gross_prices; + } } public function getProviderInfo(): array @@ -82,7 +87,7 @@ class TMEProvider implements InfoProviderInterface $result[] = new SearchResultDTO( provider_key: $this->getProviderKey(), provider_id: $product['Symbol'], - name: !empty($product['OriginalSymbol']) ? $product['OriginalSymbol'] : $product['Symbol'], + name: empty($product['OriginalSymbol']) ? $product['Symbol'] : $product['OriginalSymbol'], description: $product['Description'], category: $product['Category'], manufacturer: $product['Producer'], @@ -118,7 +123,7 @@ class TMEProvider implements InfoProviderInterface return new PartDetailDTO( provider_key: $this->getProviderKey(), provider_id: $product['Symbol'], - name: !empty($product['OriginalSymbol']) ? $product['OriginalSymbol'] : $product['Symbol'], + name: empty($product['OriginalSymbol']) ? $product['Symbol'] : $product['OriginalSymbol'], description: $product['Description'], category: $product['Category'], manufacturer: $product['Producer'], diff --git a/src/Services/LabelSystem/BarcodeScanner/BarcodeRedirector.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeRedirector.php new file mode 100644 index 00000000..2de7c035 --- /dev/null +++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeRedirector.php @@ -0,0 +1,166 @@ +. + */ + +declare(strict_types=1); + +/** + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace App\Services\LabelSystem\BarcodeScanner; + +use App\Entity\LabelSystem\LabelSupportedElement; +use App\Entity\Parts\Manufacturer; +use App\Entity\Parts\Part; +use App\Entity\Parts\PartLot; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityNotFoundException; +use InvalidArgumentException; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + +/** + * @see \App\Tests\Services\LabelSystem\Barcodes\BarcodeRedirectorTest + */ +final class BarcodeRedirector +{ + public function __construct(private readonly UrlGeneratorInterface $urlGenerator, private readonly EntityManagerInterface $em) + { + } + + /** + * Determines the URL to which the user should be redirected, when scanning a QR code. + * + * @param BarcodeScanResultInterface $barcodeScan The result of the barcode scan + * @return string the URL to which should be redirected + * + * @throws EntityNotFoundException + */ + public function getRedirectURL(BarcodeScanResultInterface $barcodeScan): string + { + if($barcodeScan instanceof LocalBarcodeScanResult) { + return $this->getURLLocalBarcode($barcodeScan); + } + + if ($barcodeScan instanceof EIGP114BarcodeScanResult) { + return $this->getURLVendorBarcode($barcodeScan); + } + + throw new InvalidArgumentException('Unknown $barcodeScan type: '.get_class($barcodeScan)); + } + + private function getURLLocalBarcode(LocalBarcodeScanResult $barcodeScan): string + { + switch ($barcodeScan->target_type) { + case LabelSupportedElement::PART: + return $this->urlGenerator->generate('app_part_show', ['id' => $barcodeScan->target_id]); + case LabelSupportedElement::PART_LOT: + //Try to determine the part to the given lot + $lot = $this->em->find(PartLot::class, $barcodeScan->target_id); + if (!$lot instanceof PartLot) { + throw new EntityNotFoundException(); + } + + return $this->urlGenerator->generate('app_part_show', ['id' => $lot->getPart()->getID()]); + + case LabelSupportedElement::STORELOCATION: + return $this->urlGenerator->generate('part_list_store_location', ['id' => $barcodeScan->target_id]); + + default: + throw new InvalidArgumentException('Unknown $type: '.$barcodeScan->target_type->name); + } + } + + /** + * Gets the URL to a part from a scan of a Vendor Barcode + */ + private function getURLVendorBarcode(EIGP114BarcodeScanResult $barcodeScan): string + { + $part = $this->getPartFromVendor($barcodeScan); + return $this->urlGenerator->generate('app_part_show', ['id' => $part->getID()]); + } + + /** + * Gets a part from a scan of a Vendor Barcode by filtering for parts + * with the same Info Provider Id or, if that fails, by looking for parts with a + * matching manufacturer product number. Only returns the first matching part. + */ + private function getPartFromVendor(EIGP114BarcodeScanResult $barcodeScan) : Part + { + // first check via the info provider ID (e.g. Vendor ID). This might fail if the part was not added via + // the info provider system or if the part was bought from a different vendor than the data was retrieved + // from. + if($barcodeScan->digikeyPartNumber) { + $qb = $this->em->getRepository(Part::class)->createQueryBuilder('part'); + //Lower() to be case insensitive + $qb->where($qb->expr()->like('LOWER(part.providerReference.provider_id)', 'LOWER(:vendor_id)')); + $qb->setParameter('vendor_id', $barcodeScan->digikeyPartNumber); + $results = $qb->getQuery()->getResult(); + if ($results) { + return $results[0]; + } + } + + if(!$barcodeScan->supplierPartNumber){ + throw new EntityNotFoundException(); + } + + //Fallback to the manufacturer part number. This may return false positives, since it is common for + //multiple manufacturers to use the same part number for their version of a common product + //We assume the user is able to realize when this returns the wrong part + //If the barcode specifies the manufacturer we try to use that as well + $mpnQb = $this->em->getRepository(Part::class)->createQueryBuilder('part'); + $mpnQb->where($mpnQb->expr()->like('LOWER(part.manufacturer_product_number)', 'LOWER(:mpn)')); + $mpnQb->setParameter('mpn', $barcodeScan->supplierPartNumber); + + if($barcodeScan->mouserManufacturer){ + $manufacturerQb = $this->em->getRepository(Manufacturer::class)->createQueryBuilder("manufacturer"); + $manufacturerQb->where($manufacturerQb->expr()->like("LOWER(manufacturer.name)", "LOWER(:manufacturer_name)")); + $manufacturerQb->setParameter("manufacturer_name", $barcodeScan->mouserManufacturer); + $manufacturers = $manufacturerQb->getQuery()->getResult(); + + if($manufacturers) { + $mpnQb->andWhere($mpnQb->expr()->eq("part.manufacturer", ":manufacturer")); + $mpnQb->setParameter("manufacturer", $manufacturers); + } + + } + + $results = $mpnQb->getQuery()->getResult(); + if($results){ + return $results[0]; + } + throw new EntityNotFoundException(); + } +} diff --git a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php new file mode 100644 index 00000000..e5930b36 --- /dev/null +++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanHelper.php @@ -0,0 +1,243 @@ +. + */ + +declare(strict_types=1); + +/** + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace App\Services\LabelSystem\BarcodeScanner; + +use App\Entity\LabelSystem\LabelSupportedElement; +use App\Entity\Parts\Part; +use App\Entity\Parts\PartLot; +use Doctrine\ORM\EntityManagerInterface; +use InvalidArgumentException; + +/** + * @see \App\Tests\Services\LabelSystem\Barcodes\BarcodeScanHelperTest + */ +final class BarcodeScanHelper +{ + private const PREFIX_TYPE_MAP = [ + 'L' => LabelSupportedElement::PART_LOT, + 'P' => LabelSupportedElement::PART, + 'S' => LabelSupportedElement::STORELOCATION, + ]; + + public const QR_TYPE_MAP = [ + 'lot' => LabelSupportedElement::PART_LOT, + 'part' => LabelSupportedElement::PART, + 'location' => LabelSupportedElement::STORELOCATION, + ]; + + public function __construct(private readonly EntityManagerInterface $entityManager) + { + } + + /** + * Parse the given barcode content and return the target type and ID. + * If the barcode could not be parsed, an exception is thrown. + * Using the $type parameter, you can specify how the barcode should be parsed. If set to null, the function + * will try to guess the type. + * @param string $input + * @param BarcodeSourceType|null $type + * @return BarcodeScanResultInterface + */ + public function scanBarcodeContent(string $input, ?BarcodeSourceType $type = null): BarcodeScanResultInterface + { + //Do specific parsing + if ($type === BarcodeSourceType::INTERNAL) { + return $this->parseInternalBarcode($input) ?? throw new InvalidArgumentException('Could not parse barcode'); + } + if ($type === BarcodeSourceType::USER_DEFINED) { + return $this->parseUserDefinedBarcode($input) ?? throw new InvalidArgumentException('Could not parse barcode'); + } + if ($type === BarcodeSourceType::IPN) { + return $this->parseIPNBarcode($input) ?? throw new InvalidArgumentException('Could not parse barcode'); + } + if ($type === BarcodeSourceType::EIGP114) { + return $this->parseEIGP114Barcode($input); + } + + //Null means auto and we try the different formats + $result = $this->parseInternalBarcode($input); + + if ($result !== null) { + return $result; + } + + //Try to parse as User defined barcode + $result = $this->parseUserDefinedBarcode($input); + if ($result !== null) { + return $result; + } + + //If the barcode is formatted as EIGP114, we can parse it directly + if (EIGP114BarcodeScanResult::isFormat06Code($input)) { + return $this->parseEIGP114Barcode($input); + } + + //Try to parse as IPN barcode + $result = $this->parseIPNBarcode($input); + if ($result !== null) { + return $result; + } + + throw new InvalidArgumentException('Unknown barcode'); + } + + private function parseEIGP114Barcode(string $input): EIGP114BarcodeScanResult + { + return EIGP114BarcodeScanResult::parseFormat06Code($input); + } + + private function parseUserDefinedBarcode(string $input): ?LocalBarcodeScanResult + { + $lot_repo = $this->entityManager->getRepository(PartLot::class); + //Find only the first result + $results = $lot_repo->findBy(['user_barcode' => $input], limit: 1); + + if (count($results) === 0) { + return null; + } + //We found a part, so use it to create the result + $lot = $results[0]; + + return new LocalBarcodeScanResult( + target_type: LabelSupportedElement::PART_LOT, + target_id: $lot->getID(), + source_type: BarcodeSourceType::USER_DEFINED + ); + } + + private function parseIPNBarcode(string $input): ?LocalBarcodeScanResult + { + $part_repo = $this->entityManager->getRepository(Part::class); + //Find only the first result + $results = $part_repo->findBy(['ipn' => $input], limit: 1); + + if (count($results) === 0) { + return null; + } + //We found a part, so use it to create the result + $part = $results[0]; + + return new LocalBarcodeScanResult( + target_type: LabelSupportedElement::PART, + target_id: $part->getID(), + source_type: BarcodeSourceType::IPN + ); + } + + /** + * This function tries to interpret the given barcode content as an internal barcode. + * If the barcode could not be parsed at all, null is returned. If the barcode is a valid format, but could + * not be found in the database, an exception is thrown. + * @param string $input + * @return LocalBarcodeScanResult|null + */ + private function parseInternalBarcode(string $input): ?LocalBarcodeScanResult + { + $input = trim($input); + $matches = []; + + //Some scanner output '-' as ß, so replace it (ß is never used, so we can replace it safely) + $input = str_replace('ß', '-', $input); + + //Extract parts from QR code's URL + if (preg_match('#^https?://.*/scan/(\w+)/(\d+)/?$#', $input, $matches)) { + return new LocalBarcodeScanResult( + target_type: self::QR_TYPE_MAP[strtolower($matches[1])], + target_id: (int) $matches[2], + source_type: BarcodeSourceType::INTERNAL + ); + } + + //New Code39 barcode use L0001 format + if (preg_match('#^([A-Z])(\d{4,})$#', $input, $matches)) { + $prefix = $matches[1]; + $id = (int) $matches[2]; + + if (!isset(self::PREFIX_TYPE_MAP[$prefix])) { + throw new InvalidArgumentException('Unknown prefix '.$prefix); + } + + return new LocalBarcodeScanResult( + target_type: self::PREFIX_TYPE_MAP[$prefix], + target_id: $id, + source_type: BarcodeSourceType::INTERNAL + ); + } + + //During development the L-000001 format was used + if (preg_match('#^(\w)-(\d{6,})$#', $input, $matches)) { + $prefix = $matches[1]; + $id = (int) $matches[2]; + + if (!isset(self::PREFIX_TYPE_MAP[$prefix])) { + throw new InvalidArgumentException('Unknown prefix '.$prefix); + } + + return new LocalBarcodeScanResult( + target_type: self::PREFIX_TYPE_MAP[$prefix], + target_id: $id, + source_type: BarcodeSourceType::INTERNAL + ); + } + + //Legacy Part-DB location labels used $L00336 format + if (preg_match('#^\$L(\d{5,})$#', $input, $matches)) { + return new LocalBarcodeScanResult( + target_type: LabelSupportedElement::STORELOCATION, + target_id: (int) $matches[1], + source_type: BarcodeSourceType::INTERNAL + ); + } + + //Legacy Part-DB used EAN8 barcodes for part labels. Format 0000001(2) (note the optional 8th digit => checksum) + if (preg_match('#^(\d{7})\d?$#', $input, $matches)) { + return new LocalBarcodeScanResult( + target_type: LabelSupportedElement::PART, + target_id: (int) $matches[1], + source_type: BarcodeSourceType::INTERNAL + ); + } + + //This function abstain from further parsing + return null; + } +} diff --git a/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultInterface.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultInterface.php new file mode 100644 index 00000000..88130351 --- /dev/null +++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeScanResultInterface.php @@ -0,0 +1,36 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\LabelSystem\BarcodeScanner; + +interface BarcodeScanResultInterface +{ + /** + * Returns all data that was decoded from the barcode in a format, that can be shown in a table to the user. + * The return values of this function are not meant to be parsed by code again, but should just give a information + * to the user. + * The keys of the returned array are the first column of the table and the values are the second column. + * @return array + */ + public function getDecodedForInfoMode(): array; +} \ No newline at end of file diff --git a/src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php b/src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php new file mode 100644 index 00000000..40f707de --- /dev/null +++ b/src/Services/LabelSystem/BarcodeScanner/BarcodeSourceType.php @@ -0,0 +1,45 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\LabelSystem\BarcodeScanner; + +/** + * This enum represents the different types, where a barcode/QR-code can be generated from + */ +enum BarcodeSourceType +{ + /** This Barcode was generated using Part-DB internal recommended barcode generator */ + case INTERNAL; + /** This barcode is containing an internal part number (IPN) */ + case IPN; + + /** + * This barcode is a user defined barcode defined on a part lot + */ + case USER_DEFINED; + + /** + * EIGP114 formatted barcodes like used by digikey, mouser, etc. + */ + case EIGP114; +} \ No newline at end of file diff --git a/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php b/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php new file mode 100644 index 00000000..0b4f4b56 --- /dev/null +++ b/src/Services/LabelSystem/BarcodeScanner/EIGP114BarcodeScanResult.php @@ -0,0 +1,332 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\LabelSystem\BarcodeScanner; + +/** + * This class represents the content of a EIGP114 barcode. + * Based on PR 811, EIGP 114.2018 (https://www.ecianow.org/assets/docs/GIPC/EIGP-114.2018%20ECIA%20Labeling%20Specification%20for%20Product%20and%20Shipment%20Identification%20in%20the%20Electronics%20Industry%20-%202D%20Barcode.pdf), + * , https://forum.digikey.com/t/digikey-product-labels-decoding-digikey-barcodes/41097 + */ +class EIGP114BarcodeScanResult implements BarcodeScanResultInterface +{ + + /** + * @var string|null Ship date in format YYYYMMDD + */ + public readonly ?string $shipDate; + + /** + * @var string|null Customer assigned part number – Optional based on + * agreements between Distributor and Supplier + */ + public readonly ?string $customerPartNumber; + + /** + * @var string|null Supplier assigned part number + */ + public readonly ?string $supplierPartNumber; + + /** + * @var int|null Quantity of product + */ + public readonly ?int $quantity; + + /** + * @var string|null Customer assigned purchase order number + */ + public readonly ?string $customerPO; + + /** + * @var string|null Line item number from PO. Required on Logistic Label when + * used on back of Packing Slip. See Section 4.9 + */ + public readonly ?string $customerPOLine; + + /** + * 9D - YYWW (Year and Week of Manufacture). ) If no date code is used + * for a particular part, this field should be populated with N/T + * to indicate the product is Not Traceable by this data field. + * @var string|null + */ + public readonly ?string $dateCode; + + /** + * 10D - YYWW (Year and Week of Manufacture). ) If no date code is used + * for a particular part, this field should be populated with N/T + * to indicate the product is Not Traceable by this data field. + * @var string|null + */ + public readonly ?string $alternativeDateCode; + + /** + * Traceability number assigned to a batch or group of items. If + * no lot code is used for a particular part, this field should be + * populated with N/T to indicate the product is Not Traceable + * by this data field. + * @var string|null + */ + public readonly ?string $lotCode; + + /** + * Country where part was manufactured. Two-letter code from + * ISO 3166 country code list + * @var string|null + */ + public readonly ?string $countryOfOrigin; + + /** + * @var string|null Unique alphanumeric number assigned by supplier + * 3S - Package ID for Inner Pack when part of a mixed Logistic + * Carton. Always used in conjunction with a mixed logistic label + * with a 5S data identifier for Package ID. + */ + public readonly ?string $packageId1; + + /** + * @var string|null + * 4S - Package ID for Logistic Carton with like items + */ + public readonly ?string $packageId2; + + /** + * @var string|null + * 5S - Package ID for Logistic Carton with mixed items + */ + public readonly ?string $packageId3; + + /** + * @var string|null Unique alphanumeric number assigned by supplier. + */ + public readonly ?string $packingListNumber; + + /** + * @var string|null Ship date in format YYYYMMDD + */ + public readonly ?string $serialNumber; + + /** + * @var string|null Code for sorting and classifying LEDs. Use when applicable + */ + public readonly ?string $binCode; + + /** + * @var int|null Sequential carton count in format “#/#” or “# of #” + */ + public readonly ?int $packageCount; + + /** + * @var string|null Alphanumeric string assigned by the supplier to distinguish + * from one closely-related design variation to another. Use as + * required or when applicable + */ + public readonly ?string $revisionNumber; + + /** + * @var string|null Digikey Extension: This is not represented in the ECIA spec, but the field being used is found in the ANSI MH10.8.2-2016 spec on which the ECIA spec is based. In the ANSI spec it is called First Level (Supplier Assigned) Part Number. + */ + public readonly ?string $digikeyPartNumber; + + /** + * @var string|null Digikey Extension: This can be shared across multiple invoices and time periods and is generated as an order enters our system from any vector (web, API, phone order, etc.) + */ + public readonly ?string $digikeySalesOrderNumber; + + /** + * @var string|null Digikey extension: This is typically assigned per shipment as items are being released to be picked in the warehouse. A SO can have many Invoice numbers + */ + public readonly ?string $digikeyInvoiceNumber; + + /** + * @var string|null Digikey extension: This is for internal DigiKey purposes and defines the label type. + */ + public readonly ?string $digikeyLabelType; + + /** + * @var string|null You will also see this as the last part of a URL for a product detail page. Ex https://www.digikey.com/en/products/detail/w%C3%BCrth-elektronik/860010672008/5726907 + */ + public readonly ?string $digikeyPartID; + + /** + * @var string|null Digikey Extension: For internal use of Digikey. Probably not needed + */ + public readonly ?string $digikeyNA; + + /** + * @var string|null Digikey Extension: This is a field of varying length used to keep the barcode approximately the same size between labels. It is safe to ignore. + */ + public readonly ?string $digikeyPadding; + + public readonly ?string $mouserPositionInOrder; + + public readonly ?string $mouserManufacturer; + + + + /** + * + * @param array $data The fields of the EIGP114 barcode, where the key is the field name and the value is the field content + */ + public function __construct(public readonly array $data) + { + //IDs per EIGP 114.2018 + $this->shipDate = $data['6D'] ?? null; + $this->customerPartNumber = $data['P'] ?? null; + $this->supplierPartNumber = $data['1P'] ?? null; + $this->quantity = isset($data['Q']) ? (int)$data['Q'] : null; + $this->customerPO = $data['K'] ?? null; + $this->customerPOLine = $data['4K'] ?? null; + $this->dateCode = $data['9D'] ?? null; + $this->alternativeDateCode = $data['10D'] ?? null; + $this->lotCode = $data['1T'] ?? null; + $this->countryOfOrigin = $data['4L'] ?? null; + $this->packageId1 = $data['3S'] ?? null; + $this->packageId2 = $data['4S'] ?? null; + $this->packageId3 = $data['5S'] ?? null; + $this->packingListNumber = $data['11K'] ?? null; + $this->serialNumber = $data['S'] ?? null; + $this->binCode = $data['33P'] ?? null; + $this->packageCount = isset($data['13Q']) ? (int)$data['13Q'] : null; + $this->revisionNumber = $data['2P'] ?? null; + //IDs used by Digikey + $this->digikeyPartNumber = $data['30P'] ?? null; + $this->digikeySalesOrderNumber = $data['1K'] ?? null; + $this->digikeyInvoiceNumber = $data['10K'] ?? null; + $this->digikeyLabelType = $data['11Z'] ?? null; + $this->digikeyPartID = $data['12Z'] ?? null; + $this->digikeyNA = $data['13Z'] ?? null; + $this->digikeyPadding = $data['20Z'] ?? null; + //IDs used by Mouser + $this->mouserPositionInOrder = $data['14K'] ?? null; + $this->mouserManufacturer = $data['1V'] ?? null; + } + + /** + * Tries to guess the vendor of the barcode based on the supplied data field. + * This is experimental and should not be relied upon. + * @return string|null The guessed vendor as smallcase string (e.g. "digikey", "mouser", etc.), or null if the vendor could not be guessed + */ + public function guessBarcodeVendor(): ?string + { + //If the barcode data contains the digikey extensions, we assume it is a digikey barcode + if (isset($this->data['13Z']) || isset($this->data['20Z']) || isset($this->data['12Z']) || isset($this->data['11Z'])) { + return 'digikey'; + } + + //If the barcode data contains the mouser extensions, we assume it is a mouser barcode + if (isset($this->data['14K']) || isset($this->data['1V'])) { + return 'mouser'; + } + + //According to this thread (https://github.com/inventree/InvenTree/issues/853), Newark/element14 codes contains a "3P" field + if (isset($this->data['3P'])) { + return 'element14'; + } + + return null; + } + + /** + * Checks if the given input is a valid format06 formatted data. + * This just perform a simple check for the header, the content might be malformed still. + * @param string $input + * @return bool + */ + public static function isFormat06Code(string $input): bool + { + //Code must begin with [)>06 + if(!str_starts_with($input, "[)>\u{1E}06\u{1D}")){ + return false; + } + + //Digikey does not put a trailer onto the barcode, so we just check for the header + + return true; + } + + /** + * Parses a format06 code a returns a new instance of this class + * @param string $input + * @return self + */ + public static function parseFormat06Code(string $input): self + { + //Ensure that the input is a valid format06 code + if (!self::isFormat06Code($input)) { + throw new \InvalidArgumentException("The given input is not a valid format06 code"); + } + + //Remove the trailer, if present + if (str_ends_with($input, "\u{1E}\u{04}")){ + $input = substr($input, 5, -2); + } + + //Split the input into the different fields (using the separator) + $parts = explode("\u{1D}", $input); + + //The first field is the format identifier, which we do not need + array_shift($parts); + + //Split the fields into key-value pairs + $results = []; + + foreach($parts as $part) { + //^ 0* ([1-9]? \d* [A-Z]) + //Start of the string Leading zeros are discarded Not a zero Any number of digits single uppercase Letter + // 00 1 4 K + + if(!preg_match('/^0*([1-9]?\d*[A-Z])/', $part, $matches)) { + throw new \LogicException("Could not parse field: $part"); + } + //Extract the key + $key = $matches[0]; + //Extract the field value + $fieldValue = substr($part, strlen($matches[0])); + + $results[$key] = $fieldValue; + } + + return new self($results); + } + + public function getDecodedForInfoMode(): array + { + $tmp = [ + 'Barcode type' => 'EIGP114', + 'Guessed vendor from barcode' => $this->guessBarcodeVendor() ?? 'Unknown', + ]; + + //Iterate over all fields of this object and add them to the array if they are not null + foreach((array) $this as $key => $value) { + //Skip data key + if ($key === 'data') { + continue; + } + if($value !== null) { + $tmp[$key] = $value; + } + } + + return $tmp; + } +} \ No newline at end of file diff --git a/src/Services/LabelSystem/BarcodeScanner/LocalBarcodeScanResult.php b/src/Services/LabelSystem/BarcodeScanner/LocalBarcodeScanResult.php new file mode 100644 index 00000000..050aff6f --- /dev/null +++ b/src/Services/LabelSystem/BarcodeScanner/LocalBarcodeScanResult.php @@ -0,0 +1,49 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\LabelSystem\BarcodeScanner; + +use App\Entity\LabelSystem\LabelSupportedElement; + +/** + * This class represents the result of a barcode scan of a barcode that uniquely identifies a local entity, + * like an internally generated barcode or a barcode that was added manually to the system by a user + */ +class LocalBarcodeScanResult implements BarcodeScanResultInterface +{ + public function __construct( + public readonly LabelSupportedElement $target_type, + public readonly int $target_id, + public readonly BarcodeSourceType $source_type, + ) { + } + + public function getDecodedForInfoMode(): array + { + return [ + 'Barcode type' => $this->source_type->name, + 'Target type' => $this->target_type->name, + 'Target ID' => $this->target_id, + ]; + } +} \ No newline at end of file diff --git a/src/Services/LabelSystem/Barcodes/BarcodeContentGenerator.php b/src/Services/LabelSystem/Barcodes/BarcodeContentGenerator.php index 5acf98f1..7ceb30dd 100644 --- a/src/Services/LabelSystem/Barcodes/BarcodeContentGenerator.php +++ b/src/Services/LabelSystem/Barcodes/BarcodeContentGenerator.php @@ -44,7 +44,7 @@ namespace App\Services\LabelSystem\Barcodes; use App\Entity\Base\AbstractDBElement; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use InvalidArgumentException; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -56,13 +56,13 @@ final class BarcodeContentGenerator public const PREFIX_MAP = [ Part::class => 'P', PartLot::class => 'L', - Storelocation::class => 'S', + StorageLocation::class => 'S', ]; private const URL_MAP = [ Part::class => 'part', PartLot::class => 'lot', - Storelocation::class => 'location', + StorageLocation::class => 'location', ]; public function __construct(private readonly UrlGeneratorInterface $urlGenerator) @@ -76,11 +76,11 @@ final class BarcodeContentGenerator { $type = $this->classToString(self::URL_MAP, $target); - return $this->urlGenerator->generate('scan_qr', [ - 'type' => $type, + return $this->urlGenerator->generate('scan_qr', [ + 'type' => $type, 'id' => $target->getID() ?? 0, '_locale' => null, -], UrlGeneratorInterface::ABSOLUTE_URL); + ], UrlGeneratorInterface::ABSOLUTE_URL); } /** diff --git a/src/Services/LabelSystem/Barcodes/BarcodeHelper.php b/src/Services/LabelSystem/Barcodes/BarcodeHelper.php new file mode 100644 index 00000000..c9fe64f3 --- /dev/null +++ b/src/Services/LabelSystem/Barcodes/BarcodeHelper.php @@ -0,0 +1,97 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\LabelSystem\Barcodes; + +use App\Entity\LabelSystem\BarcodeType; +use Com\Tecnick\Barcode\Barcode; + +/** + * This function is used to generate barcodes of various types using arbitrary (text) content. + * @see \App\Tests\Services\LabelSystem\Barcodes\BarcodeHelperTest + */ +class BarcodeHelper +{ + + /** + * Generates a barcode with the given content and type and returns it as SVG string. + * @param string $content + * @param BarcodeType $type + * @return string + */ + public function barcodeAsSVG(string $content, BarcodeType $type): string + { + $barcode = new Barcode(); + + $type_str = match ($type) { + BarcodeType::NONE => throw new \InvalidArgumentException('Barcode type must not be NONE! This would make no sense...'), + BarcodeType::QR => 'QRCODE', + BarcodeType::DATAMATRIX => 'DATAMATRIX', + BarcodeType::CODE39 => 'C39', + BarcodeType::CODE93 => 'C93', + BarcodeType::CODE128 => 'C128A', + }; + + return $barcode->getBarcodeObj($type_str, $content)->getSvgCode(); + } + + /** + * Generates a barcode with the given content and type and returns it as HTML image tag. + * @param string $content + * @param BarcodeType $type + * @param string $width Width of the image tag + * @param string|null $alt_text The alt text of the image tag. If null, the content is used. + * @return string + */ + public function barcodeAsHTML(string $content, BarcodeType $type, string $width = '100%', ?string $alt_text = null): string + { + $svg = $this->barcodeAsSVG($content, $type); + $base64 = $this->dataUri($svg, 'image/svg+xml'); + $alt_text ??= $content; + + return ''.$alt_text.''; + } + + /** + * Creates a data URI (RFC 2397). + * Based on the Twig implementation from HTMLExtension + * + * Length validation is not performed on purpose, validation should + * be done before calling this filter. + * + * @return string The generated data URI + */ + private function dataUri(string $data, string $mime): string + { + $repr = 'data:'; + + $repr .= $mime; + if (str_starts_with($mime, 'text/')) { + $repr .= ','.rawurlencode($data); + } else { + $repr .= ';base64,'.base64_encode($data); + } + + return $repr; + } +} \ No newline at end of file diff --git a/src/Services/LabelSystem/Barcodes/BarcodeNormalizer.php b/src/Services/LabelSystem/Barcodes/BarcodeNormalizer.php deleted file mode 100644 index a5b6cb5e..00000000 --- a/src/Services/LabelSystem/Barcodes/BarcodeNormalizer.php +++ /dev/null @@ -1,110 +0,0 @@ -. - */ - -declare(strict_types=1); - -/** - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -namespace App\Services\LabelSystem\Barcodes; - -use InvalidArgumentException; - -/** - * @see \App\Tests\Services\LabelSystem\Barcodes\BarcodeNormalizerTest - */ -final class BarcodeNormalizer -{ - private const PREFIX_TYPE_MAP = [ - 'L' => 'lot', - 'P' => 'part', - 'S' => 'location', - ]; - - /** - * Parses barcode content and normalizes it. - * Returns an array in the format ['part', 1]: First entry contains element type, second the ID of the element. - */ - public function normalizeBarcodeContent(string $input): array - { - $input = trim($input); - $matches = []; - - //Some scanner output '-' as ß, so replace it (ß is never used, so we can replace it safely) - $input = str_replace('ß', '-', $input); - - //Extract parts from QR code's URL - if (preg_match('#^https?://.*/scan/(\w+)/(\d+)/?$#', $input, $matches)) { - return [$matches[1], (int) $matches[2]]; - } - - //New Code39 barcode use L0001 format - if (preg_match('#^([A-Z])(\d{4,})$#', $input, $matches)) { - $prefix = $matches[1]; - $id = (int) $matches[2]; - - if (!isset(self::PREFIX_TYPE_MAP[$prefix])) { - throw new InvalidArgumentException('Unknown prefix '.$prefix); - } - - return [self::PREFIX_TYPE_MAP[$prefix], $id]; - } - - //During development the L-000001 format was used - if (preg_match('#^(\w)-(\d{6,})$#', $input, $matches)) { - $prefix = $matches[1]; - $id = (int) $matches[2]; - - if (!isset(self::PREFIX_TYPE_MAP[$prefix])) { - throw new InvalidArgumentException('Unknown prefix '.$prefix); - } - - return [self::PREFIX_TYPE_MAP[$prefix], $id]; - } - - //Legacy Part-DB location labels used $L00336 format - if (preg_match('#^\$L(\d{5,})$#', $input, $matches)) { - return ['location', (int) $matches[1]]; - } - - //Legacy Part-DB used EAN8 barcodes for part labels. Format 0000001(2) (note the optional 8th digit => checksum) - if (preg_match('#^(\d{7})\d?$#', $input, $matches)) { - return ['part', (int) $matches[1]]; - } - - throw new InvalidArgumentException('Unknown barcode format!'); - } -} diff --git a/src/Services/LabelSystem/Barcodes/BarcodeRedirector.php b/src/Services/LabelSystem/Barcodes/BarcodeRedirector.php deleted file mode 100644 index 0eba0ed4..00000000 --- a/src/Services/LabelSystem/Barcodes/BarcodeRedirector.php +++ /dev/null @@ -1,90 +0,0 @@ -. - */ - -declare(strict_types=1); - -/** - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -namespace App\Services\LabelSystem\Barcodes; - -use App\Entity\Parts\PartLot; -use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\EntityNotFoundException; -use InvalidArgumentException; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; - -/** - * @see \App\Tests\Services\LabelSystem\Barcodes\BarcodeRedirectorTest - */ -final class BarcodeRedirector -{ - public function __construct(private readonly UrlGeneratorInterface $urlGenerator, private readonly EntityManagerInterface $em) - { - } - - /** - * Determines the URL to which the user should be redirected, when scanning a QR code. - * - * @param string $type The type of the element that was scanned (e.g. 'part', 'lot', etc.) - * @param int $id The ID of the element that was scanned - * - * @return string the URL to which should be redirected - * - * @throws EntityNotFoundException - */ - public function getRedirectURL(string $type, int $id): string - { - switch ($type) { - case 'part': - return $this->urlGenerator->generate('app_part_show', ['id' => $id]); - case 'lot': - //Try to determine the part to the given lot - $lot = $this->em->find(PartLot::class, $id); - if (!$lot instanceof PartLot) { - throw new EntityNotFoundException(); - } - - return $this->urlGenerator->generate('app_part_show', ['id' => $lot->getPart()->getID()]); - - case 'location': - return $this->urlGenerator->generate('part_list_store_location', ['id' => $id]); - - default: - throw new InvalidArgumentException('Unknown $type: '.$type); - } - } -} diff --git a/src/Services/LabelSystem/DompdfFactory.php b/src/Services/LabelSystem/DompdfFactory.php index 4017a393..a2c8c3cd 100644 --- a/src/Services/LabelSystem/DompdfFactory.php +++ b/src/Services/LabelSystem/DompdfFactory.php @@ -1,4 +1,7 @@ . */ - namespace App\Services\LabelSystem; use Dompdf\Dompdf; @@ -27,7 +29,7 @@ use Symfony\Component\DependencyInjection\Attribute\AsDecorator; #[AsDecorator(decorates: DompdfFactoryInterface::class)] class DompdfFactory implements DompdfFactoryInterface { - public function __construct(private string $fontDirectory, private string $tmpDirectory) + public function __construct(private readonly string $fontDirectory, private readonly string $tmpDirectory) { //Create folder if it does not exist $this->createDirectoryIfNotExisting($this->fontDirectory); @@ -36,10 +38,8 @@ class DompdfFactory implements DompdfFactoryInterface private function createDirectoryIfNotExisting(string $path): void { - if (!is_dir($path)) { - if (!mkdir($concurrentDirectory = $path, 0777, true) && !is_dir($concurrentDirectory)) { - throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory)); - } + if (!is_dir($path) && (!mkdir($concurrentDirectory = $path, 0777, true) && !is_dir($concurrentDirectory))) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory)); } } @@ -51,4 +51,4 @@ class DompdfFactory implements DompdfFactoryInterface 'tempDir' => $this->tmpDirectory, ]); } -} \ No newline at end of file +} diff --git a/src/Services/LabelSystem/BarcodeGenerator.php b/src/Services/LabelSystem/LabelBarcodeGenerator.php similarity index 60% rename from src/Services/LabelSystem/BarcodeGenerator.php rename to src/Services/LabelSystem/LabelBarcodeGenerator.php index f955955a..66f74e58 100644 --- a/src/Services/LabelSystem/BarcodeGenerator.php +++ b/src/Services/LabelSystem/LabelBarcodeGenerator.php @@ -42,71 +42,49 @@ declare(strict_types=1); namespace App\Services\LabelSystem; use App\Entity\Base\AbstractDBElement; -use App\Entity\Base\AbstractStructuralDBElement; use App\Entity\LabelSystem\BarcodeType; use App\Entity\LabelSystem\LabelOptions; use App\Services\LabelSystem\Barcodes\BarcodeContentGenerator; -use Com\Tecnick\Barcode\Barcode; +use App\Services\LabelSystem\Barcodes\BarcodeHelper; use InvalidArgumentException; /** - * @see \App\Tests\Services\LabelSystem\BarcodeGeneratorTest + * @see \App\Tests\Services\LabelSystem\LabelBarcodeGeneratorTest */ -final class BarcodeGenerator +final class LabelBarcodeGenerator { - public function __construct(private readonly BarcodeContentGenerator $barcodeContentGenerator) + public function __construct(private readonly BarcodeContentGenerator $barcodeContentGenerator, private readonly BarcodeHelper $barcodeHelper) { } - public function generateHTMLBarcode(LabelOptions $options, object $target): ?string - { - $svg = $this->generateSVG($options, $target); - $base64 = $this->dataUri($svg, 'image/svg+xml'); - return ''. $this->getContent($options, $target) . ''; - } - - /** - * Creates a data URI (RFC 2397). - * Based on the Twig implementaion from HTMLExtension - * - * Length validation is not performed on purpose, validation should - * be done before calling this filter. - * - * @return string The generated data URI + /** + * Generate the barcode for the given label as HTML image tag. + * @param LabelOptions $options + * @param AbstractDBElement $target + * @return string|null */ - private function dataUri(string $data, string $mime): string + public function generateHTMLBarcode(LabelOptions $options, AbstractDBElement $target): ?string { - $repr = 'data:'; - - $repr .= $mime; - if (str_starts_with($mime, 'text/')) { - $repr .= ','.rawurlencode($data); - } else { - $repr .= ';base64,'.base64_encode($data); - } - - return $repr; - } - - public function generateSVG(LabelOptions $options, object $target): ?string - { - $barcode = new Barcode(); - - $type = match ($options->getBarcodeType()) { - BarcodeType::NONE => null, - BarcodeType::QR => 'QRCODE', - BarcodeType::DATAMATRIX => 'DATAMATRIX', - BarcodeType::CODE39 => 'C39', - BarcodeType::CODE93 => 'C93', - BarcodeType::CODE128 => 'C128A', - }; - - if ($type === null) { + if ($options->getBarcodeType() === BarcodeType::NONE) { return null; } + return $this->barcodeHelper->barcodeAsHTML($this->getContent($options, $target), $options->getBarcodeType()); + } - return $barcode->getBarcodeObj($type, $this->getContent($options, $target))->getSvgCode(); + /** + * Generate the barcode for the given label as SVG string. + * @param LabelOptions $options + * @param AbstractDBElement $target + * @return string|null + */ + public function generateSVG(LabelOptions $options, AbstractDBElement $target): ?string + { + if ($options->getBarcodeType() === BarcodeType::NONE) { + return null; + } + + return $this->barcodeHelper->barcodeAsSVG($this->getContent($options, $target), $options->getBarcodeType()); } public function getContent(LabelOptions $options, AbstractDBElement $target): ?string diff --git a/src/Services/LabelSystem/LabelExampleElementsGenerator.php b/src/Services/LabelSystem/LabelExampleElementsGenerator.php index 61cbcc4a..d344c929 100644 --- a/src/Services/LabelSystem/LabelExampleElementsGenerator.php +++ b/src/Services/LabelSystem/LabelExampleElementsGenerator.php @@ -49,7 +49,7 @@ use App\Entity\Parts\Manufacturer; use App\Entity\Parts\ManufacturingStatus; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\UserSystem\User; use DateTime; use InvalidArgumentException; @@ -97,24 +97,24 @@ final class LabelExampleElementsGenerator $lot->setDescription('Example Lot'); $lot->setComment('Lot comment'); - $lot->setExpirationDate(new DateTime('+1 days')); - $lot->setStorageLocation($this->getStructuralData(Storelocation::class)); + $lot->setExpirationDate(new \DateTimeImmutable('+1 day')); + $lot->setStorageLocation($this->getStructuralData(StorageLocation::class)); $lot->setAmount(123); $lot->setOwner($this->getUser()); return $lot; } - private function getStorelocation(): Storelocation + private function getStorelocation(): StorageLocation { - $storelocation = new Storelocation(); + $storelocation = new StorageLocation(); $storelocation->setName('Location 1'); $storelocation->setComment('Example comment'); $storelocation->updateTimestamps(); $storelocation->setOwner($this->getUser()); - $parent = new Storelocation(); + $parent = new StorageLocation(); $parent->setName('Parent'); $storelocation->setParent($parent); @@ -146,11 +146,11 @@ final class LabelExampleElementsGenerator throw new InvalidArgumentException('$class must be an child of AbstractStructuralDBElement'); } - /** @var AbstractStructuralDBElement $parent */ + /** @var T $parent */ $parent = new $class(); $parent->setName('Example'); - /** @var AbstractStructuralDBElement $child */ + /** @var T $child */ $child = new $class(); $child->setName((new ReflectionClass($class))->getShortName()); $child->setParent($parent); diff --git a/src/Services/LabelSystem/LabelGenerator.php b/src/Services/LabelSystem/LabelGenerator.php index f16b135a..bfb8d27b 100644 --- a/src/Services/LabelSystem/LabelGenerator.php +++ b/src/Services/LabelSystem/LabelGenerator.php @@ -42,10 +42,6 @@ declare(strict_types=1); namespace App\Services\LabelSystem; use App\Entity\LabelSystem\LabelOptions; -use App\Entity\Parts\Part; -use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; -use Dompdf\Dompdf; use InvalidArgumentException; use Jbtronics\DompdfFontLoaderBundle\Services\DompdfFactoryInterface; @@ -66,10 +62,6 @@ final class LabelGenerator */ public function generateLabel(LabelOptions $options, object|array $elements): string { - if (!is_array($elements) && !is_object($elements)) { - throw new InvalidArgumentException('$element must be an object or an array of objects!'); - } - if (!is_array($elements)) { $elements = [$elements]; } diff --git a/src/Services/LabelSystem/LabelHTMLGenerator.php b/src/Services/LabelSystem/LabelHTMLGenerator.php index 7b6defa6..42aa1e72 100644 --- a/src/Services/LabelSystem/LabelHTMLGenerator.php +++ b/src/Services/LabelSystem/LabelHTMLGenerator.php @@ -53,7 +53,14 @@ use Twig\Error\Error; final class LabelHTMLGenerator { - public function __construct(private readonly ElementTypeNameGenerator $elementTypeNameGenerator, private readonly LabelTextReplacer $replacer, private readonly Environment $twig, private readonly BarcodeGenerator $barcodeGenerator, private readonly SandboxedTwigProvider $sandboxedTwigProvider, private readonly Security $security, private readonly string $partdb_title) + public function __construct( + private readonly ElementTypeNameGenerator $elementTypeNameGenerator, + private readonly LabelTextReplacer $replacer, + private readonly Environment $twig, + private readonly LabelBarcodeGenerator $barcodeGenerator, + private readonly SandboxedTwigFactory $sandboxedTwigProvider, + private readonly Security $security, + private readonly string $partdb_title) { } @@ -66,7 +73,7 @@ final class LabelHTMLGenerator $twig_elements = []; if (LabelProcessMode::TWIG === $options->getProcessMode()) { - $sandboxed_twig = $this->sandboxedTwigProvider->getTwig($options); + $sandboxed_twig = $this->sandboxedTwigProvider->createTwig($options); $current_user = $this->security->getUser(); } @@ -79,8 +86,11 @@ final class LabelHTMLGenerator [ 'element' => $element, 'page' => $page, + 'last_page' => count($elements), 'user' => $current_user, 'install_title' => $this->partdb_title, + 'paper_width' => $options->getWidth(), + 'paper_height' => $options->getHeight(), ] ); } catch (Error $exception) { diff --git a/src/Services/LabelSystem/LabelProfileDropdownHelper.php b/src/Services/LabelSystem/LabelProfileDropdownHelper.php index d7f1120d..773923ab 100644 --- a/src/Services/LabelSystem/LabelProfileDropdownHelper.php +++ b/src/Services/LabelSystem/LabelProfileDropdownHelper.php @@ -44,15 +44,20 @@ namespace App\Services\LabelSystem; use App\Entity\LabelSystem\LabelProfile; use App\Entity\LabelSystem\LabelSupportedElement; use App\Repository\LabelProfileRepository; -use App\Services\UserSystem\UserCacheKeyGenerator; +use App\Services\Cache\ElementCacheTagGenerator; +use App\Services\Cache\UserCacheKeyGenerator; use Doctrine\ORM\EntityManagerInterface; use Symfony\Contracts\Cache\ItemInterface; use Symfony\Contracts\Cache\TagAwareCacheInterface; final class LabelProfileDropdownHelper { - public function __construct(private readonly TagAwareCacheInterface $cache, private readonly EntityManagerInterface $entityManager, private readonly UserCacheKeyGenerator $keyGenerator) - { + public function __construct( + private readonly TagAwareCacheInterface $cache, + private readonly EntityManagerInterface $entityManager, + private readonly UserCacheKeyGenerator $keyGenerator, + private readonly ElementCacheTagGenerator $tagGenerator, + ) { } /** @@ -67,10 +72,9 @@ final class LabelProfileDropdownHelper $type = LabelSupportedElement::from($type); } - $secure_class_name = str_replace('\\', '_', LabelProfile::class); + $secure_class_name = $this->tagGenerator->getElementTypeCacheTag(LabelProfile::class); $key = 'profile_dropdown_'.$this->keyGenerator->generateKey().'_'.$secure_class_name.'_'.$type->value; - - /** @var LabelProfileRepository $repo */ + $repo = $this->entityManager->getRepository(LabelProfile::class); return $this->cache->get($key, function (ItemInterface $item) use ($repo, $type, $secure_class_name) { diff --git a/src/Services/LabelSystem/LabelTextReplacer.php b/src/Services/LabelSystem/LabelTextReplacer.php index 034e243f..6f0a9ee8 100644 --- a/src/Services/LabelSystem/LabelTextReplacer.php +++ b/src/Services/LabelSystem/LabelTextReplacer.php @@ -64,6 +64,17 @@ final class LabelTextReplacer * @return string If the placeholder was valid, the replaced info. Otherwise the passed string. */ public function handlePlaceholder(string $placeholder, object $target): string + { + return $this->handlePlaceholderOrReturnNull($placeholder, $target) ?? $placeholder; + } + + /** + * Similar to handlePlaceholder, but returns null if the placeholder is not known (instead of the original string) + * @param string $placeholder + * @param object $target + * @return string|null + */ + public function handlePlaceholderOrReturnNull(string $placeholder, object $target): ?string { foreach ($this->providers as $provider) { /** @var PlaceholderProviderInterface $provider */ @@ -73,7 +84,7 @@ final class LabelTextReplacer } } - return $placeholder; + return null; } /** diff --git a/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php b/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php index 11824054..400fef35 100644 --- a/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php +++ b/src/Services/LabelSystem/PlaceholderProviders/BarcodeProvider.php @@ -24,12 +24,18 @@ namespace App\Services\LabelSystem\PlaceholderProviders; use App\Entity\LabelSystem\BarcodeType; use App\Entity\LabelSystem\LabelOptions; -use App\Services\LabelSystem\BarcodeGenerator; +use App\Entity\Parts\Part; +use App\Entity\Parts\PartLot; +use App\Services\LabelSystem\Barcodes\BarcodeHelper; +use App\Services\LabelSystem\LabelBarcodeGenerator; use App\Services\LabelSystem\Barcodes\BarcodeContentGenerator; +use Com\Tecnick\Barcode\Exception; final class BarcodeProvider implements PlaceholderProviderInterface { - public function __construct(private readonly BarcodeGenerator $barcodeGenerator, private readonly BarcodeContentGenerator $barcodeContentGenerator) + public function __construct(private readonly LabelBarcodeGenerator $barcodeGenerator, + private readonly BarcodeContentGenerator $barcodeContentGenerator, + private readonly BarcodeHelper $barcodeHelper) { } @@ -57,18 +63,61 @@ final class BarcodeProvider implements PlaceholderProviderInterface return $this->barcodeGenerator->generateHTMLBarcode($label_options, $label_target); } + if ('[[BARCODE_DATAMATRIX]]' === $placeholder) { + $label_options = new LabelOptions(); + $label_options->setBarcodeType(BarcodeType::DATAMATRIX); + return $this->barcodeGenerator->generateHTMLBarcode($label_options, $label_target); + } + if ('[[BARCODE_C39]]' === $placeholder) { $label_options = new LabelOptions(); $label_options->setBarcodeType(BarcodeType::CODE39); return $this->barcodeGenerator->generateHTMLBarcode($label_options, $label_target); } + if ('[[BARCODE_C93]]' === $placeholder) { + $label_options = new LabelOptions(); + $label_options->setBarcodeType(BarcodeType::CODE93); + return $this->barcodeGenerator->generateHTMLBarcode($label_options, $label_target); + } + if ('[[BARCODE_C128]]' === $placeholder) { $label_options = new LabelOptions(); $label_options->setBarcodeType(BarcodeType::CODE128); return $this->barcodeGenerator->generateHTMLBarcode($label_options, $label_target); } + if (($label_target instanceof Part || $label_target instanceof PartLot) + && str_starts_with($placeholder, '[[IPN_BARCODE_')) { + if ($label_target instanceof PartLot) { + $label_target = $label_target->getPart(); + } + + if ($label_target === null || $label_target->getIPN() === null || $label_target->getIPN() === '') { + //Replace with empty result, if no IPN is set + return ''; + } + + try { + //Add placeholders for the IPN barcode + if ('[[IPN_BARCODE_C39]]' === $placeholder) { + return $this->barcodeHelper->barcodeAsHTML($label_target->getIPN(), BarcodeType::CODE39); + } + if ('[[IPN_BARCODE_C128]]' === $placeholder) { + return $this->barcodeHelper->barcodeAsHTML($label_target->getIPN(), BarcodeType::CODE128); + } + if ('[[IPN_BARCODE_QR]]' === $placeholder) { + return $this->barcodeHelper->barcodeAsHTML($label_target->getIPN(), BarcodeType::QR); + } + } catch (Exception $e) { + //If an error occurs, output it + return 'IPN Barcode ERROR!: '.$e->getMessage(); + } + } + + + + return null; } } diff --git a/src/Services/LabelSystem/PlaceholderProviders/GlobalProviders.php b/src/Services/LabelSystem/PlaceholderProviders/GlobalProviders.php index 5a9b2294..ddd4dbf1 100644 --- a/src/Services/LabelSystem/PlaceholderProviders/GlobalProviders.php +++ b/src/Services/LabelSystem/PlaceholderProviders/GlobalProviders.php @@ -81,7 +81,7 @@ final class GlobalProviders implements PlaceholderProviderInterface return 'anonymous'; } - $now = new DateTime(); + $now = new \DateTimeImmutable(); if ('[[DATETIME]]' === $placeholder) { $formatter = IntlDateFormatter::create( diff --git a/src/Services/LabelSystem/PlaceholderProviders/PartLotProvider.php b/src/Services/LabelSystem/PlaceholderProviders/PartLotProvider.php index fb9447ba..946b4892 100644 --- a/src/Services/LabelSystem/PlaceholderProviders/PartLotProvider.php +++ b/src/Services/LabelSystem/PlaceholderProviders/PartLotProvider.php @@ -41,7 +41,7 @@ declare(strict_types=1); namespace App\Services\LabelSystem\PlaceholderProviders; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\UserSystem\User; use App\Entity\Parts\PartLot; use App\Services\Formatters\AmountFormatter; @@ -95,11 +95,11 @@ final class PartLotProvider implements PlaceholderProviderInterface } if ('[[LOCATION]]' === $placeholder) { - return $label_target->getStorageLocation() instanceof Storelocation ? $label_target->getStorageLocation()->getName() : ''; + return $label_target->getStorageLocation() instanceof StorageLocation ? $label_target->getStorageLocation()->getName() : ''; } if ('[[LOCATION_FULL]]' === $placeholder) { - return $label_target->getStorageLocation() instanceof Storelocation ? $label_target->getStorageLocation()->getFullPath() : ''; + return $label_target->getStorageLocation() instanceof StorageLocation ? $label_target->getStorageLocation()->getFullPath() : ''; } if ('[[OWNER]]' === $placeholder) { diff --git a/src/Services/LabelSystem/PlaceholderProviders/StorelocationProvider.php b/src/Services/LabelSystem/PlaceholderProviders/StorelocationProvider.php index 95654eca..4b4d8dcd 100644 --- a/src/Services/LabelSystem/PlaceholderProviders/StorelocationProvider.php +++ b/src/Services/LabelSystem/PlaceholderProviders/StorelocationProvider.php @@ -23,13 +23,13 @@ declare(strict_types=1); namespace App\Services\LabelSystem\PlaceholderProviders; use App\Entity\UserSystem\User; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; class StorelocationProvider implements PlaceholderProviderInterface { public function replace(string $placeholder, object $label_target, array $options = []): ?string { - if ($label_target instanceof Storelocation) { + if ($label_target instanceof StorageLocation) { if ('[[OWNER]]' === $placeholder) { return $label_target->getOwner() instanceof User ? $label_target->getOwner()->getFullName() : ''; } diff --git a/src/Services/LabelSystem/PlaceholderProviders/StructuralDBElementProvider.php b/src/Services/LabelSystem/PlaceholderProviders/StructuralDBElementProvider.php index ca8088da..f37f5901 100644 --- a/src/Services/LabelSystem/PlaceholderProviders/StructuralDBElementProvider.php +++ b/src/Services/LabelSystem/PlaceholderProviders/StructuralDBElementProvider.php @@ -52,7 +52,7 @@ final class StructuralDBElementProvider implements PlaceholderProviderInterface return $label_target->getComment(); } if ('[[COMMENT_T]]' === $placeholder) { - return strip_tags($label_target->getComment()); + return strip_tags((string) $label_target->getComment()); } if ('[[FULL_PATH]]' === $placeholder) { return $label_target->getFullPath(); diff --git a/src/Services/LabelSystem/PlaceholderProviders/TimestampableElementProvider.php b/src/Services/LabelSystem/PlaceholderProviders/TimestampableElementProvider.php index 8588e133..b316abf2 100644 --- a/src/Services/LabelSystem/PlaceholderProviders/TimestampableElementProvider.php +++ b/src/Services/LabelSystem/PlaceholderProviders/TimestampableElementProvider.php @@ -42,7 +42,6 @@ declare(strict_types=1); namespace App\Services\LabelSystem\PlaceholderProviders; use App\Entity\Contracts\TimeStampableInterface; -use DateTime; use IntlDateFormatter; use Locale; @@ -57,11 +56,11 @@ final class TimestampableElementProvider implements PlaceholderProviderInterface $formatter = new IntlDateFormatter(Locale::getDefault(), IntlDateFormatter::SHORT, IntlDateFormatter::SHORT); if ('[[LAST_MODIFIED]]' === $placeholder) { - return $formatter->format($label_target->getLastModified() ?? new DateTime()); + return $formatter->format($label_target->getLastModified() ?? new \DateTimeImmutable()); } if ('[[CREATION_DATE]]' === $placeholder) { - return $formatter->format($label_target->getAddedDate() ?? new DateTime()); + return $formatter->format($label_target->getAddedDate() ?? new \DateTimeImmutable()); } } diff --git a/src/Services/LabelSystem/SandboxedTwigProvider.php b/src/Services/LabelSystem/SandboxedTwigFactory.php similarity index 60% rename from src/Services/LabelSystem/SandboxedTwigProvider.php rename to src/Services/LabelSystem/SandboxedTwigFactory.php index a0426cd1..d6ea6968 100644 --- a/src/Services/LabelSystem/SandboxedTwigProvider.php +++ b/src/Services/LabelSystem/SandboxedTwigFactory.php @@ -51,78 +51,121 @@ use App\Entity\Contracts\TimeStampableInterface; use App\Entity\LabelSystem\LabelOptions; use App\Entity\LabelSystem\LabelProcessMode; use App\Entity\Parameters\AbstractParameter; +use App\Entity\Parts\InfoProviderReference; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; +use App\Entity\Parts\PartAssociation; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; use App\Entity\PriceInformations\Orderdetail; use App\Entity\PriceInformations\Pricedetail; use App\Entity\UserSystem\User; +use App\Twig\BarcodeExtension; +use App\Twig\EntityExtension; use App\Twig\FormatExtension; use App\Twig\Sandbox\InheritanceSecurityPolicy; +use App\Twig\Sandbox\SandboxedLabelExtension; +use App\Twig\TwigCoreExtension; use InvalidArgumentException; use Twig\Environment; use Twig\Extension\SandboxExtension; +use Twig\Extra\Html\HtmlExtension; use Twig\Extra\Intl\IntlExtension; +use Twig\Extra\Markdown\MarkdownExtension; +use Twig\Extra\String\StringExtension; use Twig\Loader\ArrayLoader; use Twig\Sandbox\SecurityPolicyInterface; /** - * @see \App\Tests\Services\LabelSystem\SandboxedTwigProviderTest + * This service creates a sandboxed twig environment for the label system. + * @see \App\Tests\Services\LabelSystem\SandboxedTwigFactoryTest */ -final class SandboxedTwigProvider +final class SandboxedTwigFactory { private const ALLOWED_TAGS = ['apply', 'autoescape', 'do', 'for', 'if', 'set', 'verbatim', 'with']; private const ALLOWED_FILTERS = ['abs', 'batch', 'capitalize', 'column', 'country_name', - 'currency_name', 'currency_symbol', 'date', 'date_modify', 'default', 'escape', 'filter', 'first', 'format', - 'format_currency', 'format_date', 'format_datetime', 'format_number', 'format_time', 'join', 'keys', - 'language_name', 'last', 'length', 'locale_name', 'lower', 'map', 'merge', 'nl2br', 'raw', 'number_format', - 'reduce', 'replace', 'reverse', 'slice', 'sort', 'spaceless', 'split', 'striptags', 'timezone_name', 'title', - 'trim', 'upper', 'url_encode', - //Part-DB specific filters: - 'moneyFormat', 'siFormat', 'amountFormat', ]; + 'currency_name', 'currency_symbol', 'date', 'date_modify', 'data_uri', 'default', 'escape', 'filter', 'first', 'format', + 'format_currency', 'format_date', 'format_datetime', 'format_number', 'format_time', 'html_to_markdown', 'join', 'keys', + 'language_name', 'last', 'length', 'locale_name', 'lower', 'map', 'markdown_to_html', 'merge', 'nl2br', 'raw', 'number_format', + 'reduce', 'replace', 'reverse', 'round', 'slice', 'slug', 'sort', 'spaceless', 'split', 'striptags', 'timezone_name', 'title', + 'trim', 'u', 'upper', 'url_encode', - private const ALLOWED_FUNCTIONS = ['date', 'html_classes', 'max', 'min', 'random', 'range']; + //Part-DB specific filters: + + //FormatExtension: + 'format_money', 'format_si', 'format_amount', 'format_bytes', + + //SandboxedLabelExtension + 'placeholders', + ]; + + private const ALLOWED_FUNCTIONS = ['country_names', 'country_timezones', 'currency_names', 'cycle', + 'date', 'html_classes', 'language_names', 'locale_names', 'max', 'min', 'random', 'range', 'script_names', + 'template_from_string', 'timezone_names', + + //Part-DB specific extensions: + //EntityExtension: + 'entity_type', 'entity_url', + //BarcodeExtension: + 'barcode_svg', + //SandboxedLabelExtension + 'placeholder', + ]; private const ALLOWED_METHODS = [ NamedElementInterface::class => ['getName'], AbstractDBElement::class => ['getID', '__toString'], TimeStampableInterface::class => ['getLastModified', 'getAddedDate'], AbstractStructuralDBElement::class => ['isChildOf', 'isRoot', 'getParent', 'getComment', 'getLevel', - 'getFullPath', 'getPathArray', 'getChildren', 'isNotSelectable', ], - AbstractCompany::class => ['getAddress', 'getPhoneNumber', 'getFaxNumber', 'getEmailAddress', 'getWebsite'], + 'getFullPath', 'getPathArray', 'getSubelements', 'getChildren', 'isNotSelectable', ], + AbstractCompany::class => ['getAddress', 'getPhoneNumber', 'getFaxNumber', 'getEmailAddress', 'getWebsite', 'getAutoProductUrl'], AttachmentContainingDBElement::class => ['getAttachments', 'getMasterPictureAttachment'], - Attachment::class => ['isPicture', 'is3DModel', 'isExternal', 'isSecure', 'isBuiltIn', 'getExtension', - 'getElement', 'getURL', 'getFilename', 'getAttachmentType', 'getShowInTable', ], + Attachment::class => ['isPicture', 'is3DModel', 'hasExternal', 'hasInternal', 'isSecure', 'isBuiltIn', 'getExtension', + 'getElement', 'getExternalPath', 'getHost', 'getFilename', 'getAttachmentType', 'getShowInTable'], AbstractParameter::class => ['getFormattedValue', 'getGroup', 'getSymbol', 'getValueMin', 'getValueMax', 'getValueTypical', 'getUnit', 'getValueText', ], MeasurementUnit::class => ['getUnit', 'isInteger', 'useSIPrefix'], PartLot::class => ['isExpired', 'getDescription', 'getComment', 'getExpirationDate', 'getStorageLocation', - 'getPart', 'isInstockUnknown', 'getAmount', 'getNeedsRefill', ], - Storelocation::class => ['isFull', 'isOnlySinglePart', 'isLimitToExistingParts', 'getStorageType'], + 'getPart', 'isInstockUnknown', 'getAmount', 'getNeedsRefill', 'getVendorBarcode'], + StorageLocation::class => ['isFull', 'isOnlySinglePart', 'isLimitToExistingParts', 'getStorageType'], Supplier::class => ['getShippingCosts', 'getDefaultCurrency'], - Part::class => ['isNeedsReview', 'getTags', 'getMass', 'getDescription', 'isFavorite', 'getCategory', - 'getFootprint', 'getPartLots', 'getPartUnit', 'useFloatAmount', 'getMinAmount', 'getAmountSum', + Part::class => ['isNeedsReview', 'getTags', 'getMass', 'getIpn', 'getProviderReference', + 'getDescription', 'getComment', 'isFavorite', 'getCategory', 'getFootprint', + 'getPartLots', 'getPartUnit', 'useFloatAmount', 'getMinAmount', 'getAmountSum', 'isNotEnoughInstock', 'isAmountUnknown', 'getExpiredAmountSum', 'getManufacturerProductUrl', 'getCustomProductURL', 'getManufacturingStatus', 'getManufacturer', - 'getManufacturerProductNumber', 'getOrderdetails', 'isObsolete', ], + 'getManufacturerProductNumber', 'getOrderdetails', 'isObsolete', + 'getParameters', 'getGroupedParameters', + 'isProjectBuildPart', 'getBuiltProject', + 'getAssociatedPartsAsOwner', 'getAssociatedPartsAsOther', 'getAssociatedPartsAll', + 'getEdaInfo' + ], Currency::class => ['getIsoCode', 'getInverseExchangeRate', 'getExchangeRate'], Orderdetail::class => ['getPart', 'getSupplier', 'getSupplierPartNr', 'getObsolete', - 'getPricedetails', 'findPriceForQty', ], + 'getPricedetails', 'findPriceForQty', 'isObsolete', 'getSupplierProductUrl'], Pricedetail::class => ['getOrderdetail', 'getPrice', 'getPricePerUnit', 'getPriceRelatedQuantity', - 'getMinDiscountQuantity', 'getCurrency', ], + 'getMinDiscountQuantity', 'getCurrency', 'getCurrencyISOCode'], + InfoProviderReference:: class => ['getProviderKey', 'getProviderId', 'getProviderUrl', 'getLastUpdated', 'isProviderCreated'], + PartAssociation::class => ['getType', 'getComment', 'getOwner', 'getOther', 'getOtherType'], + //Only allow very little information about users... User::class => ['isAnonymousUser', 'getUsername', 'getFullName', 'getFirstName', 'getLastName', 'getDepartment', 'getEmail', ], ]; private const ALLOWED_PROPERTIES = []; - public function __construct(private readonly FormatExtension $appExtension) + public function __construct( + private readonly FormatExtension $formatExtension, + private readonly BarcodeExtension $barcodeExtension, + private readonly EntityExtension $entityExtension, + private readonly TwigCoreExtension $twigCoreExtension, + private readonly SandboxedLabelExtension $sandboxedLabelExtension, + ) { } - public function getTwig(LabelOptions $options): Environment + public function createTwig(LabelOptions $options): Environment { if (LabelProcessMode::TWIG !== $options->getProcessMode()) { throw new InvalidArgumentException('The LabelOptions must explicitly allow twig via lines_mode = "twig"!'); @@ -139,9 +182,16 @@ final class SandboxedTwigProvider //Add IntlExtension $twig->addExtension(new IntlExtension()); + $twig->addExtension(new MarkdownExtension()); + $twig->addExtension(new StringExtension()); + $twig->addExtension(new HtmlExtension()); //Add Part-DB specific extension - $twig->addExtension($this->appExtension); + $twig->addExtension($this->formatExtension); + $twig->addExtension($this->barcodeExtension); + $twig->addExtension($this->entityExtension); + $twig->addExtension($this->twigCoreExtension); + $twig->addExtension($this->sandboxedLabelExtension); return $twig; } diff --git a/src/Services/LogSystem/EventUndoHelper.php b/src/Services/LogSystem/EventUndoHelper.php index ed3bc363..c57f7724 100644 --- a/src/Services/LogSystem/EventUndoHelper.php +++ b/src/Services/LogSystem/EventUndoHelper.php @@ -42,7 +42,6 @@ declare(strict_types=1); namespace App\Services\LogSystem; use App\Entity\LogSystem\AbstractLogEntry; -use InvalidArgumentException; class EventUndoHelper { diff --git a/src/Services/LogSystem/EventUndoMode.php b/src/Services/LogSystem/EventUndoMode.php index 51ad664e..de30dcfd 100644 --- a/src/Services/LogSystem/EventUndoMode.php +++ b/src/Services/LogSystem/EventUndoMode.php @@ -1,4 +1,7 @@ . */ - namespace App\Services\LogSystem; use InvalidArgumentException; diff --git a/src/Services/LogSystem/HistoryHelper.php b/src/Services/LogSystem/HistoryHelper.php index f4752b6f..3a31f127 100644 --- a/src/Services/LogSystem/HistoryHelper.php +++ b/src/Services/LogSystem/HistoryHelper.php @@ -44,7 +44,6 @@ namespace App\Services\LogSystem; use App\Entity\Attachments\AttachmentContainingDBElement; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\AbstractStructuralDBElement; -use App\Entity\Parameters\AbstractParameter; use App\Entity\Parts\Part; use App\Entity\ProjectSystem\Project; diff --git a/src/Services/LogSystem/LogDataFormatter.php b/src/Services/LogSystem/LogDataFormatter.php index f15fcdc6..af54c60c 100644 --- a/src/Services/LogSystem/LogDataFormatter.php +++ b/src/Services/LogSystem/LogDataFormatter.php @@ -41,7 +41,7 @@ class LogDataFormatter public function formatData(mixed $data, AbstractLogEntry $logEntry, string $fieldName): string { if (is_string($data)) { - $tmp = '"' . mb_strimwidth(htmlspecialchars($data), 0, self::STRING_MAX_LENGTH, ) . '"'; + $tmp = '"' . mb_strimwidth(htmlspecialchars($data), 0, self::STRING_MAX_LENGTH) . '"'; //Show special characters and line breaks $tmp = preg_replace('/\n/', '\\n
', $tmp); @@ -87,7 +87,7 @@ class LogDataFormatter private function formatJSON(array $data): string { - $json = htmlspecialchars(json_encode($data, JSON_PRETTY_PRINT), ENT_QUOTES | ENT_SUBSTITUTE); + $json = htmlspecialchars(json_encode($data, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT), ENT_QUOTES | ENT_SUBSTITUTE); return sprintf( '
', @@ -136,7 +136,7 @@ class LogDataFormatter } try { - $dateTime = new \DateTime($date, new \DateTimeZone($timezone)); + $dateTime = new \DateTimeImmutable($date, new \DateTimeZone($timezone)); } catch (\Exception) { return 'unknown DateTime format'; } diff --git a/src/Services/LogSystem/LogEntryExtraFormatter.php b/src/Services/LogSystem/LogEntryExtraFormatter.php index a1fd4c9b..ae2a5eba 100644 --- a/src/Services/LogSystem/LogEntryExtraFormatter.php +++ b/src/Services/LogSystem/LogEntryExtraFormatter.php @@ -135,7 +135,7 @@ class LogEntryExtraFormatter } if ($context instanceof LogWithCommentInterface && $context->hasComment()) { - $array[] = htmlspecialchars($context->getComment()); + $array[] = htmlspecialchars((string) $context->getComment()); } if ($context instanceof ElementCreatedLogEntry && $context->hasCreationInstockValue()) { @@ -193,6 +193,10 @@ class LogEntryExtraFormatter htmlspecialchars($this->elementTypeNameGenerator->getLocalizedTypeLabel(PartLot::class)) .' ' . $context->getMoveToTargetID(); } + if ($context->getActionTimestamp() !== null) { + $formatter = new \IntlDateFormatter($this->translator->getLocale(), \IntlDateFormatter::SHORT, \IntlDateFormatter::SHORT); + $array['log.part_stock_changed.timestamp'] = $formatter->format($context->getActionTimestamp()); + } } return $array; diff --git a/src/Services/LogSystem/LogLevelHelper.php b/src/Services/LogSystem/LogLevelHelper.php index 5cc13db8..67e87392 100644 --- a/src/Services/LogSystem/LogLevelHelper.php +++ b/src/Services/LogSystem/LogLevelHelper.php @@ -22,7 +22,6 @@ declare(strict_types=1); */ namespace App\Services\LogSystem; -use App\Entity\LogSystem\AbstractLogEntry; use Psr\Log\LogLevel; class LogLevelHelper diff --git a/src/Services/LogSystem/LogTargetHelper.php b/src/Services/LogSystem/LogTargetHelper.php index 0a10a023..5dd649f1 100644 --- a/src/Services/LogSystem/LogTargetHelper.php +++ b/src/Services/LogSystem/LogTargetHelper.php @@ -22,17 +22,9 @@ declare(strict_types=1); */ namespace App\Services\LogSystem; -use App\Entity\Attachments\Attachment; use App\Entity\Base\AbstractDBElement; -use App\Entity\Contracts\NamedElementInterface; use App\Entity\LogSystem\AbstractLogEntry; use App\Entity\LogSystem\UserNotAllowedLogEntry; -use App\Entity\Parameters\AbstractParameter; -use App\Entity\Parts\PartLot; -use App\Entity\PriceInformations\Orderdetail; -use App\Entity\PriceInformations\Pricedetail; -use App\Entity\ProjectSystem\ProjectBOMEntry; -use App\Exceptions\EntityNotSupportedException; use App\Repository\LogEntryRepository; use App\Services\ElementTypeNameGenerator; use App\Services\EntityURLGenerator; diff --git a/src/Services/LogSystem/TimeTravel.php b/src/Services/LogSystem/TimeTravel.php index 400e85f5..68d962bb 100644 --- a/src/Services/LogSystem/TimeTravel.php +++ b/src/Services/LogSystem/TimeTravel.php @@ -34,12 +34,14 @@ use App\Repository\LogEntryRepository; use Brick\Math\BigDecimal; use DateTime; use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\MappingException; use Exception; use InvalidArgumentException; use ReflectionClass; +use Symfony\Component\PropertyAccess\PropertyAccessor; class TimeTravel { @@ -54,8 +56,11 @@ class TimeTravel /** * Undeletes the element with the given ID. * + * @template T of AbstractDBElement * @param string $class The class name of the element that should be undeleted + * @phpstan-param class-string $class * @param int $id the ID of the element that should be undeleted + * @phpstan-return T */ public function undeleteEntity(string $class, int $id): AbstractDBElement { @@ -136,16 +141,16 @@ class TimeTravel //Revert many-to-one association (one element in property) if ( - ClassMetadataInfo::MANY_TO_ONE === $mapping['type'] - || ClassMetadataInfo::ONE_TO_ONE === $mapping['type'] + ClassMetadata::MANY_TO_ONE === $mapping['type'] + || ClassMetadata::ONE_TO_ONE === $mapping['type'] ) { $target_element = $this->getField($element, $field); if (null !== $target_element && $element->getLastModified() > $timestamp) { $this->revertEntityToTimestamp($target_element, $timestamp, $reverted_elements); } } elseif ( //Revert *_TO_MANY associations (collection properties) - (ClassMetadataInfo::MANY_TO_MANY === $mapping['type'] - || ClassMetadataInfo::ONE_TO_MANY === $mapping['type']) + (ClassMetadata::MANY_TO_MANY === $mapping['type'] + || ClassMetadata::ONE_TO_MANY === $mapping['type']) && !$mapping['isOwningSide'] ) { $target_elements = $this->getField($element, $field); @@ -171,17 +176,26 @@ class TimeTravel /** * This function decodes the array which is created during the json_encode of a datetime object and returns a DateTime object. * @param array $input - * @return DateTime + * @return \DateTimeInterface * @throws Exception */ - private function dateTimeDecode(?array $input): ?\DateTime + private function dateTimeDecode(?array $input, string $doctrineType): ?\DateTimeInterface { //Allow null values if ($input === null) { return null; } - return new \DateTime($input['date'], new \DateTimeZone($input['timezone'])); + //Mutable types + if (in_array($doctrineType, [Types::DATETIME_MUTABLE, Types::DATE_MUTABLE], true)) { + return new \DateTime($input['date'], new \DateTimeZone($input['timezone'])); + } + //Immutable types + if (in_array($doctrineType, [Types::DATETIME_IMMUTABLE, Types::DATE_IMMUTABLE], true)) { + return new \DateTimeImmutable($input['date'], new \DateTimeZone($input['timezone'])); + } + + throw new InvalidArgumentException('The given doctrine type is not a datetime type!'); } /** @@ -202,14 +216,24 @@ class TimeTravel $old_data = $logEntry->getOldData(); foreach ($old_data as $field => $data) { - if ($metadata->hasField($field)) { + + //We use the fieldMappings property directly instead of the hasField method, as we do not want to match the embedded field itself + //The sub fields are handled in the setField method + if (isset($metadata->fieldMappings[$field])) { //We need to convert the string to a BigDecimal first - if (!$data instanceof BigDecimal && ('big_decimal' === $metadata->getFieldMapping($field)['type'])) { + if (!$data instanceof BigDecimal && ('big_decimal' === $metadata->getFieldMapping($field)->type)) { $data = BigDecimal::of($data); } - if (!$data instanceof DateTime && ('datetime' === $metadata->getFieldMapping($field)['type'])) { - $data = $this->dateTimeDecode($data); + if (!$data instanceof \DateTimeInterface + && (in_array($metadata->getFieldMapping($field)->type, + [ + Types::DATETIME_IMMUTABLE, + Types::DATETIME_IMMUTABLE, + Types::DATE_MUTABLE, + Types::DATETIME_IMMUTABLE + ], true))) { + $data = $this->dateTimeDecode($data, $metadata->getFieldMapping($field)->type); } $this->setField($element, $field, $data); @@ -219,7 +243,7 @@ class TimeTravel $target_class = $mapping['targetEntity']; //Try to extract the old ID: if (is_array($data) && isset($data['@id'])) { - $entity = $this->em->getPartialReference($target_class, $data['@id']); + $entity = $this->em->getReference($target_class, $data['@id']); $this->setField($element, $field, $entity); } } @@ -241,8 +265,22 @@ class TimeTravel */ protected function setField(AbstractDBElement $element, string $field, mixed $new_value): void { - $reflection = new ReflectionClass($element::class); - $property = $reflection->getProperty($field); + //If the field name contains a dot, it is a embeddedable object and we need to split the field name + if (str_contains($field, '.')) { + [$embedded, $embedded_field] = explode('.', $field); + + $elementClass = new ReflectionClass($element::class); + $property = $elementClass->getProperty($embedded); + $embeddedClass = $property->getValue($element); + + $embeddedReflection = new ReflectionClass($embeddedClass::class); + $property = $embeddedReflection->getProperty($embedded_field); + $target_element = $embeddedClass; + } else { + $reflection = new ReflectionClass($element::class); + $property = $reflection->getProperty($field); + $target_element = $element; + } //Check if the property is an BackedEnum, then convert the int or float value to an enum instance if ((is_string($new_value) || is_int($new_value)) @@ -253,6 +291,6 @@ class TimeTravel $new_value = $enum_class::from($new_value); } - $property->setValue($element, $new_value); + $property->setValue($target_element, $new_value); } } diff --git a/src/Services/Misc/ConsoleInfoHelper.php b/src/Services/Misc/ConsoleInfoHelper.php index f529f74a..98de5e07 100644 --- a/src/Services/Misc/ConsoleInfoHelper.php +++ b/src/Services/Misc/ConsoleInfoHelper.php @@ -36,6 +36,7 @@ class ConsoleInfoHelper /** * Returns the username of the user who started the current script if possible. * @return string|null the username of the user who started the current script if possible, null otherwise + * @noinspection PhpUndefinedFunctionInspection */ public function getCLIUser(): ?string { diff --git a/src/Services/Misc/FAIconGenerator.php b/src/Services/Misc/FAIconGenerator.php index 18db1fad..2ea727af 100644 --- a/src/Services/Misc/FAIconGenerator.php +++ b/src/Services/Misc/FAIconGenerator.php @@ -24,7 +24,6 @@ namespace App\Services\Misc; use App\Entity\Attachments\Attachment; use function in_array; -use InvalidArgumentException; /** * @see \App\Tests\Services\Misc\FAIconGeneratorTest diff --git a/src/Services/OAuth/OAuthTokenManager.php b/src/Services/OAuth/OAuthTokenManager.php index 1f6f6b51..9c22503b 100644 --- a/src/Services/OAuth/OAuthTokenManager.php +++ b/src/Services/OAuth/OAuthTokenManager.php @@ -47,11 +47,10 @@ final class OAuthTokenManager $tokenEntity = $this->entityManager->getRepository(OAuthToken::class)->findOneBy(['name' => $app_name]); //If the token was already existing, we just replace it with the new one - if ($tokenEntity) { + if ($tokenEntity !== null) { $tokenEntity->replaceWithNewToken($token); - //@phpstan-ignore-next-line - $this->entityManager->flush($tokenEntity); + $this->entityManager->flush(); //We are done return $tokenEntity; @@ -60,8 +59,8 @@ final class OAuthTokenManager //If the token was not existing, we create a new one $tokenEntity = OAuthToken::fromAccessToken($token, $app_name); $this->entityManager->persist($tokenEntity); - //@phpstan-ignore-next-line - $this->entityManager->flush($tokenEntity); + + $this->entityManager->flush(); return $tokenEntity; } @@ -97,8 +96,8 @@ final class OAuthTokenManager { $token = $this->getToken($app_name); - if (!$token) { - throw new \Exception('No token was saved yet for '.$app_name); + if ($token === null) { + throw new \RuntimeException('No token was saved yet for '.$app_name); } $client = $this->clientRegistry->getClient($app_name); @@ -113,9 +112,7 @@ final class OAuthTokenManager //Persist the token $token->replaceWithNewToken($new_token); - - //@phpstan-ignore-next-line - $this->entityManager->flush($token); + $this->entityManager->flush(); return $token; } @@ -131,7 +128,7 @@ final class OAuthTokenManager $token = $this->getToken($app_name); //If the token is not existing, we return null - if (!$token) { + if ($token === null) { return null; } diff --git a/src/Services/Parameters/ParameterExtractor.php b/src/Services/Parameters/ParameterExtractor.php index 9eaf946a..a133b282 100644 --- a/src/Services/Parameters/ParameterExtractor.php +++ b/src/Services/Parameters/ParameterExtractor.php @@ -88,7 +88,7 @@ class ParameterExtractor protected function stringToParam(string $input, string $class): ?AbstractParameter { $input = trim($input); - $regex = '/^(.*) *(?:=|:) *(.+)/u'; + $regex = '/^(.*) *(?:=|:)(?!\/) *(.+)/u'; $matches = []; preg_match($regex, $input, $matches); diff --git a/src/Services/Parts/PartLotWithdrawAddHelper.php b/src/Services/Parts/PartLotWithdrawAddHelper.php index 8e2d2d28..34ec4c1d 100644 --- a/src/Services/Parts/PartLotWithdrawAddHelper.php +++ b/src/Services/Parts/PartLotWithdrawAddHelper.php @@ -4,18 +4,20 @@ declare(strict_types=1); namespace App\Services\Parts; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\LogSystem\PartStockChangedLogEntry; use App\Entity\Parts\PartLot; use App\Services\LogSystem\EventCommentHelper; use App\Services\LogSystem\EventLogger; +use Doctrine\ORM\EntityManagerInterface; /** * @see \App\Tests\Services\Parts\PartLotWithdrawAddHelperTest */ final class PartLotWithdrawAddHelper { - public function __construct(private readonly EventLogger $eventLogger, private readonly EventCommentHelper $eventCommentHelper) + public function __construct(private readonly EventLogger $eventLogger, + private readonly EventCommentHelper $eventCommentHelper, private readonly EntityManagerInterface $entityManager) { } @@ -30,7 +32,7 @@ final class PartLotWithdrawAddHelper } //So far all other restrictions are defined at the storelocation level - if(!$partLot->getStorageLocation() instanceof Storelocation) { + if(!$partLot->getStorageLocation() instanceof StorageLocation) { return true; } //We can not add parts if the storage location of the lot is marked as full @@ -53,9 +55,10 @@ final class PartLotWithdrawAddHelper * @param PartLot $partLot The partLot from which the instock should be taken (which value should be decreased) * @param float $amount The amount of parts that should be taken from the part lot * @param string|null $comment The optional comment describing the reason for the withdrawal - * @return PartLot The modified part lot + * @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards. + * @param bool $delete_lot_if_empty If true, the part lot will be deleted if the amount is 0 after the withdrawal. */ - public function withdraw(PartLot $partLot, float $amount, ?string $comment = null): PartLot + public function withdraw(PartLot $partLot, float $amount, ?string $comment = null, ?\DateTimeInterface $action_timestamp = null, bool $delete_lot_if_empty = false): void { //Ensure that amount is positive if ($amount <= 0) { @@ -83,7 +86,7 @@ final class PartLotWithdrawAddHelper $oldAmount = $partLot->getAmount(); $partLot->setAmount($oldAmount - $amount); - $event = PartStockChangedLogEntry::withdraw($partLot, $oldAmount, $partLot->getAmount(), $part->getAmountSum() , $comment); + $event = PartStockChangedLogEntry::withdraw($partLot, $oldAmount, $partLot->getAmount(), $part->getAmountSum() , $comment, $action_timestamp); $this->eventLogger->log($event); //Apply the comment also to global events, so it gets associated with the elementChanged log entry @@ -91,7 +94,9 @@ final class PartLotWithdrawAddHelper $this->eventCommentHelper->setMessage($comment); } - return $partLot; + if ($delete_lot_if_empty && $partLot->getAmount() === 0.0) { + $this->entityManager->remove($partLot); + } } /** @@ -100,9 +105,10 @@ final class PartLotWithdrawAddHelper * @param PartLot $partLot The partLot from which the instock should be taken (which value should be decreased) * @param float $amount The amount of parts that should be taken from the part lot * @param string|null $comment The optional comment describing the reason for the withdrawal + * @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards. * @return PartLot The modified part lot */ - public function add(PartLot $partLot, float $amount, ?string $comment = null): PartLot + public function add(PartLot $partLot, float $amount, ?string $comment = null, ?\DateTimeInterface $action_timestamp = null): PartLot { if ($amount <= 0) { throw new \InvalidArgumentException('Amount must be positive'); @@ -123,7 +129,7 @@ final class PartLotWithdrawAddHelper $oldAmount = $partLot->getAmount(); $partLot->setAmount($oldAmount + $amount); - $event = PartStockChangedLogEntry::add($partLot, $oldAmount, $partLot->getAmount(), $part->getAmountSum() , $comment); + $event = PartStockChangedLogEntry::add($partLot, $oldAmount, $partLot->getAmount(), $part->getAmountSum() , $comment, $action_timestamp); $this->eventLogger->log($event); //Apply the comment also to global events, so it gets associated with the elementChanged log entry @@ -141,8 +147,10 @@ final class PartLotWithdrawAddHelper * @param PartLot $target The part lot to which the parts should be added * @param float $amount The amount of parts that should be moved * @param string|null $comment A comment describing the reason for the move + * @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards. + * @param bool $delete_lot_if_empty If true, the part lot will be deleted if the amount is 0 after the withdrawal. */ - public function move(PartLot $origin, PartLot $target, float $amount, ?string $comment = null): void + public function move(PartLot $origin, PartLot $target, float $amount, ?string $comment = null, ?\DateTimeInterface $action_timestamp = null, bool $delete_lot_if_empty = false): void { if ($amount <= 0) { throw new \InvalidArgumentException('Amount must be positive'); @@ -177,12 +185,16 @@ final class PartLotWithdrawAddHelper //And add it to the target $target->setAmount($target->getAmount() + $amount); - $event = PartStockChangedLogEntry::move($origin, $oldOriginAmount, $origin->getAmount(), $part->getAmountSum() , $comment, $target); + $event = PartStockChangedLogEntry::move($origin, $oldOriginAmount, $origin->getAmount(), $part->getAmountSum() , $comment, $target, $action_timestamp); $this->eventLogger->log($event); //Apply the comment also to global events, so it gets associated with the elementChanged log entry if (!$this->eventCommentHelper->isMessageSet() && ($comment !== null && $comment !== '')) { $this->eventCommentHelper->setMessage($comment); } + + if ($delete_lot_if_empty && $origin->getAmount() === 0.0) { + $this->entityManager->remove($origin); + } } } diff --git a/src/Services/Parts/PartsTableActionHandler.php b/src/Services/Parts/PartsTableActionHandler.php index 08c0715d..616df229 100644 --- a/src/Services/Parts/PartsTableActionHandler.php +++ b/src/Services/Parts/PartsTableActionHandler.php @@ -22,6 +22,7 @@ declare(strict_types=1); */ namespace App\Services\Parts; +use App\Entity\Parts\StorageLocation; use Symfony\Bundle\SecurityBundle\Security; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; @@ -29,13 +30,15 @@ use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; use App\Entity\Parts\PartLot; -use App\Repository\DBElementRepository; use App\Repository\PartRepository; use Doctrine\ORM\EntityManagerInterface; use InvalidArgumentException; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Contracts\Translation\TranslatableInterface; + +use function Symfony\Component\Translation\t; final class PartsTableActionHandler { @@ -54,7 +57,6 @@ final class PartsTableActionHandler { $id_array = explode(',', $ids); - /** @var PartRepository $repo */ $repo = $this->entityManager->getRepository(Part::class); return $repo->getElementsFromIDArray($id_array); @@ -63,8 +65,9 @@ final class PartsTableActionHandler /** * @param Part[] $selected_parts * @return RedirectResponse|null Returns a redirect response if the user should be redirected to another page, otherwise null + * //@param-out list|array $errors */ - public function handleAction(string $action, array $selected_parts, ?int $target_id, ?string $redirect_url = null): ?RedirectResponse + public function handleAction(string $action, array $selected_parts, ?int $target_id, ?string $redirect_url = null, array &$errors = []): ?RedirectResponse { if ($action === 'add_to_project') { return new RedirectResponse( @@ -163,6 +166,29 @@ implode(',', array_map(static fn (PartLot $lot) => $lot->getID(), $part->getPart $this->denyAccessUnlessGranted('@measurement_units.read'); $part->setPartUnit(null === $target_id ? null : $this->entityManager->find(MeasurementUnit::class, $target_id)); break; + case 'change_location': + $this->denyAccessUnlessGranted('@storelocations.read'); + //Retrieve the first part lot and set the location for it + $part_lots = $part->getPartLots(); + if ($part_lots->count() > 0) { + if ($part_lots->count() > 1) { + $errors[] = [ + 'part' => $part, + 'message' => t('parts.table.action_handler.error.part_lots_multiple'), + ]; + break; + } + + $part_lot = $part_lots->first(); + $part_lot->setStorageLocation(null === $target_id ? null : $this->entityManager->find(StorageLocation::class, $target_id)); + } else { //Create a new part lot if there are none + $part_lot = new PartLot(); + $part_lot->setPart($part); + $part_lot->setInstockUnknown(true); //We do not know how many parts are in stock, so we set it to true + $part_lot->setStorageLocation(null === $target_id ? null : $this->entityManager->find(StorageLocation::class, $target_id)); + $this->entityManager->persist($part_lot); + } + break; default: throw new InvalidArgumentException('The given action is unknown! ('.$action.')'); diff --git a/src/Services/System/BannerHelper.php b/src/Services/System/BannerHelper.php new file mode 100644 index 00000000..3d5daef9 --- /dev/null +++ b/src/Services/System/BannerHelper.php @@ -0,0 +1,56 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\System; + +/** + * Helper service to retrieve the banner of this Part-DB installation + */ +class BannerHelper +{ + public function __construct(private readonly string $project_dir, private readonly string $partdb_banner) + { + + } + + /** + * Retrieves the banner from either the env variable or the banner.md file. + * @return string + */ + public function getBanner(): string + { + $banner = $this->partdb_banner; + if ($banner === '') { + $banner_path = $this->project_dir + .DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'banner.md'; + + $tmp = file_get_contents($banner_path); + if (false === $tmp) { + throw new \RuntimeException('The banner file could not be read.'); + } + $banner = $tmp; + } + + return $banner; + } +} \ No newline at end of file diff --git a/src/Services/System/UpdateAvailableManager.php b/src/Services/System/UpdateAvailableManager.php new file mode 100644 index 00000000..31cb3266 --- /dev/null +++ b/src/Services/System/UpdateAvailableManager.php @@ -0,0 +1,143 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\System; + +use Psr\Log\LoggerInterface; +use Shivas\VersioningBundle\Service\VersionManagerInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Cache\ItemInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Version\Version; + +/** + * This class checks if a new version of Part-DB is available. + */ +class UpdateAvailableManager +{ + + private const API_URL = 'https://api.github.com/repos/Part-DB/Part-DB-server/releases/latest'; + private const CACHE_KEY = 'uam_latest_version'; + private const CACHE_TTL = 60 * 60 * 24 * 2; // 2 day + + public function __construct(private readonly HttpClientInterface $httpClient, + private readonly CacheInterface $updateCache, private readonly VersionManagerInterface $versionManager, + private readonly bool $check_for_updates, private readonly LoggerInterface $logger, + #[Autowire(param: 'kernel.debug')] private readonly bool $is_dev_mode) + { + + } + + /** + * Gets the latest version of Part-DB as string (e.g. "1.2.3"). + * This value is cached for 2 days. + * @return string + */ + public function getLatestVersionString(): string + { + return $this->getLatestVersionInfo()['version']; + } + + /** + * Gets the latest version of Part-DB as Version object. + */ + public function getLatestVersion(): Version + { + return Version::fromString($this->getLatestVersionString()); + } + + /** + * Gets the URL to the latest version of Part-DB on GitHub. + * @return string + */ + public function getLatestVersionUrl(): string + { + return $this->getLatestVersionInfo()['url']; + } + + /** + * Checks if a new version of Part-DB is available. This value is cached for 2 days. + * @return bool + */ + public function isUpdateAvailable(): bool + { + //If we don't want to check for updates, we can return false + if (!$this->check_for_updates) { + return false; + } + + $latestVersion = $this->getLatestVersion(); + $currentVersion = $this->versionManager->getVersion(); + + return $latestVersion->isGreaterThan($currentVersion); + } + + /** + * Get the latest version info. The value is cached for 2 days. + * @return array + * @phpstan-return array{version: string, url: string} + */ + private function getLatestVersionInfo(): array + { + //If we don't want to check for updates, we can return dummy data + if (!$this->check_for_updates) { + return [ + 'version' => '0.0.1', + 'url' => 'update-checking-disabled' + ]; + } + + return $this->updateCache->get(self::CACHE_KEY, function (ItemInterface $item) { + $item->expiresAfter(self::CACHE_TTL); + try { + $response = $this->httpClient->request('GET', self::API_URL); + $result = $response->toArray(); + $tag_name = $result['tag_name']; + + // Remove the leading 'v' from the tag name + $version = substr($tag_name, 1); + + return [ + 'version' => $version, + 'url' => $result['html_url'], + ]; + } catch (\Exception $e) { + //When we are in dev mode, throw the exception, otherwise just silently log it + if ($this->is_dev_mode) { + throw $e; + } + + //In the case of an error, try it again after half of the cache time + $item->expiresAfter(self::CACHE_TTL / 2); + + $this->logger->error('Checking for updates failed: ' . $e->getMessage()); + + return [ + 'version' => '0.0.1', + 'url' => 'update-checking-error' + ]; + } + }); + } +} \ No newline at end of file diff --git a/src/Services/Tools/StatisticsHelper.php b/src/Services/Tools/StatisticsHelper.php index 0ee736f9..00bb05c9 100644 --- a/src/Services/Tools/StatisticsHelper.php +++ b/src/Services/Tools/StatisticsHelper.php @@ -49,7 +49,7 @@ use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; use App\Repository\AttachmentRepository; @@ -113,7 +113,7 @@ class StatisticsHelper 'footprint' => Footprint::class, 'manufacturer' => Manufacturer::class, 'measurement_unit' => MeasurementUnit::class, - 'storelocation' => Storelocation::class, + 'storelocation' => StorageLocation::class, 'supplier' => Supplier::class, 'currency' => Currency::class, ]; @@ -122,7 +122,6 @@ class StatisticsHelper throw new InvalidArgumentException('No count for the given type available!'); } - /** @var EntityRepository $repo */ $repo = $this->em->getRepository($arr[$type]); return $repo->count([]); diff --git a/src/Services/Tools/TagFinder.php b/src/Services/Tools/TagFinder.php index bfc7c9db..80c89e0f 100644 --- a/src/Services/Tools/TagFinder.php +++ b/src/Services/Tools/TagFinder.php @@ -66,7 +66,7 @@ class TagFinder $qb->select('p.tags') ->from(Part::class, 'p') - ->where('p.tags LIKE ?1') + ->where('ILIKE(p.tags, ?1) = TRUE') ->setMaxResults($options['query_limit']) //->orderBy('RAND()') ->setParameter(1, '%'.$keyword.'%'); diff --git a/src/Services/Trees/NodesListBuilder.php b/src/Services/Trees/NodesListBuilder.php index 66299185..e65fa37e 100644 --- a/src/Services/Trees/NodesListBuilder.php +++ b/src/Services/Trees/NodesListBuilder.php @@ -22,14 +22,15 @@ declare(strict_types=1); namespace App\Services\Trees; -use App\Entity\Attachments\AttachmentContainingDBElement; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Base\AbstractStructuralDBElement; use App\Repository\AttachmentContainingDBElementRepository; use App\Repository\DBElementRepository; +use App\Repository\NamedDBElementRepository; use App\Repository\StructuralDBElementRepository; -use App\Services\UserSystem\UserCacheKeyGenerator; +use App\Services\Cache\ElementCacheTagGenerator; +use App\Services\Cache\UserCacheKeyGenerator; use Doctrine\ORM\EntityManagerInterface; use Symfony\Contracts\Cache\ItemInterface; use Symfony\Contracts\Cache\TagAwareCacheInterface; @@ -40,19 +41,23 @@ use Symfony\Contracts\Cache\TagAwareCacheInterface; */ class NodesListBuilder { - public function __construct(protected EntityManagerInterface $em, protected TagAwareCacheInterface $cache, protected UserCacheKeyGenerator $keyGenerator) - { + public function __construct( + protected EntityManagerInterface $em, + protected TagAwareCacheInterface $cache, + protected UserCacheKeyGenerator $keyGenerator, + protected ElementCacheTagGenerator $tagGenerator, + ) { } /** * Gets a flattened hierarchical tree. Useful for generating option lists. * In difference to the Repository Function, the results here are cached. * - * @template T of AbstractDBElement + * @template T of AbstractNamedDBElement * - * @param string $class_name the class name of the entity you want to retrieve + * @param string $class_name the class name of the entity you want to retrieve * @phpstan-param class-string $class_name - * @param AbstractStructuralDBElement|null $parent This entity will be used as root element. Set to null, to use global root + * @param AbstractStructuralDBElement|null $parent This entity will be used as root element. Set to null, to use global root * * @return AbstractDBElement[] a flattened list containing the tree elements * @phpstan-return list @@ -66,7 +71,7 @@ class NodesListBuilder $ids = $this->getFlattenedIDs($class_name, $parent); //Retrieve the elements from the IDs, the order is the same as in the $ids array - /** @var DBElementRepository $repo */ + /** @var NamedDBElementRepository $repo */ $repo = $this->em->getRepository($class_name); if ($repo instanceof AttachmentContainingDBElementRepository) { @@ -78,7 +83,9 @@ class NodesListBuilder /** * This functions returns the (cached) list of the IDs of the elements for the flattened tree. + * @template T of AbstractNamedDBElement * @param string $class_name + * @phpstan-param class-string $class_name * @param AbstractStructuralDBElement|null $parent * @return int[] */ @@ -86,17 +93,19 @@ class NodesListBuilder { $parent_id = $parent instanceof AbstractStructuralDBElement ? $parent->getID() : '0'; // Backslashes are not allowed in cache keys - $secure_class_name = str_replace('\\', '_', $class_name); + $secure_class_name = $this->tagGenerator->getElementTypeCacheTag($class_name); $key = 'list_'.$this->keyGenerator->generateKey().'_'.$secure_class_name.$parent_id; return $this->cache->get($key, function (ItemInterface $item) use ($class_name, $parent, $secure_class_name) { // Invalidate when groups, an element with the class or the user changes $item->tag(['groups', 'tree_list', $this->keyGenerator->generateKey(), $secure_class_name]); - /** @var StructuralDBElementRepository $repo */ + /** @var NamedDBElementRepository $repo */ $repo = $this->em->getRepository($class_name); - return array_map(fn(AbstractDBElement $element) => $element->getID(), $repo->getFlatList($parent)); + return array_map(static fn(AbstractDBElement $element) => $element->getID(), + //@phpstan-ignore-next-line For some reason phpstan does not understand that $repo is a StructuralDBElementRepository + $repo->getFlatList($parent)); }); } @@ -105,7 +114,7 @@ class NodesListBuilder * The value is cached for performance reasons. * * @template T of AbstractStructuralDBElement - * @param T $element + * @param T $element * @return AbstractStructuralDBElement[] * * @phpstan-return list diff --git a/src/Services/Trees/SidebarTreeUpdater.php b/src/Services/Trees/SidebarTreeUpdater.php index 0d7ccee9..c0f93b1f 100644 --- a/src/Services/Trees/SidebarTreeUpdater.php +++ b/src/Services/Trees/SidebarTreeUpdater.php @@ -22,7 +22,6 @@ declare(strict_types=1); */ namespace App\Services\Trees; -use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; use Symfony\Contracts\Cache\TagAwareCacheInterface; @@ -50,7 +49,7 @@ final class SidebarTreeUpdater //This tag and therfore this whole cache gets cleared by TreeCacheInvalidationListener when a structural element is changed $item->tag('sidebar_tree_update'); - return new \DateTime(); + return new \DateTimeImmutable(); }); } } diff --git a/src/Services/Trees/ToolsTreeBuilder.php b/src/Services/Trees/ToolsTreeBuilder.php index b0fafb4f..18571306 100644 --- a/src/Services/Trees/ToolsTreeBuilder.php +++ b/src/Services/Trees/ToolsTreeBuilder.php @@ -22,22 +22,22 @@ declare(strict_types=1); namespace App\Services\Trees; -use Symfony\Bundle\SecurityBundle\Security; use App\Entity\Attachments\AttachmentType; -use App\Entity\ProjectSystem\Project; use App\Entity\LabelSystem\LabelProfile; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\Part; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; use App\Entity\PriceInformations\Currency; +use App\Entity\ProjectSystem\Project; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; use App\Helpers\Trees\TreeViewNode; -use App\Services\UserSystem\UserCacheKeyGenerator; +use App\Services\Cache\UserCacheKeyGenerator; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Contracts\Cache\ItemInterface; use Symfony\Contracts\Cache\TagAwareCacheInterface; @@ -182,7 +182,7 @@ class ToolsTreeBuilder $this->urlGenerator->generate('manufacturer_new') ))->setIcon('fa-fw fa-treeview fa-solid fa-industry'); } - if ($this->security->isGranted('read', new Storelocation())) { + if ($this->security->isGranted('read', new StorageLocation())) { $nodes[] = (new TreeViewNode( $this->translator->trans('tree.tools.edit.storelocation'), $this->urlGenerator->generate('store_location_new') diff --git a/src/Services/Trees/TreeViewGenerator.php b/src/Services/Trees/TreeViewGenerator.php index 75e0f57c..23d6a406 100644 --- a/src/Services/Trees/TreeViewGenerator.php +++ b/src/Services/Trees/TreeViewGenerator.php @@ -25,17 +25,19 @@ namespace App\Services\Trees; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Base\AbstractStructuralDBElement; -use App\Entity\ProjectSystem\Project; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; use App\Entity\Parts\Manufacturer; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use App\Entity\Parts\Supplier; +use App\Entity\ProjectSystem\Project; use App\Helpers\Trees\TreeViewNode; use App\Helpers\Trees\TreeViewNodeIterator; +use App\Repository\NamedDBElementRepository; use App\Repository\StructuralDBElementRepository; +use App\Services\Cache\ElementCacheTagGenerator; +use App\Services\Cache\UserCacheKeyGenerator; use App\Services\EntityURLGenerator; -use App\Services\UserSystem\UserCacheKeyGenerator; use Doctrine\ORM\EntityManagerInterface; use InvalidArgumentException; use RecursiveIteratorIterator; @@ -51,25 +53,72 @@ use function count; */ class TreeViewGenerator { - public function __construct(protected EntityURLGenerator $urlGenerator, protected EntityManagerInterface $em, protected TagAwareCacheInterface $cache, - protected UserCacheKeyGenerator $keyGenerator, protected TranslatorInterface $translator, private UrlGeneratorInterface $router, - protected bool $rootNodeExpandedByDefault, protected bool $rootNodeEnabled) + public function __construct( + protected EntityURLGenerator $urlGenerator, + protected EntityManagerInterface $em, + protected TagAwareCacheInterface $cache, + protected ElementCacheTagGenerator $tagGenerator, + protected UserCacheKeyGenerator $keyGenerator, + protected TranslatorInterface $translator, + private readonly UrlGeneratorInterface $router, + protected bool $rootNodeExpandedByDefault, + protected bool $rootNodeEnabled, + + ) { + } + + /** + * Gets a TreeView list for the entities of the given class. + * The result is cached, if the full tree should be shown and no element should be selected. + * + * @param string $class The class for which the treeView should be generated + * @param AbstractStructuralDBElement|null $parent The root nodes in the tree should have this element as parent (use null, if you want to get all entities) + * @param string $mode The link type that will be generated for the hyperlink section of each node (see EntityURLGenerator for possible values). + * Set to empty string, to disable href field. + * @param AbstractDBElement|null $selectedElement The element that should be selected. If set to null, no element will be selected. + * + * @return TreeViewNode[] an array of TreeViewNode[] elements of the root elements + */ + public function getTreeView( + string $class, + ?AbstractStructuralDBElement $parent = null, + string $mode = 'list_parts', + ?AbstractDBElement $selectedElement = null + ): array { + //If we just want a part of a tree, don't cache it or select a specific element, don't cache it + if ($parent instanceof AbstractStructuralDBElement || $selectedElement instanceof AbstractDBElement) { + return $this->getTreeViewUncached($class, $parent, $mode, $selectedElement); + } + + $secure_class_name = $this->tagGenerator->getElementTypeCacheTag($class); + $key = 'sidebar_treeview_'.$this->keyGenerator->generateKey().'_'.$secure_class_name; + $key .= $mode; + + return $this->cache->get($key, function (ItemInterface $item) use ($class, $parent, $mode, $selectedElement, $secure_class_name) { + // Invalidate when groups, an element with the class or the user changes + $item->tag(['groups', 'tree_treeview', $this->keyGenerator->generateKey(), $secure_class_name]); + return $this->getTreeViewUncached($class, $parent, $mode, $selectedElement); + }); } /** * Gets a TreeView list for the entities of the given class. * - * @param string $class The class for which the treeView should be generated - * @param AbstractStructuralDBElement|null $parent The root nodes in the tree should have this element as parent (use null, if you want to get all entities) - * @param string $mode The link type that will be generated for the hyperlink section of each node (see EntityURLGenerator for possible values). + * @param string $class The class for which the treeView should be generated + * @param AbstractStructuralDBElement|null $parent The root nodes in the tree should have this element as parent (use null, if you want to get all entities) + * @param string $mode The link type that will be generated for the hyperlink section of each node (see EntityURLGenerator for possible values). * Set to empty string, to disable href field. - * @param AbstractDBElement|null $selectedElement The element that should be selected. If set to null, no element will be selected. + * @param AbstractDBElement|null $selectedElement The element that should be selected. If set to null, no element will be selected. * * @return TreeViewNode[] an array of TreeViewNode[] elements of the root elements */ - public function getTreeView(string $class, ?AbstractStructuralDBElement $parent = null, string $mode = 'list_parts', ?AbstractDBElement $selectedElement = null): array - { + private function getTreeViewUncached( + string $class, + ?AbstractStructuralDBElement $parent = null, + string $mode = 'list_parts', + ?AbstractDBElement $selectedElement = null + ): array { $head = []; $href_type = $mode; @@ -77,7 +126,8 @@ class TreeViewGenerator //When we use the newEdit type, add the New Element node. if ('newEdit' === $mode) { //Generate the url for the new node - $href = $this->urlGenerator->createURL(new $class()); + //DO NOT try to create an object from the class, as this might be an proxy, which can not be easily initialized, so just pass the class_name directly + $href = $this->urlGenerator->createURL($class); $new_node = new TreeViewNode($this->translator->trans('entity.tree.new'), $href); //When the id of the selected element is null, then we have a new element, and we need to select "new" node if (!$selectedElement instanceof AbstractDBElement || null === $selectedElement->getID()) { @@ -109,11 +159,11 @@ class TreeViewGenerator } if ($item->getNodes() !== null && $item->getNodes() !== []) { - $item->addTag((string) count($item->getNodes())); + $item->addTag((string)count($item->getNodes())); } if ($href_type !== '' && null !== $item->getId()) { - $entity = $this->em->getPartialReference($class, $item->getId()); + $entity = $this->em->find($class, $item->getId()); $item->setHref($this->urlGenerator->getURL($entity, $href_type)); } @@ -141,7 +191,7 @@ class TreeViewGenerator { return match ($class) { Category::class => $this->translator->trans('category.labelp'), - Storelocation::class => $this->translator->trans('storelocation.labelp'), + StorageLocation::class => $this->translator->trans('storelocation.labelp'), Footprint::class => $this->translator->trans('footprint.labelp'), Manufacturer::class => $this->translator->trans('manufacturer.labelp'), Supplier::class => $this->translator->trans('supplier.labelp'), @@ -154,12 +204,12 @@ class TreeViewGenerator { $icon = "fa-fw fa-treeview fa-solid "; return match ($class) { - Category::class => $icon . 'fa-tags', - Storelocation::class => $icon . 'fa-cube', - Footprint::class => $icon . 'fa-microchip', - Manufacturer::class => $icon . 'fa-industry', - Supplier::class => $icon . 'fa-truck', - Project::class => $icon . 'fa-archive', + Category::class => $icon.'fa-tags', + StorageLocation::class => $icon.'fa-cube', + Footprint::class => $icon.'fa-microchip', + Manufacturer::class => $icon.'fa-industry', + Supplier::class => $icon.'fa-truck', + Project::class => $icon.'fa-archive', default => null, }; } @@ -169,8 +219,9 @@ class TreeViewGenerator * Gets a tree of TreeViewNode elements. The root elements has $parent as parent. * The treeview is generic, that means the href are null and ID values are set. * - * @param string $class The class for which the tree should be generated - * @param AbstractStructuralDBElement|null $parent the parent the root elements should have + * @param string $class The class for which the tree should be generated + * @phpstan-param class-string $class + * @param AbstractStructuralDBElement|null $parent the parent the root elements should have * * @return TreeViewNode[] */ @@ -183,22 +234,21 @@ class TreeViewGenerator throw new InvalidArgumentException('$parent must be of the type $class!'); } - /** @var StructuralDBElementRepository $repo */ + /** @var NamedDBElementRepository $repo */ $repo = $this->em->getRepository($class); //If we just want a part of a tree, don't cache it if ($parent instanceof AbstractStructuralDBElement) { - return $repo->getGenericNodeTree($parent); + return $repo->getGenericNodeTree($parent); //@phpstan-ignore-line PHPstan does not seem to recognize, that we have a StructuralDBElementRepository here, which have 1 argument } - $secure_class_name = str_replace('\\', '_', $class); + $secure_class_name = $this->tagGenerator->getElementTypeCacheTag($class); $key = 'treeview_'.$this->keyGenerator->generateKey().'_'.$secure_class_name; return $this->cache->get($key, function (ItemInterface $item) use ($repo, $parent, $secure_class_name) { // Invalidate when groups, an element with the class or the user changes $item->tag(['groups', 'tree_treeview', $this->keyGenerator->generateKey(), $secure_class_name]); - - return $repo->getGenericNodeTree($parent); + return $repo->getGenericNodeTree($parent); //@phpstan-ignore-line }); } } diff --git a/src/Services/UserSystem/PasswordResetManager.php b/src/Services/UserSystem/PasswordResetManager.php index 2349297b..1a78cb60 100644 --- a/src/Services/UserSystem/PasswordResetManager.php +++ b/src/Services/UserSystem/PasswordResetManager.php @@ -59,8 +59,7 @@ class PasswordResetManager $user->setPwResetToken($this->passwordEncoder->hash($unencrypted_token)); //Determine the expiration datetime of - $expiration_date = new DateTime(); - $expiration_date->add(date_interval_create_from_date_string('1 day')); + $expiration_date = new \DateTimeImmutable("+1 day"); $user->setPwResetExpires($expiration_date); if ($user->getEmail() !== null && $user->getEmail() !== '') { @@ -97,8 +96,7 @@ class PasswordResetManager { //Try to find the user $repo = $this->em->getRepository(User::class); - /** @var User|null $user */ - $user = $repo->findOneBy(['name' => $username]); + $user = $repo->findByUsername($username); //If no user matching the name, show an error message if (!$user instanceof User) { @@ -106,7 +104,7 @@ class PasswordResetManager } //Check if token is expired yet - if ($user->getPwResetExpires() < new DateTime()) { + if ($user->getPwResetExpires() < new \DateTimeImmutable()) { return false; } @@ -120,7 +118,7 @@ class PasswordResetManager //Remove token $user->setPwResetToken(null); - $user->setPwResetExpires(new DateTime()); + $user->setPwResetExpires(new \DateTimeImmutable()); //Save to DB $this->em->flush(); diff --git a/src/Services/UserSystem/PermissionManager.php b/src/Services/UserSystem/PermissionManager.php index fa591a91..663a7b67 100644 --- a/src/Services/UserSystem/PermissionManager.php +++ b/src/Services/UserSystem/PermissionManager.php @@ -22,7 +22,6 @@ declare(strict_types=1); namespace App\Services\UserSystem; -use App\Entity\Base\AbstractStructuralDBElement; use App\Configuration\PermissionsConfiguration; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; @@ -41,7 +40,7 @@ use Symfony\Component\Yaml\Yaml; */ class PermissionManager { - protected $permission_structure; + protected array $permission_structure; protected string $cache_file; /** @@ -125,6 +124,40 @@ class PermissionManager return null; //The inherited value is never resolved. Should be treated as false, in Voters. } + /** + * Same as inherit(), but it checks if the access token has the required role. + * @param User $user the user for which the operation should be checked + * @param array $roles The roles associated with the authentication token + * @param string $permission the name of the permission for which should be checked + * @param string $operation the name of the operation for which should be checked + * + * @return bool|null true, if the user is allowed to do the operation (ALLOW), false if not (DISALLOW), and null, + * if the value is set to inherit + */ + public function inheritWithAPILevel(User $user, array $roles, string $permission, string $operation): ?bool + { + //Check that the permission/operation combination is valid + if (! $this->isValidOperation($permission, $operation)) { + throw new InvalidArgumentException('The permission/operation combination "'.$permission.'/'.$operation.'" is not valid!'); + } + + //Get what API level we require for the permission/operation + $level_role = $this->permission_structure['perms'][$permission]['operations'][$operation]['apiTokenRole']; + + //When no role was set (or it is null), then the operation is blocked for API access + if (null === $level_role) { + return false; + } + + //Otherwise check if the token has the required role, if not, then the operation is blocked for API access + if (!in_array($level_role, $roles, true)) { + return false; + } + + //If we have the required role, then we can check the permission + return $this->inherit($user, $permission, $operation); + } + /** * Sets the new value for the operation. * @@ -195,12 +228,16 @@ class PermissionManager /** * This functions sets all operations mentioned in the alsoSet value of a permission, so that the structure is always valid. + * This function should be called after every setPermission() call. + * @return bool true if values were changed/corrected, false if not */ - public function ensureCorrectSetOperations(HasPermissionsInterface $user): void + public function ensureCorrectSetOperations(HasPermissionsInterface $user): bool { //If we have changed anything on the permission structure due to the alsoSet value, this becomes true, so we //redo the whole process, to ensure that all alsoSet values are set recursively. + $return_value = false; + do { $anything_changed = false; //Reset the variable for the next iteration @@ -219,12 +256,15 @@ class PermissionManager $this->setPermission($user, $set_perm, $set_op, true); //Mark the change, so we redo the whole process $anything_changed = true; + $return_value = true; } } } } } } while($anything_changed); + + return $return_value; } /** @@ -271,6 +311,27 @@ class PermissionManager } } + /** + * This function checks if the given user has any permission set to allow, either directly or inherited. + * @param User $user + * @return bool + */ + public function hasAnyPermissionSetToAllowInherited(User $user): bool + { + //Iterate over all permissions + foreach ($this->permission_structure['perms'] as $perm_key => $permission) { + //Iterate over all operations of the permission + foreach ($permission['operations'] as $op_key => $op) { + //Check if the user has the permission set to allow + if ($this->inherit($user, $perm_key, $op_key) === true) { + return true; + } + } + } + + return false; + } + protected function generatePermissionStructure() { $cache = new ConfigCache($this->cache_file, $this->kernel_debug_enabled); diff --git a/src/Services/UserSystem/PermissionPresetsHelper.php b/src/Services/UserSystem/PermissionPresetsHelper.php index ea2391f7..eeb80f61 100644 --- a/src/Services/UserSystem/PermissionPresetsHelper.php +++ b/src/Services/UserSystem/PermissionPresetsHelper.php @@ -107,6 +107,8 @@ class PermissionPresetsHelper //Allow to manage Oauth tokens $this->permissionResolver->setPermission($perm_holder, 'system', 'manage_oauth_tokens', PermissionData::ALLOW); + //Allow to show updates + $this->permissionResolver->setPermission($perm_holder, 'system', 'show_updates', PermissionData::ALLOW); } diff --git a/src/Services/UserSystem/PermissionSchemaUpdater.php b/src/Services/UserSystem/PermissionSchemaUpdater.php index 5fb08182..104800dc 100644 --- a/src/Services/UserSystem/PermissionSchemaUpdater.php +++ b/src/Services/UserSystem/PermissionSchemaUpdater.php @@ -25,6 +25,7 @@ namespace App\Services\UserSystem; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\PermissionData; use App\Entity\UserSystem\User; +use App\Helpers\TrinaryLogicHelper; use App\Security\Interfaces\HasPermissionsInterface; /** @@ -138,4 +139,22 @@ class PermissionSchemaUpdater $holder->getPermissions()->removePermission('devices'); } } + + private function upgradeSchemaToVersion3(HasPermissionsInterface $holder): void //@phpstan-ignore-line This is called via reflection + { + $permissions = $holder->getPermissions(); + + //If the system.show_updates permission is not defined yet, set it to true, if the user can view server info, server logs or edit users or groups + if (!$permissions->isPermissionSet('system', 'show_updates')) { + + $new_value = TrinaryLogicHelper::or( + $permissions->getPermissionValue('system', 'server_infos'), + $permissions->getPermissionValue('system', 'show_logs'), + $permissions->getPermissionValue('users', 'edit'), + $permissions->getPermissionValue('groups', 'edit') + ); + + $permissions->setPermissionValue('system', 'show_updates', $new_value); + } + } } diff --git a/src/Services/UserSystem/TFA/DecoratedGoogleAuthenticator.php b/src/Services/UserSystem/TFA/DecoratedGoogleAuthenticator.php index 562358c5..05e5ed4c 100644 --- a/src/Services/UserSystem/TFA/DecoratedGoogleAuthenticator.php +++ b/src/Services/UserSystem/TFA/DecoratedGoogleAuthenticator.php @@ -1,4 +1,7 @@ . */ - namespace App\Services\UserSystem\TFA; use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface; -use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticator; use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticatorInterface; use Symfony\Component\DependencyInjection\Attribute\AsDecorator; use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated; @@ -33,8 +34,8 @@ class DecoratedGoogleAuthenticator implements GoogleAuthenticatorInterface public function __construct( #[AutowireDecorated] - private GoogleAuthenticatorInterface $inner, - private RequestStack $requestStack) + private readonly GoogleAuthenticatorInterface $inner, + private readonly RequestStack $requestStack) { } @@ -68,4 +69,4 @@ class DecoratedGoogleAuthenticator implements GoogleAuthenticatorInterface { return $this->inner->generateSecret(); } -} \ No newline at end of file +} diff --git a/src/Services/UserSystem/UserAvatarHelper.php b/src/Services/UserSystem/UserAvatarHelper.php index dd06ce1b..a694fa77 100644 --- a/src/Services/UserSystem/UserAvatarHelper.php +++ b/src/Services/UserSystem/UserAvatarHelper.php @@ -20,24 +20,34 @@ declare(strict_types=1); * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + namespace App\Services\UserSystem; -use Imagine\Exception\RuntimeException; use App\Entity\Attachments\Attachment; use App\Entity\Attachments\AttachmentType; +use App\Entity\Attachments\AttachmentUpload; use App\Entity\Attachments\UserAttachment; use App\Entity\UserSystem\User; use App\Services\Attachments\AttachmentSubmitHandler; use App\Services\Attachments\AttachmentURLGenerator; use Doctrine\ORM\EntityManagerInterface; -use Liip\ImagineBundle\Service\FilterService; use Symfony\Component\Asset\Packages; use Symfony\Component\HttpFoundation\File\UploadedFile; class UserAvatarHelper { - public function __construct(private readonly bool $use_gravatar, private readonly Packages $packages, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly FilterService $filterService, private readonly EntityManagerInterface $entityManager, private readonly AttachmentSubmitHandler $submitHandler) - { + /** + * Path to the default avatar image (must not start with a slash, or the asset package will not work) + */ + public const IMG_DEFAULT_AVATAR_PATH = 'img/default_avatar.svg'; + + public function __construct( + private readonly bool $use_gravatar, + private readonly Packages $packages, + private readonly AttachmentURLGenerator $attachmentURLGenerator, + private readonly EntityManagerInterface $entityManager, + private readonly AttachmentSubmitHandler $submitHandler + ) { } @@ -51,7 +61,7 @@ class UserAvatarHelper //Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture) if ($user->getMasterPictureAttachment() instanceof Attachment) { return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_md') - ?? throw new RuntimeException('Could not generate thumbnail URL'); + ?? $this->packages->getUrl(self::IMG_DEFAULT_AVATAR_PATH); } //If not check if gravatar is enabled (then use gravatar URL) @@ -60,7 +70,7 @@ class UserAvatarHelper } //Fallback to the default avatar picture - return $this->packages->getUrl('/img/default_avatar.png'); + return $this->packages->getUrl(self::IMG_DEFAULT_AVATAR_PATH); } public function getAvatarSmURL(User $user): string @@ -68,7 +78,7 @@ class UserAvatarHelper //Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture) if ($user->getMasterPictureAttachment() instanceof Attachment) { return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_xs') - ?? throw new RuntimeException('Could not generate thumbnail URL');; + ?? $this->packages->getUrl(self::IMG_DEFAULT_AVATAR_PATH); } //If not check if gravatar is enabled (then use gravatar URL) @@ -76,13 +86,8 @@ class UserAvatarHelper return $this->getGravatar($user, 50); //50px wide picture } - try { - //Otherwise we can serve the relative path via Asset component - return $this->filterService->getUrlOfFilteredImage('/img/default_avatar.png', 'thumbnail_xs'); - } catch (RuntimeException) { - //If the filter fails, we can not serve the thumbnail and fall back to the original image and log an warning - return $this->packages->getUrl('/img/default_avatar.png'); - } + //Otherwise serve the default image (its an SVG, so we dont need to thumbnail it) + return $this->packages->getUrl(self::IMG_DEFAULT_AVATAR_PATH); } public function getAvatarMdURL(User $user): string @@ -90,7 +95,7 @@ class UserAvatarHelper //Check if the user has a master attachment defined (meaning he has explicitly defined a profile picture) if ($user->getMasterPictureAttachment() instanceof Attachment) { return $this->attachmentURLGenerator->getThumbnailURL($user->getMasterPictureAttachment(), 'thumbnail_sm') - ?? throw new RuntimeException('Could not generate thumbnail URL'); + ?? $this->packages->getUrl(self::IMG_DEFAULT_AVATAR_PATH); } //If not check if gravatar is enabled (then use gravatar URL) @@ -98,20 +103,15 @@ class UserAvatarHelper return $this->getGravatar($user, 150); } - try { - //Otherwise we can serve the relative path via Asset component - return $this->filterService->getUrlOfFilteredImage('/img/default_avatar.png', 'thumbnail_xs'); - } catch (RuntimeException) { - //If the filter fails, we can not serve the thumbnail and fall back to the original image and log an warning - return $this->packages->getUrl('/img/default_avatar.png'); - } + //Otherwise serve the default image (its an SVG, so we dont need to thumbnail it) + return $this->packages->getUrl(self::IMG_DEFAULT_AVATAR_PATH); } /** * Get either a Gravatar URL or complete image tag for a specified email address. * - * @param User $user The user for which the gravator should be generated + * @param User $user The user for which the gravator should be generated * @param int $s Size in pixels, defaults to 80px [ 1 - 2048 ] * @param string $d Default imageset to use [ 404 | mm | identicon | monsterid | wavatar ] * @param string $r Maximum rating (inclusive) [ g | pg | r | x ] @@ -129,7 +129,7 @@ class UserAvatarHelper $url = 'https://www.gravatar.com/avatar/'; $url .= md5(strtolower(trim($email))); - return $url . "?s=${s}&d=${d}&r=${r}"; + return $url."?s=$s&d=$d&r=$r"; } /** @@ -157,11 +157,10 @@ class UserAvatarHelper } $attachment->setAttachmentType($attachment_type); - //$user->setMasterPictureAttachment($attachment); } //Handle the upload - $this->submitHandler->handleFormSubmit($attachment, $file); + $this->submitHandler->handleUpload($attachment, new AttachmentUpload(file: $file)); //Set attachment as master picture $user->setMasterPictureAttachment($attachment); diff --git a/src/Services/UserSystem/VoterHelper.php b/src/Services/UserSystem/VoterHelper.php new file mode 100644 index 00000000..644351f4 --- /dev/null +++ b/src/Services/UserSystem/VoterHelper.php @@ -0,0 +1,127 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\UserSystem; + +use App\Entity\UserSystem\User; +use App\Repository\UserRepository; +use App\Security\ApiTokenAuthenticatedToken; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + +/** + * @see \App\Tests\Services\UserSystem\VoterHelperTest + */ +final class VoterHelper +{ + private readonly UserRepository $userRepository; + + public function __construct(private readonly PermissionManager $permissionManager, private readonly EntityManagerInterface $entityManager) + { + $this->userRepository = $this->entityManager->getRepository(User::class); + } + + /** + * Checks if the operation on the given permission is granted for the given token. + * Similar to isGrantedTrinary, but returns false if the permission is not granted. + * @param TokenInterface $token The token to check + * @param string $permission The permission to check + * @param string $operation The operation to check + * @return bool + */ + public function isGranted(TokenInterface $token, string $permission, string $operation): bool + { + return $this->isGrantedTrinary($token, $permission, $operation) ?? false; + } + + /** + * Checks if the operation on the given permission is granted for the given token. + * The result is returned in trinary value, where null means inherted from the parent. + * @param TokenInterface $token The token to check + * @param string $permission The permission to check + * @param string $operation The operation to check + * @return bool|null The result of the check. Null means inherted from the parent. + */ + public function isGrantedTrinary(TokenInterface $token, string $permission, string $operation): ?bool + { + $user = $token->getUser(); + + if ($user instanceof User) { + //A disallowed user is not allowed to do anything... + if ($user->isDisabled()) { + return false; + } + } else { + //Try to resolve the user from the token + $user = $this->resolveUser($token); + } + + //If the token is a APITokenAuthenticated + if ($token instanceof ApiTokenAuthenticatedToken) { + //Use the special API token checker + return $this->permissionManager->inheritWithAPILevel($user, $token->getRoleNames(), $permission, $operation); + } + + //Otherwise use the normal permission checker + return $this->permissionManager->inherit($user, $permission, $operation); + } + + /** + * Resolves the user from the given token. If the token is anonymous, the anonymous user is returned. + * @return User + */ + public function resolveUser(TokenInterface $token): User + { + $user = $token->getUser(); + //If the user is a User entity, just return it + if ($user instanceof User) { + return $user; + } + + //If the user is null, return the anonymous user + if ($user === null) { + $user = $this->userRepository->getAnonymousUser(); + if (!$user instanceof User) { + throw new \RuntimeException('The anonymous user could not be resolved.'); + } + return $user; + } + + //Otherwise throw an exception + throw new \RuntimeException('The user could not be resolved.'); + } + + /** + * Checks if the permission operation combination with the given names is existing. + * Just a proxy to the permission manager. + * + * @param string $permission the name of the permission which should be checked + * @param string $operation the name of the operation which should be checked + * + * @return bool true if the given permission operation combination is existing + */ + public function isValidOperation(string $permission, string $operation): bool + { + return $this->permissionManager->isValidOperation($permission, $operation); + } +} \ No newline at end of file diff --git a/src/State/CurrentApiTokenProvider.php b/src/State/CurrentApiTokenProvider.php new file mode 100644 index 00000000..f989d504 --- /dev/null +++ b/src/State/CurrentApiTokenProvider.php @@ -0,0 +1,49 @@ +. + */ + +declare(strict_types=1); + + +namespace App\State; + +use ApiPlatform\Metadata\Operation; +use ApiPlatform\State\ProviderInterface; +use App\Security\ApiTokenAuthenticatedToken; +use Symfony\Bundle\SecurityBundle\Security; + + +class CurrentApiTokenProvider implements ProviderInterface +{ + + public function __construct(private readonly Security $security) + { + + } + + public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + $securityToken = $this->security->getToken(); + if (!$securityToken instanceof ApiTokenAuthenticatedToken) { + return null; + } + + return $securityToken->getApiToken(); + } +} \ No newline at end of file diff --git a/src/State/PartDBInfoProvider.php b/src/State/PartDBInfoProvider.php new file mode 100644 index 00000000..c6760ede --- /dev/null +++ b/src/State/PartDBInfoProvider.php @@ -0,0 +1,44 @@ +versionManager->getVersion()->toString(), + git_branch: $this->gitVersionInfo->getGitBranchName(), + git_commit: $this->gitVersionInfo->getGitCommitHash(), + title: $this->partdb_title, + banner: $this->bannerHelper->getBanner(), + default_uri: $this->default_uri, + global_timezone: $this->global_timezone, + base_currency: $this->base_currency, + global_locale: $this->global_locale, + ); + } +} diff --git a/src/Translation/Fixes/SegmentAwareXliffFileDumper.php b/src/Translation/Fixes/SegmentAwareXliffFileDumper.php new file mode 100644 index 00000000..4b44ef01 --- /dev/null +++ b/src/Translation/Fixes/SegmentAwareXliffFileDumper.php @@ -0,0 +1,242 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Translation\Fixes; + +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use Symfony\Component\Translation\Dumper\FileDumper; +use Symfony\Component\Translation\MessageCatalogue; +use Symfony\Component\Translation\Exception\InvalidArgumentException; + +/** + * Backport of the XliffFile dumper from Symfony 7.2, which supports segment attributes and notes, this keeps the + * metadata when editing the translations from inside Symfony. + */ +#[AsDecorator("translation.dumper.xliff")] +class SegmentAwareXliffFileDumper extends FileDumper +{ + + public function __construct( + private string $extension = 'xlf', + ) { + } + + public function formatCatalogue(MessageCatalogue $messages, string $domain, array $options = []): string + { + $xliffVersion = '1.2'; + if (\array_key_exists('xliff_version', $options)) { + $xliffVersion = $options['xliff_version']; + } + + if (\array_key_exists('default_locale', $options)) { + $defaultLocale = $options['default_locale']; + } else { + $defaultLocale = \Locale::getDefault(); + } + + if ('1.2' === $xliffVersion) { + return $this->dumpXliff1($defaultLocale, $messages, $domain, $options); + } + if ('2.0' === $xliffVersion) { + return $this->dumpXliff2($defaultLocale, $messages, $domain); + } + + throw new InvalidArgumentException(\sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)); + } + + protected function getExtension(): string + { + return $this->extension; + } + + private function dumpXliff1(string $defaultLocale, MessageCatalogue $messages, ?string $domain, array $options = []): string + { + $toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony']; + if (\array_key_exists('tool_info', $options)) { + $toolInfo = array_merge($toolInfo, $options['tool_info']); + } + + $dom = new \DOMDocument('1.0', 'utf-8'); + $dom->formatOutput = true; + + $xliff = $dom->appendChild($dom->createElement('xliff')); + $xliff->setAttribute('version', '1.2'); + $xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2'); + + $xliffFile = $xliff->appendChild($dom->createElement('file')); + $xliffFile->setAttribute('source-language', str_replace('_', '-', $defaultLocale)); + $xliffFile->setAttribute('target-language', str_replace('_', '-', $messages->getLocale())); + $xliffFile->setAttribute('datatype', 'plaintext'); + $xliffFile->setAttribute('original', 'file.ext'); + + $xliffHead = $xliffFile->appendChild($dom->createElement('header')); + $xliffTool = $xliffHead->appendChild($dom->createElement('tool')); + foreach ($toolInfo as $id => $value) { + $xliffTool->setAttribute($id, $value); + } + + if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) { + $xliffPropGroup = $xliffHead->appendChild($dom->createElement('prop-group')); + foreach ($catalogueMetadata as $key => $value) { + $xliffProp = $xliffPropGroup->appendChild($dom->createElement('prop')); + $xliffProp->setAttribute('prop-type', $key); + $xliffProp->appendChild($dom->createTextNode($value)); + } + } + + $xliffBody = $xliffFile->appendChild($dom->createElement('body')); + foreach ($messages->all($domain) as $source => $target) { + $translation = $dom->createElement('trans-unit'); + + $translation->setAttribute('id', strtr(substr(base64_encode(hash('xxh128', $source, true)), 0, 7), '/+', '._')); + $translation->setAttribute('resname', $source); + + $s = $translation->appendChild($dom->createElement('source')); + $s->appendChild($dom->createTextNode($source)); + + // Does the target contain characters requiring a CDATA section? + $text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target); + + $targetElement = $dom->createElement('target'); + $metadata = $messages->getMetadata($source, $domain); + if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) { + foreach ($metadata['target-attributes'] as $name => $value) { + $targetElement->setAttribute($name, $value); + } + } + $t = $translation->appendChild($targetElement); + $t->appendChild($text); + + if ($this->hasMetadataArrayInfo('notes', $metadata)) { + foreach ($metadata['notes'] as $note) { + if (!isset($note['content'])) { + continue; + } + + $n = $translation->appendChild($dom->createElement('note')); + $n->appendChild($dom->createTextNode($note['content'])); + + if (isset($note['priority'])) { + $n->setAttribute('priority', $note['priority']); + } + + if (isset($note['from'])) { + $n->setAttribute('from', $note['from']); + } + } + } + + $xliffBody->appendChild($translation); + } + + return $dom->saveXML(); + } + + private function dumpXliff2(string $defaultLocale, MessageCatalogue $messages, ?string $domain): string + { + $dom = new \DOMDocument('1.0', 'utf-8'); + $dom->formatOutput = true; + + $xliff = $dom->appendChild($dom->createElement('xliff')); + $xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:2.0'); + $xliff->setAttribute('version', '2.0'); + $xliff->setAttribute('srcLang', str_replace('_', '-', $defaultLocale)); + $xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale())); + + $xliffFile = $xliff->appendChild($dom->createElement('file')); + if (str_ends_with($domain, MessageCatalogue::INTL_DOMAIN_SUFFIX)) { + $xliffFile->setAttribute('id', substr($domain, 0, -\strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX)).'.'.$messages->getLocale()); + } else { + $xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale()); + } + + if ($catalogueMetadata = $messages->getCatalogueMetadata('', $domain) ?? []) { + $xliff->setAttribute('xmlns:m', 'urn:oasis:names:tc:xliff:metadata:2.0'); + $xliffMetadata = $xliffFile->appendChild($dom->createElement('m:metadata')); + foreach ($catalogueMetadata as $key => $value) { + $xliffMeta = $xliffMetadata->appendChild($dom->createElement('prop')); + $xliffMeta->setAttribute('type', $key); + $xliffMeta->appendChild($dom->createTextNode($value)); + } + } + + foreach ($messages->all($domain) as $source => $target) { + $translation = $dom->createElement('unit'); + $translation->setAttribute('id', strtr(substr(base64_encode(hash('xxh128', $source, true)), 0, 7), '/+', '._')); + + if (\strlen($source) <= 80) { + $translation->setAttribute('name', $source); + } + + $metadata = $messages->getMetadata($source, $domain); + + // Add notes section + if ($this->hasMetadataArrayInfo('notes', $metadata)) { + $notesElement = $dom->createElement('notes'); + foreach ($metadata['notes'] as $note) { + $n = $dom->createElement('note'); + $n->appendChild($dom->createTextNode($note['content'] ?? '')); + unset($note['content']); + + foreach ($note as $name => $value) { + $n->setAttribute($name, $value); + } + $notesElement->appendChild($n); + } + $translation->appendChild($notesElement); + } + + $segment = $translation->appendChild($dom->createElement('segment')); + + if ($this->hasMetadataArrayInfo('segment-attributes', $metadata)) { + foreach ($metadata['segment-attributes'] as $name => $value) { + $segment->setAttribute($name, $value); + } + } + + $s = $segment->appendChild($dom->createElement('source')); + $s->appendChild($dom->createTextNode($source)); + + // Does the target contain characters requiring a CDATA section? + $text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target); + + $targetElement = $dom->createElement('target'); + if ($this->hasMetadataArrayInfo('target-attributes', $metadata)) { + foreach ($metadata['target-attributes'] as $name => $value) { + $targetElement->setAttribute($name, $value); + } + } + $t = $segment->appendChild($targetElement); + $t->appendChild($text); + + $xliffFile->appendChild($translation); + } + + return $dom->saveXML(); + } + + private function hasMetadataArrayInfo(string $key, ?array $metadata = null): bool + { + return is_iterable($metadata[$key] ?? null); + } +} \ No newline at end of file diff --git a/src/Translation/Fixes/SegmentAwareXliffFileLoader.php b/src/Translation/Fixes/SegmentAwareXliffFileLoader.php new file mode 100644 index 00000000..12455e87 --- /dev/null +++ b/src/Translation/Fixes/SegmentAwareXliffFileLoader.php @@ -0,0 +1,262 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Translation\Fixes; + +use Symfony\Component\Config\Resource\FileResource; +use Symfony\Component\Config\Util\Exception\InvalidXmlException; +use Symfony\Component\Config\Util\Exception\XmlParsingException; +use Symfony\Component\Config\Util\XmlUtils; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use Symfony\Component\Translation\Exception\InvalidResourceException; +use Symfony\Component\Translation\Exception\NotFoundResourceException; +use Symfony\Component\Translation\Exception\RuntimeException; +use Symfony\Component\Translation\Loader\LoaderInterface; +use Symfony\Component\Translation\MessageCatalogue; +use Symfony\Component\Translation\Util\XliffUtils; + +/** + * Backport of the XliffFile dumper from Symfony 7.2, which supports segment attributes and notes, this keeps the + * metadata when editing the translations from inside Symfony. + */ +#[AsDecorator("translation.loader.xliff")] +class SegmentAwareXliffFileLoader implements LoaderInterface +{ + public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue + { + if (!class_exists(XmlUtils::class)) { + throw new RuntimeException('Loading translations from the Xliff format requires the Symfony Config component.'); + } + + if (!$this->isXmlString($resource)) { + if (!stream_is_local($resource)) { + throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource)); + } + + if (!file_exists($resource)) { + throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource)); + } + + if (!is_file($resource)) { + throw new InvalidResourceException(\sprintf('This is neither a file nor an XLIFF string "%s".', $resource)); + } + } + + try { + if ($this->isXmlString($resource)) { + $dom = XmlUtils::parse($resource); + } else { + $dom = XmlUtils::loadFile($resource); + } + } catch (\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) { + throw new InvalidResourceException(\sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e); + } + + if ($errors = XliffUtils::validateSchema($dom)) { + throw new InvalidResourceException(\sprintf('Invalid resource provided: "%s"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors)); + } + + $catalogue = new MessageCatalogue($locale); + $this->extract($dom, $catalogue, $domain); + + if (is_file($resource) && class_exists(FileResource::class)) { + $catalogue->addResource(new FileResource($resource)); + } + + return $catalogue; + } + + private function extract(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void + { + $xliffVersion = XliffUtils::getVersionNumber($dom); + + if ('1.2' === $xliffVersion) { + $this->extractXliff1($dom, $catalogue, $domain); + } + + if ('2.0' === $xliffVersion) { + $this->extractXliff2($dom, $catalogue, $domain); + } + } + + /** + * Extract messages and metadata from DOMDocument into a MessageCatalogue. + */ + private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void + { + $xml = simplexml_import_dom($dom); + $encoding = $dom->encoding ? strtoupper($dom->encoding) : null; + + $namespace = 'urn:oasis:names:tc:xliff:document:1.2'; + $xml->registerXPathNamespace('xliff', $namespace); + + foreach ($xml->xpath('//xliff:file') as $file) { + $fileAttributes = $file->attributes(); + + $file->registerXPathNamespace('xliff', $namespace); + + foreach ($file->xpath('.//xliff:prop') as $prop) { + $catalogue->setCatalogueMetadata($prop->attributes()['prop-type'], (string) $prop, $domain); + } + + foreach ($file->xpath('.//xliff:trans-unit') as $translation) { + $attributes = $translation->attributes(); + + if (!(isset($attributes['resname']) || isset($translation->source))) { + continue; + } + + $source = (string) (isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source); + + if (isset($translation->target) + && 'needs-translation' === (string) $translation->target->attributes()['state'] + && \in_array((string) $translation->target, [$source, (string) $translation->source], true) + ) { + continue; + } + + // If the xlf file has another encoding specified, try to convert it because + // simple_xml will always return utf-8 encoded values + $target = $this->utf8ToCharset((string) ($translation->target ?? $translation->source), $encoding); + + $catalogue->set($source, $target, $domain); + + $metadata = [ + 'source' => (string) $translation->source, + 'file' => [ + 'original' => (string) $fileAttributes['original'], + ], + ]; + if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) { + $metadata['notes'] = $notes; + } + + if (isset($translation->target) && $translation->target->attributes()) { + $metadata['target-attributes'] = []; + foreach ($translation->target->attributes() as $key => $value) { + $metadata['target-attributes'][$key] = (string) $value; + } + } + + if (isset($attributes['id'])) { + $metadata['id'] = (string) $attributes['id']; + } + + $catalogue->setMetadata($source, $metadata, $domain); + } + } + } + + private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, string $domain): void + { + $xml = simplexml_import_dom($dom); + $encoding = $dom->encoding ? strtoupper($dom->encoding) : null; + + $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:2.0'); + + foreach ($xml->xpath('//xliff:unit') as $unit) { + foreach ($unit->segment as $segment) { + $attributes = $unit->attributes(); + $source = $attributes['name'] ?? $segment->source; + + // If the xlf file has another encoding specified, try to convert it because + // simple_xml will always return utf-8 encoded values + $target = $this->utf8ToCharset((string) ($segment->target ?? $segment->source), $encoding); + + $catalogue->set((string) $source, $target, $domain); + + $metadata = []; + if ($segment->attributes()) { + $metadata['segment-attributes'] = []; + foreach ($segment->attributes() as $key => $value) { + $metadata['segment-attributes'][$key] = (string) $value; + } + } + + if (isset($segment->target) && $segment->target->attributes()) { + $metadata['target-attributes'] = []; + foreach ($segment->target->attributes() as $key => $value) { + $metadata['target-attributes'][$key] = (string) $value; + } + } + + if (isset($unit->notes)) { + $metadata['notes'] = []; + foreach ($unit->notes->note as $noteNode) { + $note = []; + foreach ($noteNode->attributes() as $key => $value) { + $note[$key] = (string) $value; + } + $note['content'] = (string) $noteNode; + $metadata['notes'][] = $note; + } + } + + $catalogue->setMetadata((string) $source, $metadata, $domain); + } + } + } + + /** + * Convert a UTF8 string to the specified encoding. + */ + private function utf8ToCharset(string $content, ?string $encoding = null): string + { + if ('UTF-8' !== $encoding && $encoding) { + return mb_convert_encoding($content, $encoding, 'UTF-8'); + } + + return $content; + } + + private function parseNotesMetadata(?\SimpleXMLElement $noteElement = null, ?string $encoding = null): array + { + $notes = []; + + if (null === $noteElement) { + return $notes; + } + + /** @var \SimpleXMLElement $xmlNote */ + foreach ($noteElement as $xmlNote) { + $noteAttributes = $xmlNote->attributes(); + $note = ['content' => $this->utf8ToCharset((string) $xmlNote, $encoding)]; + if (isset($noteAttributes['priority'])) { + $note['priority'] = (int) $noteAttributes['priority']; + } + + if (isset($noteAttributes['from'])) { + $note['from'] = (string) $noteAttributes['from']; + } + + $notes[] = $note; + } + + return $notes; + } + + private function isXmlString(string $resource): bool + { + return str_starts_with($resource, ' 'part', Footprint::class => 'footprint', - Storelocation::class => 'storelocation', + StorageLocation::class => 'storelocation', Manufacturer::class => 'manufacturer', Category::class => 'category', Project::class => 'device', diff --git a/src/Twig/InfoProviderExtension.php b/src/Twig/InfoProviderExtension.php index 7cb04db4..a963b778 100644 --- a/src/Twig/InfoProviderExtension.php +++ b/src/Twig/InfoProviderExtension.php @@ -51,7 +51,7 @@ class InfoProviderExtension extends AbstractExtension { try { return $this->providerRegistry->getProviderByKey($key); - } catch (\InvalidArgumentException $exception) { + } catch (\InvalidArgumentException) { return null; } } @@ -65,7 +65,7 @@ class InfoProviderExtension extends AbstractExtension { try { return $this->providerRegistry->getProviderByKey($key)->getProviderInfo()['name']; - } catch (\InvalidArgumentException $exception) { + } catch (\InvalidArgumentException) { return null; } } diff --git a/src/Twig/MiscExtension.php b/src/Twig/MiscExtension.php index 1edef7a3..93762d35 100644 --- a/src/Twig/MiscExtension.php +++ b/src/Twig/MiscExtension.php @@ -22,6 +22,7 @@ declare(strict_types=1); */ namespace App\Twig; +use Symfony\Component\HttpFoundation\Request; use Twig\TwigFunction; use App\Services\LogSystem\EventCommentNeededHelper; use Twig\Extension\AbstractExtension; @@ -38,6 +39,22 @@ final class MiscExtension extends AbstractExtension new TwigFunction('event_comment_needed', fn(string $operation_type) => $this->eventCommentNeededHelper->isCommentNeeded($operation_type) ), + + new TwigFunction('uri_without_host', $this->uri_without_host(...)) ]; } + + /** + * Similar to the getUri function of the request, but does not contain protocol and host. + * @param Request $request + * @return string + */ + public function uri_without_host(Request $request): string + { + if (null !== $qs = $request->getQueryString()) { + $qs = '?'.$qs; + } + + return $request->getBaseUrl().$request->getPathInfo().$qs; + } } diff --git a/src/Twig/Sandbox/InheritanceSecurityPolicy.php b/src/Twig/Sandbox/InheritanceSecurityPolicy.php index db1cd2b5..93e874e9 100644 --- a/src/Twig/Sandbox/InheritanceSecurityPolicy.php +++ b/src/Twig/Sandbox/InheritanceSecurityPolicy.php @@ -22,7 +22,6 @@ use Twig\Sandbox\SecurityNotAllowedTagError; use Twig\Sandbox\SecurityPolicyInterface; use Twig\Template; -use function get_class; use function in_array; use function is_array; diff --git a/src/Twig/Sandbox/SandboxedLabelExtension.php b/src/Twig/Sandbox/SandboxedLabelExtension.php new file mode 100644 index 00000000..59fb0af0 --- /dev/null +++ b/src/Twig/Sandbox/SandboxedLabelExtension.php @@ -0,0 +1,51 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Twig\Sandbox; + +use App\Services\LabelSystem\LabelTextReplacer; +use Twig\Extension\AbstractExtension; +use Twig\TwigFilter; +use Twig\TwigFunction; + +class SandboxedLabelExtension extends AbstractExtension +{ + public function __construct(private readonly LabelTextReplacer $labelTextReplacer) + { + + } + + public function getFunctions(): array + { + return [ + new TwigFunction('placeholder', fn(string $text, object $label_target) => $this->labelTextReplacer->handlePlaceholderOrReturnNull($text, $label_target)), + ]; + } + + public function getFilters(): array + { + return [ + new TwigFilter('placeholders', fn(string $text, object $label_target) => $this->labelTextReplacer->replace($text, $label_target)), + ]; + } +} \ No newline at end of file diff --git a/src/Twig/TwigCoreExtension.php b/src/Twig/TwigCoreExtension.php index b77ff28b..352e09d3 100644 --- a/src/Twig/TwigCoreExtension.php +++ b/src/Twig/TwigCoreExtension.php @@ -42,7 +42,7 @@ final class TwigCoreExtension extends AbstractExtension { return [ /* Returns the enum cases as values */ - new TwigFunction('enum_cases', [$this, 'getEnumCases']), + new TwigFunction('enum_cases', $this->getEnumCases(...)), ]; } @@ -69,6 +69,7 @@ final class TwigCoreExtension extends AbstractExtension throw new \InvalidArgumentException(sprintf('The given class "%s" is not an enum!', $enum_class)); } + /** @noinspection PhpUndefinedMethodInspection */ return ($enum_class)::cases(); } diff --git a/src/Twig/UserExtension.php b/src/Twig/UserExtension.php index 93ea57be..5045257a 100644 --- a/src/Twig/UserExtension.php +++ b/src/Twig/UserExtension.php @@ -127,7 +127,7 @@ final class UserExtension extends AbstractExtension public function removeLocaleFromPath(string $path): string { //Ensure the path has the correct format - if (!preg_match('/^\/\w{2}\//', $path)) { + if (!preg_match('/^\/\w{2}(?:_\w{2})?\//', $path)) { throw new \InvalidArgumentException('The given path is not a localized path!'); } diff --git a/src/Validator/Constraints/NoLockoutValidator.php b/src/Validator/Constraints/NoLockoutValidator.php index 9d51d81e..f3998188 100644 --- a/src/Validator/Constraints/NoLockoutValidator.php +++ b/src/Validator/Constraints/NoLockoutValidator.php @@ -44,7 +44,7 @@ class NoLockoutValidator extends ConstraintValidator * @param mixed $value The value that should be validated * @param Constraint $constraint The constraint for the validation */ - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof NoLockout) { throw new UnexpectedTypeException($constraint, NoLockout::class); diff --git a/src/Validator/Constraints/NoneOfItsChildrenValidator.php b/src/Validator/Constraints/NoneOfItsChildrenValidator.php index 3846c2cc..2be5f16b 100644 --- a/src/Validator/Constraints/NoneOfItsChildrenValidator.php +++ b/src/Validator/Constraints/NoneOfItsChildrenValidator.php @@ -30,6 +30,7 @@ use Symfony\Component\Validator\Exception\UnexpectedValueException; /** * The validator for the NoneOfItsChildren annotation. + * @see \App\Tests\Validator\Constraints\NoneOfItsChildrenValidatorTest */ class NoneOfItsChildrenValidator extends ConstraintValidator { @@ -39,7 +40,7 @@ class NoneOfItsChildrenValidator extends ConstraintValidator * @param mixed $value The value that should be validated * @param Constraint $constraint The constraint for the validation */ - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof NoneOfItsChildren) { throw new UnexpectedTypeException($constraint, NoneOfItsChildren::class); diff --git a/src/Validator/Constraints/ProjectSystem/ValidProjectBuildRequestValidator.php b/src/Validator/Constraints/ProjectSystem/ValidProjectBuildRequestValidator.php index e5de07d2..2d59e648 100644 --- a/src/Validator/Constraints/ProjectSystem/ValidProjectBuildRequestValidator.php +++ b/src/Validator/Constraints/ProjectSystem/ValidProjectBuildRequestValidator.php @@ -69,12 +69,12 @@ class ValidProjectBuildRequestValidator extends ConstraintValidator ->addViolation(); } - if ($withdraw_sum > $needed_amount) { + if ($withdraw_sum > $needed_amount && $value->isDontCheckQuantity() === false) { $this->buildViolationForLot($lot, 'validator.project_build.lot_bigger_than_needed') ->addViolation(); } - if ($withdraw_sum < $needed_amount) { + if ($withdraw_sum < $needed_amount && $value->isDontCheckQuantity() === false) { $this->buildViolationForLot($lot, 'validator.project_build.lot_smaller_than_needed') ->addViolation(); } diff --git a/src/Validator/Constraints/Selectable.php b/src/Validator/Constraints/Selectable.php index f65cb685..c26e47fa 100644 --- a/src/Validator/Constraints/Selectable.php +++ b/src/Validator/Constraints/Selectable.php @@ -31,5 +31,5 @@ use Symfony\Component\Validator\Constraint; #[\Attribute(\Attribute::TARGET_PROPERTY)] class Selectable extends Constraint { - public $message = 'validator.isSelectable'; + public string $message = 'validator.isSelectable'; } diff --git a/src/Validator/Constraints/SelectableValidator.php b/src/Validator/Constraints/SelectableValidator.php index 8519d230..013a3964 100644 --- a/src/Validator/Constraints/SelectableValidator.php +++ b/src/Validator/Constraints/SelectableValidator.php @@ -30,6 +30,7 @@ use Symfony\Component\Validator\Exception\UnexpectedValueException; /** * The validator for the Selectable constraint. + * @see \App\Tests\Validator\Constraints\SelectableValidatorTest */ class SelectableValidator extends ConstraintValidator { @@ -39,7 +40,7 @@ class SelectableValidator extends ConstraintValidator * @param mixed $value The value that should be validated * @param Constraint $constraint The constraint for the validation */ - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof Selectable) { throw new UnexpectedTypeException($constraint, Selectable::class); diff --git a/src/Validator/Constraints/UniqueObjectCollection.php b/src/Validator/Constraints/UniqueObjectCollection.php index 574959a8..6548494e 100644 --- a/src/Validator/Constraints/UniqueObjectCollection.php +++ b/src/Validator/Constraints/UniqueObjectCollection.php @@ -1,4 +1,7 @@ . */ - namespace App\Validator\Constraints; use InvalidArgumentException; @@ -34,19 +36,19 @@ class UniqueObjectCollection extends Constraint self::IS_NOT_UNIQUE => 'IS_NOT_UNIQUE', ]; - public string $message = 'This collection should contain only unique elements.'; + public string $message = 'This value is already used.'; public $normalizer; /** * @param array|string $fields the combination of fields that must contain unique values or a set of options */ public function __construct( - array $options = null, - string $message = null, - callable $normalizer = null, - array $groups = null, + ?array $options = null, + ?string $message = null, + ?callable $normalizer = null, + ?array $groups = null, mixed $payload = null, - array|string $fields = null, + array|string|null $fields = null, public bool $allowNull = true, ) { parent::__construct($options, $groups, $payload); @@ -59,4 +61,4 @@ class UniqueObjectCollection extends Constraint throw new InvalidArgumentException(sprintf('The "normalizer" option must be a valid callable ("%s" given).', get_debug_type($this->normalizer))); } } -} \ No newline at end of file +} diff --git a/src/Validator/Constraints/UniqueObjectCollectionValidator.php b/src/Validator/Constraints/UniqueObjectCollectionValidator.php index 5522ca19..b80889a4 100644 --- a/src/Validator/Constraints/UniqueObjectCollectionValidator.php +++ b/src/Validator/Constraints/UniqueObjectCollectionValidator.php @@ -1,4 +1,7 @@ . */ - namespace App\Validator\Constraints; -use App\Entity\Base\AbstractDBElement; use App\Validator\UniqueValidatableInterface; -use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; -use Symfony\Component\Serializer\Serializer; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\UnexpectedValueException; +/** + * @see \App\Tests\Validator\Constraints\UniqueObjectCollectionValidatorTest + */ class UniqueObjectCollectionValidator extends ConstraintValidator { - public function validate(mixed $value, Constraint $constraint) + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof UniqueObjectCollection) { throw new UnexpectedTypeException($constraint, UniqueObjectCollection::class); @@ -86,11 +88,7 @@ class UniqueObjectCollectionValidator extends ConstraintValidator private function getNormalizer(UniqueObjectCollection $unique): callable { - if (null === $unique->normalizer) { - return static fn ($value) => $value; - } - - return $unique->normalizer; + return $unique->normalizer ?? static fn($value) => $value; } private function reduceElementKeys(array $fields, array $element, UniqueObjectCollection $constraint): array @@ -113,4 +111,4 @@ class UniqueObjectCollectionValidator extends ConstraintValidator return $output; } -} \ No newline at end of file +} diff --git a/src/Validator/Constraints/UrlOrBuiltinValidator.php b/src/Validator/Constraints/UrlOrBuiltinValidator.php index af498d2a..71407a6a 100644 --- a/src/Validator/Constraints/UrlOrBuiltinValidator.php +++ b/src/Validator/Constraints/UrlOrBuiltinValidator.php @@ -34,6 +34,7 @@ use function is_object; * The validator for UrlOrBuiltin. * It checks if the value is either a builtin ressource or a valid url. * In both cases it is not checked, if the ressource is really existing. + * @see \App\Tests\Validator\Constraints\UrlOrBuiltinValidatorTest */ class UrlOrBuiltinValidator extends UrlValidator { diff --git a/src/Validator/Constraints/ValidFileFilterValidator.php b/src/Validator/Constraints/ValidFileFilterValidator.php index d591a968..2a90a010 100644 --- a/src/Validator/Constraints/ValidFileFilterValidator.php +++ b/src/Validator/Constraints/ValidFileFilterValidator.php @@ -42,7 +42,7 @@ class ValidFileFilterValidator extends ConstraintValidator * @param mixed $value The value that should be validated * @param Constraint $constraint The constraint for the validation */ - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof ValidFileFilter) { throw new UnexpectedTypeException($constraint, ValidFileFilter::class); diff --git a/src/Validator/Constraints/ValidGoogleAuthCode.php b/src/Validator/Constraints/ValidGoogleAuthCode.php index 482af35c..180d346e 100644 --- a/src/Validator/Constraints/ValidGoogleAuthCode.php +++ b/src/Validator/Constraints/ValidGoogleAuthCode.php @@ -31,8 +31,8 @@ class ValidGoogleAuthCode extends Constraint * @param TwoFactorInterface|null $user The user to use for the validation process, if null, the current user is used */ public function __construct( - array $options = null, - array $groups = null, + ?array $options = null, + ?array $groups = null, mixed $payload = null, public ?TwoFactorInterface $user = null) { diff --git a/src/Validator/Constraints/ValidGoogleAuthCodeValidator.php b/src/Validator/Constraints/ValidGoogleAuthCodeValidator.php index be935a71..25afe57b 100644 --- a/src/Validator/Constraints/ValidGoogleAuthCodeValidator.php +++ b/src/Validator/Constraints/ValidGoogleAuthCodeValidator.php @@ -22,12 +22,9 @@ declare(strict_types=1); namespace App\Validator\Constraints; -use App\Entity\UserSystem\User; use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface; -use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticator; use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticatorInterface; use Symfony\Bundle\SecurityBundle\Security; -use Symfony\Component\Form\FormInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; @@ -36,9 +33,12 @@ use Symfony\Component\Validator\Exception\UnexpectedValueException; use function is_string; use function strlen; +/** + * @see \App\Tests\Validator\Constraints\ValidGoogleAuthCodeValidatorTest + */ class ValidGoogleAuthCodeValidator extends ConstraintValidator { - public function __construct(private GoogleAuthenticatorInterface $googleAuthenticator, private Security $security) + public function __construct(private readonly GoogleAuthenticatorInterface $googleAuthenticator, private readonly Security $security) { } diff --git a/src/Validator/Constraints/ValidPartLotValidator.php b/src/Validator/Constraints/ValidPartLotValidator.php index 4f988362..316fedea 100644 --- a/src/Validator/Constraints/ValidPartLotValidator.php +++ b/src/Validator/Constraints/ValidPartLotValidator.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace App\Validator\Constraints; use App\Entity\Parts\PartLot; -use App\Entity\Parts\Storelocation; +use App\Entity\Parts\StorageLocation; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; @@ -42,7 +42,7 @@ class ValidPartLotValidator extends ConstraintValidator * @param mixed $value The value that should be validated * @param Constraint $constraint The constraint for the validation */ - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof ValidPartLot) { throw new UnexpectedTypeException($constraint, ValidPartLot::class); @@ -53,8 +53,8 @@ class ValidPartLotValidator extends ConstraintValidator } //We can only validate the values if we know the storelocation - if ($value->getStorageLocation() instanceof Storelocation) { - $repo = $this->em->getRepository(Storelocation::class); + if ($value->getStorageLocation() instanceof StorageLocation) { + $repo = $this->em->getRepository(StorageLocation::class); //We can only determine associated parts, if the part have an ID //When the storage location is new (no ID), we can just assume there are no other parts if (null !== $value->getID() && $value->getStorageLocation()->getID()) { diff --git a/src/Validator/Constraints/ValidPermissionValidator.php b/src/Validator/Constraints/ValidPermissionValidator.php index c0004e6c..afb7721b 100644 --- a/src/Validator/Constraints/ValidPermissionValidator.php +++ b/src/Validator/Constraints/ValidPermissionValidator.php @@ -22,15 +22,21 @@ declare(strict_types=1); namespace App\Validator\Constraints; +use App\Controller\GroupController; +use App\Controller\UserController; use App\Security\Interfaces\HasPermissionsInterface; use App\Services\UserSystem\PermissionManager; use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use function Symfony\Component\Translation\t; + class ValidPermissionValidator extends ConstraintValidator { - public function __construct(protected PermissionManager $resolver) + public function __construct(protected PermissionManager $resolver, protected RequestStack $requestStack) { } @@ -40,7 +46,7 @@ class ValidPermissionValidator extends ConstraintValidator * @param mixed $value The value that should be validated * @param Constraint $constraint The constraint for the validation */ - public function validate($value, Constraint $constraint): void + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof ValidPermission) { throw new UnexpectedTypeException($constraint, ValidPermission::class); @@ -49,6 +55,26 @@ class ValidPermissionValidator extends ConstraintValidator /** @var HasPermissionsInterface $perm_holder */ $perm_holder = $this->context->getObject(); - $this->resolver->ensureCorrectSetOperations($perm_holder); + $changed = $this->resolver->ensureCorrectSetOperations($perm_holder); + + //Sending a flash message if the permissions were fixed (only if called from UserController or GroupController) + //This is pretty hacky and bad design but I dont see a better way without a complete rewrite of how permissions are validated + //on the admin pages + if ($changed) { + //Check if this was called in context of UserController + $request = $this->requestStack->getMainRequest(); + if ($request === null) { + return; + } + //Determine the controller class (the part before the ::) + $controller_class = explode('::', (string) $request->attributes->get('_controller'))[0]; + + if (in_array($controller_class, [UserController::class, GroupController::class], true)) { + /** @var Session $session */ + $session = $this->requestStack->getSession(); + $flashBag = $session->getFlashBag(); + $flashBag->add('warning', t('user.edit.flash.permissions_fixed')); + } + } } } diff --git a/src/Validator/Constraints/ValidThemeValidator.php b/src/Validator/Constraints/ValidThemeValidator.php index 5d222934..713be9a5 100644 --- a/src/Validator/Constraints/ValidThemeValidator.php +++ b/src/Validator/Constraints/ValidThemeValidator.php @@ -26,6 +26,9 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; +/** + * @see \App\Tests\Validator\Constraints\ValidThemeValidatorTest + */ class ValidThemeValidator extends ConstraintValidator { public function __construct(private readonly array $available_themes) diff --git a/src/Validator/Constraints/Year2038BugWorkaround.php b/src/Validator/Constraints/Year2038BugWorkaround.php new file mode 100644 index 00000000..04a07908 --- /dev/null +++ b/src/Validator/Constraints/Year2038BugWorkaround.php @@ -0,0 +1,41 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; + +/** + * Datetime interfaces properties with this constraint are limited to the year 2038 on 32-bit systems, to prevent a + * Year 2038 bug during rendering. + * + * Current PHP versions can not format dates after 2038 on 32-bit systems and throw an exception. + * (See https://github.com/Part-DB/Part-DB-server/discussions/548). + * + * This constraint does not fix that problem, but can prevent users from entering such invalid dates. + */ +#[\Attribute(\Attribute::TARGET_PROPERTY)] +class Year2038BugWorkaround extends Constraint +{ + public string $message = 'validator.year_2038_bug_on_32bit'; +} \ No newline at end of file diff --git a/src/Validator/Constraints/Year2038BugWorkaroundValidator.php b/src/Validator/Constraints/Year2038BugWorkaroundValidator.php new file mode 100644 index 00000000..747721f9 --- /dev/null +++ b/src/Validator/Constraints/Year2038BugWorkaroundValidator.php @@ -0,0 +1,74 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Validator\Constraints; + +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; + +class Year2038BugWorkaroundValidator extends ConstraintValidator +{ + + public function __construct( + #[Autowire(env: "DISABLE_YEAR2038_BUG_CHECK")] + private readonly bool $disable_validation = false + ) + { + } + + public function isActivated(): bool + { + //If we are on a 32 bit system and the validation is not disabled, we should activate the validation + return !$this->disable_validation && PHP_INT_SIZE === 4; + } + + public function validate(mixed $value, Constraint $constraint): void + { + if (!$this->isActivated()) { + return; + } + + //If the value is null, we don't need to validate it + if ($value === null) { + return; + } + + //Ensure that we check the correct constraint + if (!$constraint instanceof Year2038BugWorkaround) { + throw new \InvalidArgumentException('This validator can only validate Year2038Bug constraints'); + } + + //We can only validate DateTime objects + if (!$value instanceof \DateTimeInterface) { + throw new UnexpectedTypeException($value, \DateTimeInterface::class); + } + + //If we reach here the validation is active and we should forbid any date after 2038. + if ($value->diff(new \DateTime('2038-01-19 03:14:06'))->invert === 1) { + $this->context->buildViolation($constraint->message) + ->addViolation(); + } + } +} \ No newline at end of file diff --git a/src/Validator/UniqueValidatableInterface.php b/src/Validator/UniqueValidatableInterface.php index 97e3a0b9..3d954490 100644 --- a/src/Validator/UniqueValidatableInterface.php +++ b/src/Validator/UniqueValidatableInterface.php @@ -1,4 +1,7 @@ . */ - namespace App\Validator; interface UniqueValidatableInterface @@ -29,4 +31,4 @@ interface UniqueValidatableInterface * @return array An array of the form ['field1' => 'value1', 'field2' => 'value2', ...] */ public function getComparableFields(): array; -} \ No newline at end of file +} diff --git a/symfony.lock b/symfony.lock index d47e131c..c7471b73 100644 --- a/symfony.lock +++ b/symfony.lock @@ -1,9 +1,17 @@ { - "amphp/amp": { - "version": "v2.2.1" - }, - "amphp/byte-stream": { - "version": "v1.6.1" + "api-platform/core": { + "version": "3.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.2", + "ref": "696d44adc3c0d4f5d25a2f1c4f3700dd8a5c6db9" + }, + "files": [ + "config/packages/api_platform.yaml", + "config/routes/api_platform.yaml", + "src/ApiResource/.gitignore" + ] }, "beberlei/assert": { "version": "v3.2.6" @@ -20,49 +28,24 @@ "composer/package-versions-deprecated": { "version": "1.11.99.4" }, - "composer/pcre": { - "version": "1.0.0" - }, - "composer/semver": { - "version": "1.5.0" - }, - "composer/xdebug-handler": { - "version": "1.3.3" - }, "dama/doctrine-test-bundle": { - "version": "4.0", + "version": "8.0", "recipe": { "repo": "github.com/symfony/recipes-contrib", - "branch": "master", - "version": "4.0", - "ref": "56eaa387b5e48ebcc7c95a893b47dfa1ad51449c" + "branch": "main", + "version": "7.2", + "ref": "896306d79d4ee143af9eadf9b09fd34a8c391b70" }, "files": [ - "./config/packages/test/dama_doctrine_test_bundle.yaml" + "./config/packages/dama_doctrine_test_bundle.yaml" ] }, - "dnoegel/php-xdg-base-dir": { - "version": "v0.1.1" - }, - "doctrine/annotations": { - "version": "1.14", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "1.10", - "ref": "64d8583af5ea57b7afa4aba4b159907f3a148b05" - }, - "files": [] - }, "doctrine/cache": { "version": "v1.8.0" }, "doctrine/collections": { "version": "v1.5.0" }, - "doctrine/common": { - "version": "v2.10.0" - }, "doctrine/data-fixtures": { "version": "v1.3.2" }, @@ -73,17 +56,17 @@ "version": "v0.5.3" }, "doctrine/doctrine-bundle": { - "version": "2.10", + "version": "2.11", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", "version": "2.10", - "ref": "f0d8c9a4da17815830aac0d63e153a940ae176bb" + "ref": "c170ded8fc587d6bd670550c43dafcf093762245" }, "files": [ - "config/packages/doctrine.yaml", - "src/Entity/.gitignore", - "src/Repository/.gitignore" + "./config/packages/doctrine.yaml", + "./src/Entity/.gitignore", + "./src/Repository/.gitignore" ] }, "doctrine/doctrine-fixtures-bundle": { @@ -147,12 +130,6 @@ "erusev/parsedown": { "version": "1.7.4" }, - "felixfbecker/advanced-json-rpc": { - "version": "v3.0.4" - }, - "felixfbecker/language-server-protocol": { - "version": "v1.4.0" - }, "florianv/exchanger": { "version": "1.4.1" }, @@ -160,25 +137,25 @@ "version": "3.5.0" }, "florianv/swap-bundle": { - "version": "5.0.0" - }, - "friendsofphp/proxy-manager-lts": { - "version": "v1.0.5" + "version": "5.0.x-dev" }, "gregwar/captcha": { "version": "v1.1.7" }, "gregwar/captcha-bundle": { - "version": "v2.0.6" + "version": "v2.2.0" }, "imagine/imagine": { "version": "1.2.2" }, "jbtronics/2fa-webauthn": { - "version": "dev-master" + "version": "v2.2.1" }, "jbtronics/dompdf-font-loader-bundle": { - "version": "dev-main" + "version": "v1.1.1" + }, + "jbtronics/translation-editor-bundle": { + "version": "v1.0" }, "knpuniversity/oauth2-client-bundle": { "version": "2.15", @@ -192,9 +169,6 @@ "./config/packages/knpu_oauth2_client.yaml" ] }, - "laminas/laminas-code": { - "version": "3.4.1" - }, "league/html-to-markdown": { "version": "4.8.2" }, @@ -218,7 +192,19 @@ "version": "1.24.0" }, "nbgrp/onelogin-saml-bundle": { - "version": "v1.3.2" + "version": "v1.4.0" + }, + "nelmio/cors-bundle": { + "version": "2.3", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.5", + "ref": "6bea22e6c564fba3a1391615cada1437d0bde39c" + }, + "files": [ + "./config/packages/nelmio_cors.yaml" + ] }, "nelmio/security-bundle": { "version": "2.4", @@ -232,18 +218,12 @@ "./config/packages/nelmio_security.yaml" ] }, - "netresearch/jsonmapper": { - "version": "v1.6.0" - }, "nikic/php-parser": { "version": "v4.2.1" }, "nikolaposa/version": { "version": "2.2.2" }, - "nyholm/nsa": { - "version": "1.1.0" - }, "nyholm/psr7": { "version": "1.0", "recipe": { @@ -295,30 +275,6 @@ "php-http/promise": { "version": "v1.0.0" }, - "php-translation/common": { - "version": "1.0.0" - }, - "php-translation/extractor": { - "version": "1.7.1" - }, - "php-translation/symfony-bundle": { - "version": "0.12", - "recipe": { - "repo": "github.com/symfony/recipes-contrib", - "branch": "master", - "version": "0.10", - "ref": "f3ca4e4da63897d177e58da78626c20648c0e102" - }, - "files": [ - "config/packages/dev/php_translation.yaml", - "config/packages/php_translation.yaml", - "config/routes/dev/php_translation.yaml", - "config/routes/php_translation.yaml" - ] - }, - "php-translation/symfony-storage": { - "version": "1.0.1" - }, "phpdocumentor/reflection-common": { "version": "1.0.1" }, @@ -332,7 +288,16 @@ "version": "1.0.3" }, "phpstan/phpstan": { - "version": "0.12.8" + "version": "1.10", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "1.0", + "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767" + }, + "files": [ + "phpstan.dist.neon" + ] }, "phpstan/phpstan-doctrine": { "version": "0.12.9" @@ -340,8 +305,19 @@ "phpstan/phpstan-symfony": { "version": "0.12.4" }, - "psalm/plugin-symfony": { - "version": "v1.2.1" + "phpunit/phpunit": { + "version": "9.6", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "9.6", + "ref": "7364a21d87e658eb363c5020c072ecfdc12e2326" + }, + "files": [ + "./.env.test", + "./phpunit.xml.dist", + "./tests/bootstrap.php" + ] }, "psr/cache": { "version": "1.0.1" @@ -402,10 +378,7 @@ "version": "3.0.2" }, "shivas/versioning-bundle": { - "version": "3.1.3" - }, - "spomky-labs/cbor-bundle": { - "version": "v2.0.3" + "version": "4.0.3" }, "symfony/apache-pack": { "version": "1.0", @@ -413,10 +386,10 @@ "repo": "github.com/symfony/recipes-contrib", "branch": "main", "version": "1.0", - "ref": "efb318193e48384eb5c5aadff15396ed698f8ffc" + "ref": "0f18b4decdf5695d692c1d0dfd65516a07a6adf1" }, "files": [ - "public/.htaccess" + "./public/.htaccess" ] }, "symfony/asset": { @@ -435,15 +408,15 @@ "version": "v4.2.3" }, "symfony/console": { - "version": "5.3", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", - "branch": "master", + "branch": "main", "version": "5.3", - "ref": "da0c8be8157600ad34f10ff0c9cc91232522e047" + "ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" }, "files": [ - "./bin/console" + "bin/console" ] }, "symfony/css-selector": { @@ -495,27 +468,28 @@ "version": "v4.2.3" }, "symfony/flex": { - "version": "1.19", + "version": "2.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "1.0", - "ref": "146251ae39e06a95be0fe3d13c807bcf3938b172" + "version": "2.4", + "ref": "52e9754527a15e2b79d9a610f98185a1fe46622a" }, "files": [ - ".env" + ".env", + ".env.dev" ] }, "symfony/form": { "version": "v4.2.3" }, "symfony/framework-bundle": { - "version": "6.2", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "6.2", - "ref": "af47254c5e4cd543e6af3e4508298ffebbdaddd3" + "version": "6.4", + "ref": "a91c965766ad3ff2ae15981801643330eb42b6a5" }, "files": [ "config/packages/cache.yaml", @@ -544,15 +518,15 @@ "version": "v4.2.3" }, "symfony/mailer": { - "version": "5.4", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", "version": "4.3", - "ref": "2bf89438209656b85b9a49238c4467bff1b1f939" + "ref": "df66ee1f226c46f01e85c29c2f7acce0596ba35a" }, "files": [ - "config/packages/mailer.yaml" + "./config/packages/mailer.yaml" ] }, "symfony/maker-bundle": { @@ -571,12 +545,12 @@ "version": "v4.4.2" }, "symfony/monolog-bundle": { - "version": "3.7", + "version": "3.10", "recipe": { "repo": "github.com/symfony/recipes", - "branch": "master", + "branch": "main", "version": "3.7", - "ref": "213676c4ec929f046dfde5ea8e97625b81bc0578" + "ref": "aff23899c4440dd995907613c1dd709b6f59503f" }, "files": [ "./config/packages/monolog.yaml" @@ -589,18 +563,18 @@ "version": "v5.3.8" }, "symfony/phpunit-bridge": { - "version": "5.4", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "5.3", - "ref": "819d3d2ffa4590eba0b8f4f3e5e89415ee4e45c3" + "version": "6.3", + "ref": "a411a0480041243d97382cac7984f7dce7813c08" }, "files": [ - ".env.test", - "bin/phpunit", - "phpunit.xml.dist", - "tests/bootstrap.php" + "./.env.test", + "./bin/phpunit", + "./phpunit.xml.dist", + "./tests/bootstrap.php" ] }, "symfony/polyfill-ctype": { @@ -621,9 +595,6 @@ "symfony/polyfill-mbstring": { "version": "v1.10.0" }, - "symfony/polyfill-php72": { - "version": "v1.10.0" - }, "symfony/polyfill-php80": { "version": "v1.17.0" }, @@ -636,9 +607,6 @@ "symfony/property-info": { "version": "v4.2.3" }, - "symfony/proxy-manager-bridge": { - "version": "v5.2.1" - }, "symfony/routing": { "version": "6.2", "recipe": { @@ -656,15 +624,16 @@ "version": "v5.3.4" }, "symfony/security-bundle": { - "version": "6.2", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "6.0", - "ref": "8a5b112826f7d3d5b07027f93786ae11a1c7de48" + "version": "6.4", + "ref": "2ae08430db28c8eb4476605894296c82a642028f" }, "files": [ - "config/packages/security.yaml" + "config/packages/security.yaml", + "config/routes/security.yaml" ] }, "symfony/security-core": { @@ -683,12 +652,12 @@ "version": "v1.1.5" }, "symfony/stimulus-bundle": { - "version": "2.9", + "version": "2.16", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "2.9", - "ref": "05c45071c7ecacc1e48f94bc43c1f8d4405fb2b2" + "version": "2.13", + "ref": "6acd9ff4f7fd5626d2962109bd4ebab351d43c43" }, "files": [ "./assets/bootstrap.js", @@ -703,12 +672,12 @@ "version": "v5.1.0" }, "symfony/translation": { - "version": "5.3", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", - "branch": "master", - "version": "5.3", - "ref": "da64f5a2b6d96f5dc24914517c0350a5f91dee43" + "branch": "main", + "version": "6.3", + "ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b" }, "files": [ "./config/packages/translation.yaml", @@ -722,16 +691,16 @@ "version": "v4.2.3" }, "symfony/twig-bundle": { - "version": "6.3", + "version": "6.4", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "6.3", - "ref": "b7772eb20e92f3fb4d4fe756e7505b4ba2ca1a2c" + "version": "6.4", + "ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877" }, "files": [ - "config/packages/twig.yaml", - "templates/base.html.twig" + "./config/packages/twig.yaml", + "./templates/base.html.twig" ] }, "symfony/uid": { @@ -762,7 +731,7 @@ ] }, "symfony/ux-turbo": { - "version": "v2.0.1" + "version": "v2.16.0" }, "symfony/validator": { "version": "5.4", @@ -799,18 +768,15 @@ ] }, "symfony/webpack-encore-bundle": { - "version": "1.17", + "version": "2.1", "recipe": { "repo": "github.com/symfony/recipes", "branch": "main", - "version": "1.10", - "ref": "eff2e505d4557c967b6710fe06bd947ba555cae5" + "version": "2.0", + "ref": "082d754b3bd54b3fc669f278f1eea955cfd23cf5" }, "files": [ "assets/app.js", - "assets/bootstrap.js", - "assets/controllers.json", - "assets/controllers/hello_controller.js", "assets/styles/app.css", "config/packages/webpack_encore.yaml", "package.json", @@ -836,7 +802,7 @@ "version": "v3.0.0" }, "twig/extra-bundle": { - "version": "v3.0.0" + "version": "v3.8.0" }, "twig/html-extra": { "version": "v3.0.3" @@ -856,17 +822,18 @@ "ua-parser/uap-php": { "version": "v3.9.8" }, - "vimeo/psalm": { - "version": "3.5.1" - }, "web-auth/webauthn-symfony-bundle": { - "version": "3.3", + "version": "4.7", "recipe": { "repo": "github.com/symfony/recipes-contrib", "branch": "main", "version": "3.0", - "ref": "9926090a80c2cceeffe96e6c3312b397ea55d4a7" - } + "ref": "a5dff33bd46575bea263af94069650af7742dcb6" + }, + "files": [ + "config/packages/webauthn.yaml", + "config/routes/webauthn_routes.yaml" + ] }, "webmozart/assert": { "version": "1.4.0" diff --git a/templates/_navbar.html.twig b/templates/_navbar.html.twig index 164848f1..cd1f641f 100644 --- a/templates/_navbar.html.twig +++ b/templates/_navbar.html.twig @@ -1,12 +1,20 @@ {% import "helper.twig" as helper %} +{% import "components/search.macro.html.twig" as search %}
diff --git a/templates/label_system/scanner/scanner.html.twig b/templates/label_system/scanner/scanner.html.twig index 39f4e140..1f978a9b 100644 --- a/templates/label_system/scanner/scanner.html.twig +++ b/templates/label_system/scanner/scanner.html.twig @@ -23,4 +23,22 @@ {{ form_end(form) }} + + {% if infoModeData %} +
+

{% trans %}label_scanner.decoded_info.title{% endtrans %}

+ + + + {% for key, value in infoModeData %} + + + + + {% endfor %} + +
{{ key }}{{ value }}
+ + {% endif %} + {% endblock %} diff --git a/templates/log_system/details/helper.macro.html.twig b/templates/log_system/details/helper.macro.html.twig index 1d774910..e8957b66 100644 --- a/templates/log_system/details/helper.macro.html.twig +++ b/templates/log_system/details/helper.macro.html.twig @@ -22,7 +22,7 @@ data-delete-title="{% trans %}log.undo.confirm_title{% endtrans %}" data-delete-message="{% trans %}log.undo.confirm_message{% endtrans %}"> - +
+
\ No newline at end of file diff --git a/templates/parts/edit/_eda.html.twig b/templates/parts/edit/_eda.html.twig new file mode 100644 index 00000000..4df675c4 --- /dev/null +++ b/templates/parts/edit/_eda.html.twig @@ -0,0 +1,24 @@ +{{ form_row(form.eda_info.reference_prefix) }} +{{ form_row(form.eda_info.value) }} + +
+
+ {{ form_row(form.eda_info.visibility) }} +
+
+ +
+
+ {{ form_widget(form.eda_info.exclude_from_bom) }} + {{ form_widget(form.eda_info.exclude_from_board) }} + {{ form_widget(form.eda_info.exclude_from_sim) }} +
+
+ +
+
+
{% trans %}eda_info.kicad_section.title{% endtrans %}:
+
+
+{{ form_row(form.eda_info.kicad_symbol) }} +{{ form_row(form.eda_info.kicad_footprint) }} \ No newline at end of file diff --git a/templates/parts/edit/edit_form_styles.html.twig b/templates/parts/edit/edit_form_styles.html.twig index 7ff81b77..c2a89b6a 100644 --- a/templates/parts/edit/edit_form_styles.html.twig +++ b/templates/parts/edit/edit_form_styles.html.twig @@ -14,9 +14,10 @@ {{ form_widget(form.price_related_quantity, {'attr': {'class': 'form-control-sm'}}) }} {{ form_errors(form.price_related_quantity) }} - {{ form_errors(form) }} @@ -57,8 +58,9 @@
- {{ form_errors(form) }} @@ -73,12 +75,14 @@ {{ form_widget(form.value_min) }}{{ form_errors(form.value_min) }} {{ form_widget(form.value_typical) }}{{ form_errors(form.value_typical) }} {{ form_widget(form.value_max) }}{{ form_errors(form.value_max) }} - {{ form_widget(form.unit, {"attr": {"data-pages--parameters-autocomplete-target": "unit", "data-pages--latex-preview-target": "input"}}) }}{{ form_errors(form.unit) }} + {{ form_widget(form.unit, {"attr": {"data-pages--parameters-autocomplete-target": "unit", "data-pages--latex-preview-target": "input"}}) }}{{ form_errors(form.unit) }} {{ form_widget(form.value_text) }}{{ form_errors(form.value_text) }} {{ form_widget(form.group) }}{{ form_errors(form.group) }} - {{ form_errors(form) }} @@ -89,12 +93,29 @@ {% import 'components/collection_type.macro.html.twig' as collection %} - {{ form_widget(form) }} + {{ form_row(form.description) }} + {{ form_row(form.storage_location) }} + {{ form_row(form.amount) }} + {{ form_row(form.instock_unknown) }} + {{ form_row(form.needs_refill) }} + {{ form_row(form.expiration_date) }} + + {% set id = 'collapse_' ~ random() %} + + +
+ {{ form_row(form.comment) }} + {{ form_row(form.owner) }} + {{ form_row(form.user_barcode) }} +
- {{ form_errors(form) }} @@ -124,41 +145,39 @@ - {% set attach = form.vars.value %} + {# @var \App\Entity\Attachments\Attachment attach #} {% if attach is not null %} - {% if attachment_manager.fileExisting(attach) %} - {% if not attach.external %} -

-
+ {% if not attach.hasInternal() and attach.external %} +
- {{ attach.filename }} + {% trans %}attachment.external_only{% endtrans %} -
- +
+ {% elseif attachment_manager.isInternalFileExisting(attach) %} +
+
+ {{ attach.filename|u.truncate(25, ' ...') }} +
+
+
{{ attachment_manager.humanFileSize(attach) }} - -
- {% else %} -

-
- - {% trans %}attachment.external{% endtrans %} - -
- {% endif %} +
+
{% if attach.secure %} -
+
{% trans %}attachment.secure{% endtrans %} -
+ {% endif %} {% if attach.secure and not is_granted('show_private', attach) %} @@ -168,19 +187,43 @@ {% trans %}attachment.preview.alt{% endtrans %} {% else %} - {% trans %}attachment.view{% endtrans %} + {% trans %}attachment.view_local{% endtrans %} {% endif %} {% else %} -

-
+
{% trans %}attachment.file_not_found{% endtrans %} -
+ + {% endif %} + {% if attach.external %} + {% endif %} {% endif %} +{% endblock %} + +{% block part_association_widget %} + {% import 'components/collection_type.macro.html.twig' as collection %} + + +
+ {{ form_widget(form) }} +
+ + + + {{ form_errors(form) }} + + {% endblock %} \ No newline at end of file diff --git a/templates/parts/edit/edit_part_info.html.twig b/templates/parts/edit/edit_part_info.html.twig index 51b5d865..20cddbd7 100644 --- a/templates/parts/edit/edit_part_info.html.twig +++ b/templates/parts/edit/edit_part_info.html.twig @@ -58,6 +58,18 @@ {% trans %}part.edit.tab.specifications{% endtrans %} + + + {% if filterForm.project is defined %} + + {% endif %} {{ form_start(filterForm, {"attr": {"data-controller": "helpers--form-cleanup", "data-action": "helpers--form-cleanup#submit"}}) }} @@ -113,6 +118,14 @@ + {% if filterForm.project is defined %} +
+ {{ form_row(filterForm.project) }} + {{ form_row(filterForm.bomQuantity) }} + {{ form_row(filterForm.bomName) }} + {{ form_row(filterForm.bomComment) }} +
+ {% endif %} diff --git a/templates/parts/lists/search_list.html.twig b/templates/parts/lists/search_list.html.twig index 69dae48a..49093c4c 100644 --- a/templates/parts/lists/search_list.html.twig +++ b/templates/parts/lists/search_list.html.twig @@ -50,7 +50,7 @@
- +
diff --git a/templates/projects/build/_form.html.twig b/templates/projects/build/_form.html.twig index 4a02dd4d..a8f772e9 100644 --- a/templates/projects/build/_form.html.twig +++ b/templates/projects/build/_form.html.twig @@ -74,6 +74,9 @@ {{ form_row(form.comment) }} +
+{{ form_row(form.dontCheckQuantity) }} +
{{ form_row(form.addBuildsToBuildsPart) }} {% if form.buildsPartLot is defined %} diff --git a/templates/projects/info/_bom.html.twig b/templates/projects/info/_bom.html.twig index bed96dde..2a9cfd00 100644 --- a/templates/projects/info/_bom.html.twig +++ b/templates/projects/info/_bom.html.twig @@ -2,7 +2,7 @@
+ href="{{ path('project_add_parts', {"id": project.id, "_redirect": uri_without_host(app.request)}) }}"> {% trans %}project.info.bom_add_parts{% endtrans %} diff --git a/templates/projects/info/_builds.html.twig b/templates/projects/info/_builds.html.twig index 5418a614..fc49b50d 100644 --- a/templates/projects/info/_builds.html.twig +++ b/templates/projects/info/_builds.html.twig @@ -28,7 +28,7 @@
- +
diff --git a/templates/security/2fa_base_form.html.twig b/templates/security/2fa_base_form.html.twig index 8190e7a1..847048e4 100644 --- a/templates/security/2fa_base_form.html.twig +++ b/templates/security/2fa_base_form.html.twig @@ -7,7 +7,7 @@ {% block content %} {% if authenticationError %} {% endif %} diff --git a/templates/tools/server_infos/_db.html.twig b/templates/tools/server_infos/_db.html.twig index 0c0e60a2..828783fe 100644 --- a/templates/tools/server_infos/_db.html.twig +++ b/templates/tools/server_infos/_db.html.twig @@ -21,5 +21,13 @@ Database User {{ db_user }} + + Natural sort method + {{ db_natsort_method }} + + + Slow natural sort allowed + {{ helper.boolean_badge(db_natsort_slow_allowed) }} + \ No newline at end of file diff --git a/templates/tools/server_infos/_partdb.html.twig b/templates/tools/server_infos/_partdb.html.twig index 52d19c93..ca2b82a8 100644 --- a/templates/tools/server_infos/_partdb.html.twig +++ b/templates/tools/server_infos/_partdb.html.twig @@ -11,7 +11,7 @@ Symfony environment - {{ enviroment }} (Debug: {{ helper.boolean_badge(is_debug) }}) + {{ environment }} (Debug: {{ helper.boolean_badge(is_debug) }}) Part-DB Instance name @@ -42,8 +42,8 @@ {{ helper.boolean_badge(demo_mode) }} - GPDR Compliance Mode - {{ helper.boolean_badge(gpdr_compliance) }} + GDPR Compliance Mode + {{ helper.boolean_badge(gdpr_compliance) }} Users diff --git a/templates/tools/server_infos/_php.html.twig b/templates/tools/server_infos/_php.html.twig index ae485639..ea5a0b4c 100644 --- a/templates/tools/server_infos/_php.html.twig +++ b/templates/tools/server_infos/_php.html.twig @@ -9,6 +9,12 @@ Server Operating System {{ php_uname }} + + PHP Bit Size + {{ php_bit_size }}-bit + {% if php_bit_size < 64 %}(32-bit PHP is affected by Year 2038 problem, and can not work with dates after 2038!){% endif %} + + Opcache enabled {{ helper.boolean_badge(php_opcache_enabled) }} @@ -25,5 +31,19 @@ Server time {{ "now" | format_datetime("long", "long") }} + + Symfony Kernel Runtime + {{ kernel_runtime }} + + + Symfony Kernel Runtime Environment + {{ kernel_runtime_environment }} + + + Symfony Kernel Runtime mode + {% for key, value in kernel_runtime_mode %} + {{ key }}: {{ value }}
+ {% endfor %} + \ No newline at end of file diff --git a/templates/tools/server_infos/server_infos.html.twig b/templates/tools/server_infos/server_infos.html.twig index fd3d2759..e4e02d32 100644 --- a/templates/tools/server_infos/server_infos.html.twig +++ b/templates/tools/server_infos/server_infos.html.twig @@ -1,4 +1,5 @@ {% extends "main_card.html.twig" %} +{% import "components/new_version.macro.html.twig" as nv %} {% block title %}{% trans %}tools.server_infos.title{% endtrans %}{% endblock %} @@ -6,6 +7,12 @@ {% trans %}tools.server_infos.title{% endtrans %} {% endblock %} +{% block before_card %} + {% if is_granted('@system.show_updates') %} + {{ nv.new_version_alert(new_version_available, new_version, new_version_url) }} + {% endif %} +{% endblock %} + {% block card_content %}