pax_global_header00006660000000000000000000000064143702376000014514gustar00rootroot0000000000000052 comment=194ac08502cad54dc072e58c1f30a901c04b3284 hex-2.0.6/000077500000000000000000000000001437023760000123055ustar00rootroot00000000000000hex-2.0.6/.credo.exs000066400000000000000000000076411437023760000142100ustar00rootroot00000000000000%{ configs: [ %{ name: "default", files: %{ included: ["lib/", "src/", "test/"], excluded: [~r"/_build/", ~r"/deps/"] }, requires: [], check_for_updates: false, # # You can customize the parameters of any check by adding a second element # to the tuple. # # To disable a check put `false` as second element: # # {Credo.Check.Design.DuplicatedCode, false} # checks: [ {Credo.Check.Consistency.ExceptionNames}, {Credo.Check.Consistency.LineEndings}, {Credo.Check.Consistency.MultiAliasImportRequireUse}, {Credo.Check.Consistency.SpaceAroundOperators}, {Credo.Check.Consistency.SpaceInParentheses}, {Credo.Check.Consistency.TabsOrSpaces}, # For some checks, like AliasUsage, you can only customize the priority # Priority values are: `low, normal, high, higher` or disable it (false). {Credo.Check.Design.AliasUsage, false}, # For others you can set parameters # If you don't want the `setup` and `test` macro calls in ExUnit tests # or the `schema` macro in Ecto schemas to trigger DuplicatedCode, just # set the `excluded_macros` parameter to `[:schema, :setup, :test]`. {Credo.Check.Design.DuplicatedCode, excluded_macros: []}, # Disabled for now as they are also checked by Code Climate {Credo.Check.Design.TagTODO, false}, {Credo.Check.Design.TagFIXME, false}, {Credo.Check.Readability.FunctionNames}, {Credo.Check.Readability.MaxLineLength, false}, {Credo.Check.Readability.ModuleAttributeNames}, {Credo.Check.Readability.ModuleDoc, false}, {Credo.Check.Readability.ModuleNames}, {Credo.Check.Readability.ParenthesesOnZeroArityDefs, false}, {Credo.Check.Readability.ParenthesesInCondition}, {Credo.Check.Readability.PredicateFunctionNames}, {Credo.Check.Readability.TrailingBlankLine}, {Credo.Check.Readability.TrailingWhiteSpace}, {Credo.Check.Readability.VariableNames}, {Credo.Check.Readability.RedundantBlankLines}, {Credo.Check.Readability.SinglePipe, false}, # This is the job of dialyzer {Credo.Check.Readability.Specs, false}, {Credo.Check.Readability.StringSigils}, {Credo.Check.Refactor.ABCSize, false}, {Credo.Check.Refactor.CondStatements}, # That's a feature! {Credo.Check.Refactor.DoubleBooleanNegation, false}, {Credo.Check.Refactor.FunctionArity, max_arity: 8}, {Credo.Check.Refactor.MatchInCondition}, {Credo.Check.Refactor.PipeChainStart, false}, {Credo.Check.Refactor.CyclomaticComplexity}, {Credo.Check.Refactor.NegatedConditionsInUnless}, {Credo.Check.Refactor.NegatedConditionsWithElse}, {Credo.Check.Refactor.Nesting, max_nesting: 3}, {Credo.Check.Refactor.UnlessWithElse}, # That's a feature! {Credo.Check.Refactor.VariableRebinding, false}, {Credo.Check.Warning.IExPry}, {Credo.Check.Warning.IoInspect, false}, # Those are warned by Elixir when it is ambiguous since Elixir v1.4 {Credo.Check.Warning.NameRedeclarationByAssignment, false}, {Credo.Check.Warning.NameRedeclarationByCase, false}, {Credo.Check.Warning.NameRedeclarationByDef, false}, {Credo.Check.Warning.NameRedeclarationByFn, false}, {Credo.Check.Warning.OperationOnSameValues}, {Credo.Check.Warning.BoolOperationOnSameValues}, {Credo.Check.Warning.UnusedEnumOperation}, {Credo.Check.Warning.UnusedKeywordOperation}, {Credo.Check.Warning.UnusedListOperation}, {Credo.Check.Warning.UnusedStringOperation}, {Credo.Check.Warning.UnusedTupleOperation}, {Credo.Check.Warning.OperationWithConstantResult} # Custom checks can be created using `mix credo.gen.check`. # ] } ] } hex-2.0.6/.formatter.exs000066400000000000000000000001411437023760000151030ustar00rootroot00000000000000[ inputs: [ "*.exs", "config/*.exs", "lib/**/*.ex", "test/**/*.{ex,exs}" ] ] hex-2.0.6/.github/000077500000000000000000000000001437023760000136455ustar00rootroot00000000000000hex-2.0.6/.github/workflows/000077500000000000000000000000001437023760000157025ustar00rootroot00000000000000hex-2.0.6/.github/workflows/main.yml000066400000000000000000000070311437023760000173520ustar00rootroot00000000000000name: CI on: [push, pull_request] jobs: format: name: Format runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v3 - name: Install OTP and Elixir uses: erlef/setup-beam@v1 with: otp-version: 24 elixir-version: 1.12 version-type: strict - name: Install dependencies run: mix deps.get - name: Check mix format run: mix format --check-formatted test: name: Test runs-on: ubuntu-18.04 services: postgres: image: postgres:14 env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: postgres ports: - 5432:5432 options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 strategy: fail-fast: false matrix: pair: - erlang: master elixir: 1.14.0 - erlang: 25.0 elixir: main - erlang: 25.0 elixir: 1.14.0 - erlang: 25.0 elixir: 1.13.4 - erlang: 24.0 elixir: 1.12.3 - erlang: 23.1 elixir: 1.11.3 - erlang: 23.1 elixir: 1.10.4 - erlang: 22.3 elixir: 1.9.4 - erlang: 21.3 elixir: 1.8.1 - erlang: 21.3 elixir: 1.7.2 - erlang: 21.3 elixir: 1.6.6 - erlang: 20.3 elixir: 1.5.3 env: HEXPM_OTP: OTP-25.0 HEXPM_ELIXIR: v1.14.0 HEXPM_PATH: hexpm HEXPM_ELIXIR_PATH: hexpm_elixir HEXPM_OTP_PATH: hexpm_otp HEXPM_MIX_HOME: hexpm_mix HEXPM_MIX_ARCHIVES: hexpm_mix steps: - uses: actions/checkout@v3 - name: Install OTP and Elixir uses: erlef/setup-beam@v1 with: otp-version: ${{matrix.pair.erlang}} elixir-version: ${{matrix.pair.elixir}} version-type: strict - name: Install OTP and Elixir for hexpm run: | wget https://repo.hex.pm/builds/otp/ubuntu-16.04/${HEXPM_OTP}.tar.gz mkdir -p ${HEXPM_OTP_PATH} tar -xf ${HEXPM_OTP}.tar.gz -C ${HEXPM_OTP_PATH} --strip-components=1 ${HEXPM_OTP_PATH}/Install -minimal $(pwd)/${HEXPM_OTP_PATH} wget https://repo.hex.pm/builds/elixir/${HEXPM_ELIXIR}.zip unzip -d ${HEXPM_ELIXIR_PATH} ${HEXPM_ELIXIR}.zip mkdir -p ${HEXPM_MIX_HOME} PATH=$(pwd)/${HEXPM_ELIXIR_PATH}/bin:$(pwd)/${HEXPM_OTP_PATH}/bin:${PATH} MIX_HOME=$(pwd)/${HEXPM_MIX_HOME} MIX_ARCHIVES=$(pwd)/${HEXPM_MIX_HOME} mix local.hex --force PATH=$(pwd)/${HEXPM_ELIXIR_PATH}/bin:$(pwd)/${HEXPM_OTP_PATH}/bin:${PATH} MIX_HOME=$(pwd)/${HEXPM_MIX_HOME} MIX_ARCHIVES=$(pwd)/${HEXPM_MIX_HOME} mix local.rebar --force - name: Set up hexpm run: | git clone https://github.com/hexpm/hexpm.git hexpm cd hexpm; PATH=$(pwd)/../${HEXPM_ELIXIR_PATH}/bin:$(pwd)/../${HEXPM_OTP_PATH}/bin:${PATH} MIX_HOME=$(pwd)/../${HEXPM_MIX_HOME} MIX_ARCHIVES=$(pwd)/../${HEXPM_MIX_HOME} MIX_ENV=hex ../${HEXPM_ELIXIR_PATH}/bin/mix deps.get; cd .. cd hexpm; PATH=$(pwd)/../${HEXPM_ELIXIR_PATH}/bin:$(pwd)/../${HEXPM_OTP_PATH}/bin:${PATH} MIX_HOME=$(pwd)/../${HEXPM_MIX_HOME} MIX_ARCHIVES=$(pwd)/../${HEXPM_MIX_HOME} MIX_ENV=hex ../${HEXPM_ELIXIR_PATH}/bin/mix compile; cd .. - name: Install dependencies run: | sudo rm -rf /usr/local/bin/rebar3 mix deps.get mix deps.compile - name: Run tests run: mix test hex-2.0.6/.gitignore000066400000000000000000000001461437023760000142760ustar00rootroot00000000000000/_build /deps /tmp /src/mix_safe_erl_term.erl erl_crash.dump hex-1.x.csv hex-1.x.csv.signed *.ez /doc hex-2.0.6/CHANGELOG.md000066400000000000000000001024271437023760000141240ustar00rootroot00000000000000# CHANGELOG ## v2.0.6 (2023-02-06) ### Bug fixes * Fix application startup when there are configured organizations ## v2.0.5 (2023-02-06) ### Bug fixes * Fix HTTP authentication for repositories added before v2.0.3 ## v2.0.4 (2023-02-02) ### Bug fixes * Fix trust lookup for organizations ## v2.0.3 (2023-02-01) ### Enhancements * Remove dependency on `ssh` application * Add `trusted_mirror_url` config and `HEX_TRUSTED_MIRROR_URL` environment variable. When setting either of these the repository authentication key will be included in requests. `mirror_url` config and `HEX_MIRROR_URL` have changed to no longer include the authentication key in requests. This is to ensure secrets are not sent to repository mirrors that are not trusted. ## v2.0.2 (2023-01-30) ### Enhancements * Remove `hex.install` task ### Bug fixes * Fixes for upcoming Elixir 1.15.0 release ## v2.0.1 (2023-01-09) ### Enhancements * Raise when parsing intersected ranges * Skip unselected optionals during solving ### Bug fixes * Fix converging of requirements from different sources * Fix organization owner prompt during publish * Do not override locked deps ## v2.0.0 (2022-10-30) ### Enhancements * New version solver with higher performance and better error messages * Switch to IPv6 if requests fail due to connection errors ### Bug fixes * Fix browser opening on Windows ## v1.0.1 (2021-12-14) ### Bug fixes * Fix compatibility with some Elixir and OTP combinations ## v1.0.0 (2021-12-13) ### Enhancements * Set exit code to 1 when `mix hex.publish` fails * Validate OSS licenses * Read authorization credentials from `~/.netrc` * Error if building package with an `app: false` dependency ### Bug fixes * Do not error if the organization authorization key could not be verified, this improves handling of API server issues * Improvements to version solver to prevent scenarios where it takes a long time to find a solution * Improve error when update checker times out ## v0.21.3 (2021-09-18) ### Enhancements * Add config `no_short_urls` and env var `HEX_NO_SHORT_URLS` to disable short URL generation * Mention `mix hex.sponsor` when fetching packages that accept sponsorship * Add `--key` option to `mix hex.repo show NAME` to print repository key * Improve output when update check fails * Print hint if version resolution is slow ### Bug fixes * Improve version backtracking to fix slow version resolutions and downgrading of dependencies ## v0.21.2 (2021-04-14) ### Enhancements * Add support for `mix hex.package fetch PACKAGE` (without version) ### Bug fixes * Gracefully handle missing hex metadata in sponsor task * Fix building hex registry * Update ssl opts for host validation on redirect * Store correct password after confirmation failure ## v0.21.1 (2021-01-15) ### Enhancements * Warn when using ssl-10.2 * Disable API write operations when using ssl-10.2 ## v0.21.0 (2021-01-14) ### Enhancements * Add `--epub` option to `mix hex.docs offline` * Add `--replace` option to `mix hex.publish` * Add locked version to `mix hex.info ` * Clarify publish message around ownership * Remove reliance on colors for hex.outdated * Follow XDG Base Directory Specification * Add link to diffs page in footer of `mix hex.outdated` * Introduce `latest` branch to install Hex using `mix archive.install git ...` * Add `--repo` flag to `mix hex.package` task * Make `mix hex.package diff` more CLI-friendly * Customize hostname check to allow also wildcard certificates * Use API for dependency config in mix hex.info * Do not pass --canonical to docs task * Always add `*.DS_Store` to `:exclude_patterns` * Add note about updatable packages to `mix hex.outdated` task * Use tarball outer checksum to check cache freshness * Add `--within-requirements` flag to `mix hex.outdated` * Add `--fetch-public-key FINGERPRINT` to `mix hex.repo add` * Return non-zero exit when package or release are not found in `mix hex.info` * Add `no_proxy` configuration * Add `mix hex.package diff APP VERSION` * Add `mix hex.sponsor` for listing all dependencies ask for sponsors or support * Add `mix hex.registry build` for building registries locally ### Bug fixes * Fix order of organizations displayed on `mix hex.publish` * Fix stacktrace warning * Hide `mix hex.install` private task * Fix `mix hex.repo remove` command doc * Fix backtracking on single parent * Do not unpack the tarball on `mix hex.package fetch` unless `--unpack` is passed * Re-fetch stale cached package if registry checksum changed * Fix compatibility with OTP 24 ## v0.20.6 (2020-10-20) ### Bug fixes * Fix compatibility with OTP 24 ## v0.20.5 (2020-02-05) ### Enhancements * Add timestamps to entries in registry cache for easier debugging * Bump registry cache version to invalidate old caches * Warn if fetching registry without outer checksum ### Bug fixes * Do not require that the registry supports outer checksums * Missing outer checksum is not a mismatch, this will fix "out of date" errors when the manifest is newer than the lockfile ## v0.20.4 (2020-02-04) ### Bug fixes * Fix tarball file extraction through symlinks ## v0.20.3 (2020-02-03) ### Enhancements * Fetch the latest non-prerelease version of a package in `mix hex.docs ` ### Bug fixes * Correctly handle old manifest files without crashing ## v0.20.2 (2020-02-03) ### Enhancements * Add `--output` option to `mix hex.package fetch` task * Add `cacerts_path` configuration for custom CA certificate files * Improve output in `mix hex.publish` to make it more clear to what repository you are publishing * Explain red colors in hex.outdated ### Bug fixes * Fix HTTP timeout config * Do not allow creating empty packages ### Security fixes * Fix for directory traversal vulnerability for symlinks in tarballs * Update package checksum to include the entire tarball instead of specific files inside it ## v0.20.1 (2019-06-10) ### Bug fixes * Do not print transfer message when not transferring ## v0.20.0 (2019-06-09) ### Enhancements * Add per-project Hex configuration. Configure Hex under the `:hex` key inside your project configuration in `mix.exs` * Show location of package after running `mix hex.build` * List all available Hex tasks when running `mix hex` * List subtasks when running `mix hex` * Remove tarball if it is invalid to avoid it being as cache in the future * Show umbrella children `mix.exs` location in `mix hex.outdated` * Add `mix hex.owner transfer` task * Show improved error message on invalid configs * Add `mix hex.package fetch` task * Add `mix hex.package diff` task ### Bug fixes * Fix `mirror_url` config * Fix `api_url` config * Do no try to remove docs after reverting package – docs are already automatically removed ## v0.19.0 (2019-01-15) ### Enhancements * Improve output of `mix hex.config` * Print publisher in `mix hex.info PACKAGE VERSION` * Add organization flag to dependency config in `mix hex.info PACKAGE` ### Bug fixes * Don't follow symlinks when adding files to tarballs * Error with a descriptive msg when building a package with git dependencies * Improve listing of incompatible package versions when displaying backtrack error message * Improve resolver performance when it needs to do a lot of backtracking ### Security fixes * Verify authenticity of registry records. This fixes a vulnerability that would allow a malicious mirror to serve modified versions of Hex packages. A new check has been introduced that requires the latest registry record version, if you are using a repository or mirror that has not been updated yet you can disable this check by setting the environment variable `HEX_NO_VERIFY_REPO_ORIGIN=1`. Further clarification of this issue will come at a later stage. ## v0.18.2 (2018-11-08) ### Enhancements * Add checks before publishing docs * Update generated protobuf files for Registry with OTP 21 compatibility * No longer list tasks in `mix hex` task * Use hexdocs organization URLs * Adds `--dry-run` option to publish tasks * Do not print "Unchanged" dependencies on mix deps.get in green * Validate hex config keys * Add `c_src/` and `Makefile` to default package files * Publish Mix task docs on * Add recommendation when retiring and require `--message` flag ### Bug fixes * Use rebar3, not rebar, when guessing build tool * Fix issue saving write key when resetting local password ## v0.18.1 (2018-07-06) ### Bug fixes * Fix normalization of repo paths when authenticating organization ## v0.18.0 (2018-07-05) ### API keys When authenticating with `mix hex.user auth` two API keys are generated instead of single one. One key is unencrypted with read access and the other is encrypted with your local password and has full read/write access to the API. Now commands that don't make any changes will not require a password. Additionally, we generate a single key that gives access to all your organization repositories, instead of one key for each repository. It also has the added benefit that you don't have to reauthenticate if you are added to a new organization. We have also added support for keys owned directly by an organization instead of a specific user, these keys can be accessed through `mix hex.organization`. This is useful when generating keys for a CI environment, previously when personal keys were used, a person leaving an organization or revoking the key could negatively affect CI workflow. ### Improvements to continuous integration workflows The `HEX_API_KEY` environment variable has been introduced to be able run commands that require an authentication without having to authenticate manually with `mix hex.user auth` which has user input prompts. The key set with `HEX_API_KEY` can be generated with `mix hex.user key generate` or `mix hex.organization key ORGANIZATION generate`. It also makes it possible to run commands such as `mix hex.publish` without being prompted for a password. By passing the `--yes` flag to `mix hex.publish` you can publish your package (together with `HEX_API_KEY`) without any confirmation prompts. This allows you to publish your package as part of your CI build process. ### Ignoring `:maintainers` field In previous Hex versions we required `:maintainers` key to be present when publishing package. At the same time, on hex.pm we are also showing package owners (controlled by the `mix hex.owner` task). It was confusing to show both maintainers and owners and figure out which really control the package, so we've dropped showing maintainers on hex.pm and the field will no longer be added to package's metadata. If maintainers field was used to give credit to current and/or past contributors we encourage to mention that in project's README instead. ### Enhancements * Add `--yes` flag to `hex.publish` for publishing without any confirmation prompts * Add `HEX_API_KEY` environment variable for setting and overriding the key used when authenticating against the API * Generate a single key for all organization repositories when authenticating a new user * Return a non-zero exit code from `hex.outdated` when dependencies are outdated * Generate two API keys when authenticating, one encrypted with write access, and one unencrypted with only read access * Add ownership levels to `hex.owner` task * When resolving, try all possible backtrack branches and select the best solution * Improve formatting of multi-line validation errors * Do not use `:maintainers` package configuration field * Change `hex.organization` to generate keys owned by organization instead of the user generating them * Add options to `hex.organization key` for revoking and listing keys owned by organization * Improve interface for `hex.user key` and `hex.organization key`, the following commands have changed: * `hex.user key --generate` => `hex.user key generate` * `hex.user key --list` => `hex.user key list` * `hex.user key --revoke KEY_NAME` => `hex.user key revoke KEY_NAME` * `hex.user key --revoke-all` => `hex.user key revoke --all` * `hex.organization key ORGANIZATION` => `hex.organization key ORGANIZATION generate` ## v0.17.8 (2018-07-01) ### Bug fixes * Fix private packages on Windows ## v0.17.7 (2018-04-20) ### Bug fixes * Fix crash when unpacking tarballs with broken symlinks * Correct the type of build tools package metadata ## v0.17.6 (2018-04-18) ### Bug fixes * Fix crash when printing resolver output when having lock entries from other SCMs ## v0.17.5 (2018-04-18) ### Bug fixes * Fix crash when printing resolver output for old lock files ## v0.17.4 (2018-04-18) ### Enhancements * Tarball and registry code has been extracted to the `hex_erl` package * Hide retired versions when showing latest release in `hex.info` task * Add `hex.docs offline` and `hex.docs` online tasks * Add `--key-name` flag to key generation tasks * Add `:exclude_patterns` to package config for excluding files from package * Resolver now backtracks children before parents to improve versions selected when backtracking * Change some errors to warnings when building private packages * Group resolved dependency output into unchanged, updated, and downgraded when running `deps.get` and `deps.update` tasks * Add authentication to `hex.docs` task for showing private package documentation * Improve error message when package fetch times out * General improvements to tasks when accessing organizations ### Bug fixes * Fix wrong publish message when using `--organization` flag in `hex.publish` task * Set file times inside tarballs to 2000-01-01 to fix tars on FAT file systems * Fix `hex.docs open` task on Windows ## v0.17.3 (2018-01-17) ### Bug fixes * Handle missing package descriptions in `hex.search` task * Fix printing of package checksum after publishing ## v0.17.2 (2018-01-16) ### Enhancements * Increase `hex.publish` timeouts and make it configurable with `:http_timeout` config and `HEX_HTTP_TIMEOUT` variable * Test key before adding it with `hex.organization auth NAME --key KEY` * Remove pre-release publish restriction for private packages * Add package descriptions to `hex.search` task * Improve error message when there are no versions matching requirement * Add latest stable version to `hex.search` task * Add `metadata.config` file to checked out dependency directory * Warn if we detect a lock entry from a newer Hex version * Add `hex.build --output` and `hex.build --unpack` tasks * Preserve symlinks and empty directories in tar * Simplify Hex output on deps.get * General improvements to tarball creation and unpacking * List umbrella children's top level dependencies in `hex.outdated` * Include `.formatter.exs` file in default package builds * Prompt user when authentication is required * Automatically auth all organizations when authing user with `hex.user auth` * Highlight if a package release has been retired in `hex.info` * Display package website links in `mix hex.owner packages` ### Bug fixes * Do not crash if failing to write tarball * Disable HTTP pipelining to avoid bugs in HTTP client * Also purge registry etags when repository source changed * Retry HTTP requests on `:socket_closed_remotely` errors * Fix package tarballs being reproducible * Authenticate HTTP requests for `hex.search` * Populate managers when initially getting dependencies * Check dependencies on `hex.audit` and `hex.publish` * Fix fetching of private packages that overrides public packages * Fix HTTP redirect handling * Don't display internal configs in `hex.config` ## v0.17.1 (2017-08-29) ### Enhancements * Improve error message when package does not exist * Improve error message when no versions exist for given requirement * Add `--key` flag to `hex.organization auth` to authorize by giving a key directly without supplying a password * Add `hex.organization key` to generate a key for accessing the organization's repository ## v0.17.0 (2017-08-28) ### Private packages and organizations Hex.pm is adding support for private packages with organizations. See https://hex.pm/docs/private for more details. To authorize an organization on your machine run `mix hex.organization auth acme`, this will store the organization's repository details in Hex so that you can fetch packages from the repository. As soon as you are added as a member to an organization you can administer and publish packages, if you have the appropriate role, with the `--organization` flag or by setting the `:organization` option on the package configuration. Different from the last release packages will always be pulled from the default `hexpm` repository and you have to override it with the `:organization` or `:repo` options on the dependency configuration. ### Enhancements * Add `hex.organization` task * Rename `hex.user key` flag `--remove*` to `--revoke*` to clarify what it does * Add `--organization` flag to tasks working on packages * Add `:organization` option to package configuration * Add support for publishing to organizations * Improve error message when docs task is missing * Add `--confirm` flag to `hex.publish` task ### Bug fixes * Fix version validation exceptions * Reintroduce `HEX_MIRROR` environment variable * Preserve file modes when building tarball * Disallow `:app` option for dependencies ## v0.16.1 (2017-06-22) ### Enhancements * Add `mix hex.repo show` task for showing repo configuration * Improve error message if there are no releases for given requirement in the registry * Add `mix hex.audit` task for checking for retired packages ### Bug fixes * Do not try to publish docs if package publish failed * Do not update lock entry if only metadata changed * Do not show authentication details when printing URLs * Fix password reset * Fix race condition where some entries may not be cached if they were added just before application closed * Support PAX tarballs, created on OTP 20, when using older OTP versions. Additionally, make it less likely PAX tarballs are created ## v0.16.0 (2017-04-18) ### Multiple repository support This version adds support for using packages from multiple repositories. With the `hex.repo` task additional repositories can be added to Hex. With it you can add additional repositories or replace the default "hexpm" repository by running `mix hex.repo add hexpm ...`, check the docs for more information. To use a dependency from another repository add `repo: :my_other_repo` to the dependency definition in `mix.exs` and make sure you have added `my_other_repo` with `mix hex.repo add my_other_repo`. Dependencies of a package will be automatically pulled from the same repository as the parent package unless otherwise stated with the `:repo` option on the dependency definition. ### Enhancements * Add `hex.repo` task * Move `hex.key` tasks to `hex.user keys` * Warn or error if publishing a package with pre-release dependencies ### Bug fixes * Do not check for updates when running in offline mode * Fix an issue where dependency resolution could take a very long time * Do not publish docs if publishing the package failed * Fix an issue where HTTP timeouts could cause the application to freeze * Ensure managers always exist in the lock ## v0.15.0 (2016-12-24) ### Package retirement With this new release you can mark versions of your packages as retired when you no longer recommend its use. This can be because the release has a serious security flaw, something went wrong with the release so that it's unusable or because the package has been renamed or deprecated. A retired version is still usable and fetchable but it will show as retired on hex.pm and when resolved Hex will show a warning to the user with the retirement message. ### Enhancements * Add --module flag to `hex.docs` task * Changed `hex.outdated` task to show if a dependency can be updated * Add `hex.retire` task for package retirement * Warn when resolving retired packages * Restrict number of default SSL ciphers ### Bug fixes * Do not make conditional HTTP request if file is missing * Ensure cache file is saved when Hex exits ## v0.14.1 (2016-11-24) ### Enhancements * Add environment variable `HEX_HTTP_CONCURRENCY` for limiting number of concurrent HTTP requests ### Bug fixes * Fix compatibilities with older Elixir version (<= 1.1) * Ensure build tools are unique in mix.lock and when publishing * Fix `hex.docs open` opening websites on Unix systems * Do not crash on diverged dependencies with conflicting SCMs * Fix some duplicate HTTP requests on slow networks * Limit concurrent registry HTTP requests ## v0.14.0 (2016-10-28) ### New registry format Hex has switched to a new registry format that is more efficient and will scale better as the registry grows. The new registry format is encoded with protocol buffers and is split into multiple files (one file per package) to avoid fetching one big file with data you will not need. The resolver will make more HTTP requests but will in total fetch much less data. The specification for the new format can be found here: https://github.com/hexpm/specifications/pull/10. The old ETS based registry format is no longer supported in the client but will continue to be available from the registry for the foreseeable future. ### Enhancements * `hex.docs open` will by default open the online hexdocs for the given package * An `--offline` option has been added to `hex.docs open` for opening docs stored on your local filesystem and it will automatically fetch the docs if they are not available locally * Only support secure SSL ciphers and safe SSL versions (support for SSLv3 has been dropped) * Improvements to the language in the resolver error messages ### Bug fixes * Fix an issue where duplicate build tool names could be added to the package metadata ## v0.13.2 (2016-09-19) ### Bug fixes * Only error on non-Hex dependencies when building ## v0.13.1 (2016-09-19) ### Enhancements * Most warnings on `hex.publish` are now errors ### Bug fixes * Fix bug where the old config format was not readable * Convert old config format to new format on every read * Fix `HEX_UNSAFE_REGISTRY` negation ## v0.13.0 (2016-07-30) ### Enhancements * Inform about new Hex version in `hex.info` * Support `extra` metadata field * Print package checksum when building and publishing * Warn if using registry from cache * Show creation time of API keys in `hex.keys list` * Improve the error message if OTP has broken SNI in `:ssl` application * Verify dependencies from registry against lock * Hex will now automatically encrypt your local API key, use `hex.user passphrase` to change the encryption passphrase * Improve resolver error message to mention behavior of pre-releases and overrides * Improve error message if a dependency has configured the OTP application name incorrectly for another dependency * `hex.publish` now also publishes docs by default, use `hex.publish package` and `hex.publish docs` to respectively publish package and docs independently * `hex.docs` will now open or fetch documentation tarballs * `hex.key remove` will now also de-auth the user if the local API key was removed * Add status messages when publishing and reverting ### Bug fixes * Fix bug where the client was fetching packages even when lock is OK * Fix resolver sometimes not producing any backtrack output * Verify certificate against correct hostname after redirect ## v0.12.1 (2016-05-31) ### Enhancements * Only show proxy settings when MIX_DEBUG=1 * Add retries to idempotent requests ### Bug fixes * Fix crash when you get multiple backtrack messages ## v0.12.0 (2016-05-15) ### Enhancements * Add package checksums to lock, ensuring a locked package can not change its content * Add managers and deps to lock, allowing Hex to run without loading the registry * Align deps fetching output from scm * Update hex.pm repo URL to https://repo.hex.pm * Link to policies when registering account * Update CoC links * Improve conflict messages * Improve error messages when ex_doc is missing when publishing docs * Show app name of dependency in `hex.info` * Warn about long package descriptions ### Bug fixes * Fix `HEX_UNSAFE_HTTPS` environment variable and `unsafe_https` config ## v0.11.5 (2016-04-07) ### Enhancements * Add more registry metrics to `hex.info` ### Bug fixes * Fix a bug where Hex was about a bit too enthusiastic when informing the user of new versions * Fix some missing future-proofing of lock ## v0.11.4 (2016-04-06) ### Enhancements * Use HTTPS to Hex.pm repository * Make lock backwards compatible by treating it as a list and only matching on the front ### Bug fixes * Correctly show update notification * Remove duplicate parents from backtrack messages * Fix invalid message in `hex.outdated` if locked version is a pre-release ## v0.11.3 (2016-03-14) ### Bug fixes * Do not crash if registry fails to fetch * Remove force update of registry if it is more than a week old ## v0.11.2 (2016-03-11) ### Enhancements * Verify registry signature against public key * Improve missing registry error message * Deprecate `HEX_CDN` in favor of `HEX_REPO` and `HEX_MIRROR`. See the `hex` task for more information * Deprecate `:cdn_url` config in favor of `:repo_url` and `mirror_url`. See the `hex.config` task for more information * Improve performance of parallel package fetching * Use fastly instead of S3 for the Hex.pm repository * Add `--delete` option to `hex.config` task ### Bug fixes * Show local time in hex.info * Correctly unlock all dependencies on `deps.update` * Always fetch registry if it's missing or known to be old ## v0.11.1 (2016-03-03) ### Bug fixes * Fix incorrect build version check * Fix parsing of requirements without spaces ## v0.11.0 (2016-03-03) ### Enhancements * Append the OTP version to the user_agent function * Improve output of http request timeout errors * Warn if `:manager` or `:compile` is set on dependencies when publishing * Add `--pre` flag to `hex.outdated` * Use erlang binary term encoding for API instead of elixir encoding * Pull package name from correct source when publish docs * Pass canonical url to ex_doc task * Change hexdocs links to use https * Add `hex.outdated APP` to list all requirements on given dependency * Do not allow pre-releases for dependencies unless the requirement uses a pre-release version * Optimize version cache memory usage ### Bug fixes * Fix incorrect build version check for dev versions of Elixir * Fix loop when backtracking in resolver * Fix timeout errors on slow systems ## v0.10.4 (2016-01-26) ### Enhancements * Make the experimental resolver the default ### Bug fixes * Ensure registry can be opened/closed multiple times * Ensure `hex.search` task handles empty results * Fix experimental resolvers only backtracking on parents that had requirements that failed * Fix merging of overlapping parent and package versions in backtrack messages ## v0.10.3 (2016-01-23) ### Bug fixes * Fix bug when umbrella child has dependency with `:only` ## v0.10.2 (2016-01-22) ### Enhancements * General optimizations in dependency resolver * Add experimental faster backtracker that does more aggressive backtracking, set environment variable `HEX_EXPERIMENTAL_RESOLVER=1` to use it * Merge backtrack messages that have similar parents * Merge multiple versions into version ranges when possible for more succinct backtrack messages ### Bug fixes * Reduce memory usage when resolver produces many backtrack messages ## v0.10.1 (2016-01-15) ### Bug fixes * Fix a crash when a dependency is missing its version requirement ## v0.10.0 (2016-01-14) ### Enhancements * Add support for authentication when using HTTP proxies * Add more build information to `hex.info` task to ease debugging * Greatly improve backtracking error messages * Prevent packages for being published without a description * Improve error printing when S3 return errors * Improve output from `hex.outdated` task * Warn if a package dependency is missing its requirement * Improve error message from `hex.docs` task when `ex_doc` dependency is missing * Remove useless output when fetching dependencies * Improve package output in `hex.info` task ### Bug fixes * Fix a rare bug that could cause the resolver to go into an infinite loop * UTF8 encode package metadata * Only list missing files if `:files` is set * Fix bug when umbrella child has dependency with `:only` ## v0.9.0 (2015-09-25) ### Enhancements * Pass build tool information to Mix (supported in Elixir 1.1.0) * Make Hex a proper OTP application * Update CA store * Warn if files are missing when building package * Improve error message when resolution fails because of a locked dependency * Add `hex.registry` task for loading and dumping registry * Add `HEX_OFFLINE` for running in offline mode which skips fetching registry and packages * Add `hex.build` task for building package without publishing * Reduce noise when users gets lots of resolution errors and generally improve their output * Add Server Name Indication support for HTTPS requests * Add `HEX_UNSAFE_HTTPS` for disabling certificate checking * Rename `:contributors` metadata to `:maintainers` to better reflect purpose of field ### Bug fixes * `HEX_API` no longer automatically adds `api/` to URL * Fix crash when user doesn't explicitly override Hex package when needed * Fix bug where metadata in package tarball was not properly UTF8 encoded * Fix error message when registry file is missing * Support `hex.outdated` task for umbrella projects * Do not raise on bad data in a users old lock ## v0.8.3 (2015-07-17) ### Security fixes * Fix a bug that would trust any certificate in the certificate chain signed by a trusted CA, this could allow the certificate, that is not a CA, to issue and sign new certificates for any host ## v0.8.2 (2015-07-13) ### Enhancements * Sort dependency resolver results ### Bug fixes * Fix build_tools metadata being sent incorrectly ## v0.8.1 (2015-07-12) ### Enhancements * Warn if registry file is missing when loading deps ### Bug fixes * Consider new optional requirements for already activated dependency * Add multiple build tools to metadata ## v0.8.0 (2015-05-19) ### Enhancements * Warn if using insecure SSL because of old OTP version * Use yellow test for warning text * Include build_tools in release metadata * Print more metadata when publishing ### Bug fixes * Fix an error when printing an http status codes * Always fetch new registry if it's older than 7 days ## v0.7.5 (2015-04-12) ### Enhancements * Add task `hex.user test` for testing user authentication. * Add task `hex.outdated` for listing outdated packages compared to the registry. * Update CA store as of April 3. * Inform user if authentication failed because they did not confirm email. * Improve error message for unsupported tarball version. ### Bug fixes * Fix a bug where overriding a Hex dependency with a non-Hex dependency was ignored when the overriding at least two levels deep in the dependency tree ## v0.7.4 (2015-03-16) ### Bug fixes * Include all conflicting requirements in backtrack message * Fix a bug where backtrack message failed on optional requests ## v0.7.3 (2015-03-04) ### Bug fixes * Fix an error when merging locked and optional dependencies ## v0.7.2 (2015-03-04) ### Enhancements * Print messages on backtracks if dependency resolution failed, this is intended to help users resolve conflicts ### Bug fixes * Fix a bug where a dependency converged in mix did not consider all its requirements * Fix a bug where dependencies in the lock was considered even if they weren't requested ## v0.7.1 (2015-02-15) ### Bug fixes * Fix updating the registry ## v0.7.0 (2015-02-15) ### Enhancements * Print proxy options on startup * Add `mix hex.user password reset` and remove `mix hex.user update` * Create version 3 tarballs with erlang term encoded metadata ### Bug fixes * Verify peer certificate against CA certificate public key in `partial_chain` * Fix a bug where overriding a Hex dependency with a non-Hex dependency was ignored when the overriding happened in a sub-dependency * Create hex directory before writing registry ## v0.6.2 (2015-01-02) ### Enhancements * Add PKIX hostname verification according to RFC6125 * Improve error messages from HTTP error codes * Improve HTTP performance * Add config options `api_url`, `cdn_url`, `http_proxy` and `https_proxy` * Support both doc/ and docs/ as documentation directory ## v0.6.1 (2014-12-11) ### Enhancements * Convert config file to erlang term file ## v0.6.0 (2014-10-12) ### Enhancements * Add support for packages with a different OTP application name than the package name * Add task `mix hex.docs` for uploading project documentation * Add email confirmation ### Bug fixes * Allow you to change your password with `mix hex.user update` * Correctly display dependencies in `mix hex.info PACKAGE VERSION` * Verify peer certificates when fetching tarball ## v0.5.0 (2014-09-19) ### Enhancements * Verify peer certificate for SSL (only available in OTP 17.3) * Reduce archive size with compiler option `debug_info: false` * Add support for config as an erlang term file * Warn if Hex was built against a different major.minor Elixir version ## v0.4.3 (2014-09-06) ## v0.4.2 (2014-08-31) ### Enhancements * Add task `hex.user whoami` that prints the locally authorized user * Add task `hex.user deauth` to deauthorize the local user * Rename environment variable `HEX_URL` to `HEX_API` to not confuse it with `HEX_CDN` ### Bug fixes * Print newline after progress bar ## v0.4.1 (2014-08-12) ### Enhancements * Add progress bar for uploading the tarball when publishing * Compare tarball checksum against checksum in registry * Bump tarball support to version 3 * Rename task for authenticating on the local machine from `hex.key new` to `hex.user auth` * Remove the ability to pass password as a CLI parameter ### Bug fixes * Support lower-case proxy environment variables * Remove any timeouts when fetching package tarballs hex-2.0.6/README.md000066400000000000000000000040261437023760000135660ustar00rootroot00000000000000# Hex [![CI](https://github.com/hexpm/hex/workflows/CI/badge.svg)](https://github.com/hexpm/hex/actions) Hex is package manager for the Erlang VM. This project currently provides tasks that integrate with Mix, [Elixir](https://github.com/elixir-lang/elixir)'s build tool. See [hex.pm](https://hex.pm) for installation instructions and other documentation. ## Contributing Install Hex locally for development with: `mix install`. ### Bundled CA certs Hex bundles a list of root CA certificates used for certificate validation in HTTPS. The certificates are fetched from [Mozilla's source tree](http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt) with curl's [mk-ca-bundle.pl](https://github.com/bagder/curl/blob/master/lib/mk-ca-bundle.pl) script. The bundle created from the Perl script is stored in `lib/hex/http/ca-bundle.crt` and is included in source control, the file should be updated when new releases are made by Mozilla. When Hex is compiled the certificates are parsed and included with the compiled artifacts. The task `mix certdata` automates this process. ### hexpm Integration tests run against the API server [hexpm](https://github.com/hexpm/hexpm). It needs to be cloned into `../hexpm` or `HEXPM_PATH` needs to be set and point its location. hexpm also requires postgresql with username `postgres` and password `postgres`. Exclude integration tests with `mix test --exclude integration`. ## License Copyright 2015 Six Colors AB Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. hex-2.0.6/RELEASE.md000066400000000000000000000047661437023760000137240ustar00rootroot00000000000000# Release process This document simply outlines the release process: 1. Remove all `-dev` extension from versions (see below for all files) 2. Ensure CHANGELOG is updated and add current date 3. Update the local `release.sh` with the Elixir and OTP versions Hex should be built against. 4. Commit changes above with title "Release vVERSION" and generate new tag 5. Set branch latest to the new tag 6. Push main branch, latest branch and the new tag 7. Create GitHub release 8. Run the `release.sh` script and set the path to the private key for Elixir `ELIXIR_PEM=path/to/elixir.pem ./release.sh VERSION` where `VERSION` is the Hex version being released without a `v` prefix 9. Purge "installs" key on Fastly dashboard 10. Increment version and add `-dev` extension to versions (see below for all files) 11. Commit changes above with title "Bump to vVERSION-dev" 12. Push main ## All builds Hex needs to built for every Elixir supported vMAJOR.MINOR version. Currently that is every minor version released after 1.0.0. Always build on the latest patch version and make sure tests pass before building the archive. ## Places where version is mentioned * mix.exs `@version` attribute * CHANGELOG.md ## S3 paths * s3.hex.pm/installs/hex.ez (latest Hex built against oldest supported Elixir) * s3.hex.pm/installs/[ELIXIR]/hex.ez * s3.hex.pm/installs/[ELIXIR]/hex-[HEX].ez * s3.hex.pm/installs/hex-1.x.csv * s3.hex.pm/installs/hex-1.x.csv.signed ## S3 upload commands Only for oldest elixir and OTP version: ``` aws s3 cp hex.ez s3://s3.hex.pm/installs/hex.ez --acl public-read ``` ``` aws s3 cp hex.ez s3://s3.hex.pm/installs/[ELIXIR]/hex.ez --acl public-read && aws s3 cp hex-[HEX].ez s3://s3.hex.pm/installs/[ELIXIR]/hex-[HEX].ez --acl public-read && aws s3 cp hex-1.x.csv s3://s3.hex.pm/installs/hex-1.x.csv --acl public-read && aws s3 cp hex-1.x.csv.signed s3://s3.hex.pm/installs/hex-1.x.csv.signed --acl public-read ``` ## Hex release CSV ### CSV format ``` hex_version,sha512(hex-[HEX].ez),elixir_version ``` Example: ``` 0.9.0,4f6eae32124500117691740358df2a078d014f4d396a56a73b3e553e0b112b3f0ac9e0f7e0763feb85c889bac20571c6e028e5f4c252ac158cbb3c586efe992f,1.0.0 0.9.0,21fd3dbff18b2d2d51b41e147ac8bd13188a9840dae8f4ced6c150e227df64c3c6c5a472c3fd74e170f14fcf7cbeb7d85e12a520438bf0731c1ac55d2f6a4a8a,1.1.0 ``` ### Generate sha ``` shasum -a 512 hex-[HEX].ez ``` ### Sign CSV ``` openssl dgst -sha512 -sign elixir.pem hex-1.x.csv | openssl base64 > hex-1.x.csv.signed ``` hex-2.0.6/config/000077500000000000000000000000001437023760000135525ustar00rootroot00000000000000hex-2.0.6/config/config.exs000066400000000000000000000002241437023760000155360ustar00rootroot00000000000000import Config if config_env() == :test do config :logger, level: :warn config :logger, :console, format: "$date $time [$level] $message\n" end hex-2.0.6/config/mix_config.exs000066400000000000000000000002221437023760000164110ustar00rootroot00000000000000use Mix.Config if Mix.env() == :test do config :logger, level: :warn config :logger, :console, format: "$date $time [$level] $message\n" end hex-2.0.6/lib/000077500000000000000000000000001437023760000130535ustar00rootroot00000000000000hex-2.0.6/lib/hex.ex000066400000000000000000000010521437023760000141730ustar00rootroot00000000000000defmodule Hex do @moduledoc false def start() do {:ok, _} = Application.ensure_all_started(:hex) end def stop() do case Application.stop(:hex) do :ok -> :ok {:error, {:not_started, :hex}} -> :ok end end # For compatibility during development def start(start_type, start_args) do Hex.Application.start(start_type, start_args) end def version(), do: unquote(Mix.Project.config()[:version]) def elixir_version(), do: unquote(System.version()) def otp_version(), do: unquote(Hex.Utils.otp_version()) end hex-2.0.6/lib/hex/000077500000000000000000000000001437023760000136375ustar00rootroot00000000000000hex-2.0.6/lib/hex/api.ex000066400000000000000000000062421437023760000147520ustar00rootroot00000000000000defmodule Hex.API do @moduledoc false alias Hex.HTTP @erlang_content ~c"application/vnd.hex+erlang" @tar_content ~c"application/octet-stream" @tar_chunk_size 10_000 @tar_timeout 60_000 def request(method, repo, path, opts \\ []) do HTTP.request(method, url(repo, path), headers(opts), nil) |> handle_response() end def erlang_post_request(repo, path, body, opts \\ []) do HTTP.request(:post, url(repo, path), headers(opts), encode_erlang(body)) |> handle_response() end def erlang_put_request(repo, path, body, opts \\ []) do HTTP.request(:put, url(repo, path), headers(opts), encode_erlang(body)) |> handle_response() end def tar_post_request(repo, path, body, opts \\ []) do progress = Keyword.fetch!(opts, :progress) headers = %{~c"content-length" => Integer.to_charlist(byte_size(body))} |> Map.merge(headers(opts)) opts = [ timeout: Hex.State.fetch!(:http_timeout, fn val -> if is_integer(val), do: val * 1000 end) || @tar_timeout ] HTTP.request(:post, url(repo, path), headers, encode_tar(body, progress), opts) |> handle_response() end defp url(repo, path) do api_url = Hex.State.fetch!(:api_url) api_url <> repo_path(repo) <> path end defp repo_path(nil), do: "/" defp repo_path(org), do: "/repos/#{org}/" defp headers(opts) do %{~c"accept" => @erlang_content} |> Map.merge(auth(opts)) end defp auth(opts) do cond do opts[:key] -> %{~c"authorization" => String.to_charlist(opts[:key])} opts[:user] && opts[:pass] -> base64 = :base64.encode_to_string(opts[:user] <> ":" <> opts[:pass]) %{~c"authorization" => ~c"Basic " ++ base64} true -> %{} end end defp encode_erlang(body) do {@erlang_content, Hex.Utils.safe_serialize_erlang(body)} end defp encode_tar(body, progress) do body = fn size when size < byte_size(body) -> new_size = min(size + @tar_chunk_size, byte_size(body)) chunk = new_size - size progress.(new_size) {:ok, :binary.part(body, size, chunk), new_size} _size -> :eof end {@tar_content, {body, 0}} end defp handle_response({:ok, {code, body, headers}}) do {:ok, {code, decode_body(body, headers), headers}} end defp handle_response({:error, term}) do {:error, term} end defp decode_body(body, headers) do content_type = List.to_string(headers[~c"content-type"] || ~c"") erlang_vendor = List.to_string(@erlang_content) if String.contains?(content_type, erlang_vendor) do Hex.Utils.safe_deserialize_erlang(body) else body end end def check_write_api() do case Application.load(:ssl) do :ok -> if :application.get_key(:ssl, :vsn) == {:ok, ~c"10.2"} do Mix.raise(""" You are using an OTP release with the application ssl-10.2 which has a vulnerability \ making it susceptible to man-in-the-middle attacks. API operations with write capabilities are disabled until you upgrade to newer version, ssl-10.2.1+ or OTP-23.2.2+. """) end {:error, _} -> :ok end end end hex-2.0.6/lib/hex/api/000077500000000000000000000000001437023760000144105ustar00rootroot00000000000000hex-2.0.6/lib/hex/api/auth.ex000066400000000000000000000002751437023760000157130ustar00rootroot00000000000000defmodule Hex.API.Auth do @moduledoc false alias Hex.API def get(domain, resource, auth) do API.request(:get, nil, "auth?domain=#{domain}&resource=#{resource}", auth) end end hex-2.0.6/lib/hex/api/key.ex000066400000000000000000000023621437023760000155410ustar00rootroot00000000000000defmodule Hex.API.Key do @moduledoc false alias Hex.API def new(name, permissions, auth) do Hex.API.check_write_api() API.erlang_post_request(nil, "keys", %{name: name, permissions: permissions}, auth) end def get(auth) do API.request(:get, nil, "keys", auth) end def delete(name, auth) do Hex.API.check_write_api() API.request(:delete, nil, "keys/#{URI.encode(name)}", auth) end def delete_all(auth) do Hex.API.check_write_api() API.request(:delete, nil, "keys", auth) end defmodule Organization do @moduledoc false def new(organization, name, permissions, auth) do Hex.API.check_write_api() API.erlang_post_request( nil, "orgs/#{organization}/keys", %{name: name, permissions: permissions}, auth ) end def get(organization, auth) do API.request(:get, nil, "orgs/#{organization}/keys", auth) end def delete(organization, name, auth) do Hex.API.check_write_api() API.request(:delete, nil, "orgs/#{organization}/keys/#{URI.encode(name)}", auth) end def delete_all(organization, auth) do Hex.API.check_write_api() API.request(:delete, nil, "orgs/#{organization}/keys", auth) end end end hex-2.0.6/lib/hex/api/package.ex000066400000000000000000000021071437023760000163410ustar00rootroot00000000000000defmodule Hex.API.Package do @moduledoc false alias Hex.API def get(repo, name, auth \\ []) do path = "packages/#{URI.encode(name)}" API.request(:get, repo, path, auth) end def search(repo, search, auth \\ []) do path = "packages?search=#{URI.encode(search)}&sort=downloads" API.request(:get, repo, path, auth) end defmodule Owner do @moduledoc false def add(repo, package, owner, level, transfer, auth) do Hex.API.check_write_api() owner = URI.encode_www_form(owner) path = "packages/#{URI.encode(package)}/owners/#{URI.encode(owner)}" params = %{level: level, transfer: transfer} API.erlang_put_request(repo, path, params, auth) end def delete(repo, package, owner, auth) do Hex.API.check_write_api() owner = URI.encode_www_form(owner) path = "packages/#{URI.encode(package)}/owners/#{URI.encode(owner)}" API.request(:delete, repo, path, auth) end def get(repo, package, auth) do API.request(:get, repo, "packages/#{URI.encode(package)}/owners", auth) end end end hex-2.0.6/lib/hex/api/release.ex000066400000000000000000000022111437023760000163620ustar00rootroot00000000000000defmodule Hex.API.Release do @moduledoc false alias Hex.API def get(repo, name, version, auth \\ []) do path = "packages/#{URI.encode(name)}/releases/#{URI.encode(version)}" API.request(:get, repo, path, auth) end def publish(repo, tar, auth, progress \\ fn _ -> nil end, replace \\ false) def publish(repo, tar, auth, progress, replace?) do Hex.API.check_write_api() path = "publish?replace=#{replace?}" opts = [progress: progress] ++ auth API.tar_post_request(repo, path, tar, opts) end def delete(repo, name, version, auth) do Hex.API.check_write_api() path = "packages/#{URI.encode(name)}/releases/#{URI.encode(version)}" API.request(:delete, repo, path, auth) end def retire(repo, name, version, body, auth) do Hex.API.check_write_api() path = "packages/#{URI.encode(name)}/releases/#{URI.encode(version)}/retire" API.erlang_post_request(repo, path, body, auth) end def unretire(repo, name, version, auth) do Hex.API.check_write_api() path = "packages/#{URI.encode(name)}/releases/#{URI.encode(version)}/retire" API.request(:delete, repo, path, auth) end end hex-2.0.6/lib/hex/api/release_docs.ex000066400000000000000000000013111437023760000173720ustar00rootroot00000000000000defmodule Hex.API.ReleaseDocs do @moduledoc false alias Hex.API def get(repo, name, version) do path = "packages/#{URI.encode(name)}/releases/#{URI.encode(version)}/docs" API.request(:get, repo, path) end def publish(repo, name, version, tar, auth, progress \\ fn _ -> nil end) do Hex.API.check_write_api() path = "packages/#{URI.encode(name)}/releases/#{URI.encode(version)}/docs" opts = [progress: progress] ++ auth API.tar_post_request(repo, path, tar, opts) end def delete(repo, name, version, auth) do Hex.API.check_write_api() path = "packages/#{URI.encode(name)}/releases/#{URI.encode(version)}/docs" API.request(:delete, repo, path, auth) end end hex-2.0.6/lib/hex/api/short_url.ex000066400000000000000000000004211437023760000167640ustar00rootroot00000000000000defmodule Hex.API.ShortURL do @moduledoc false alias Hex.API def create(url) do case API.erlang_post_request(nil, "short_url", %{url: url}) do {:ok, {201, %{"url" => short_url}, _resp_headers}} -> {:ok, short_url} _error -> :error end end end hex-2.0.6/lib/hex/api/user.ex000066400000000000000000000010401437023760000157170ustar00rootroot00000000000000defmodule Hex.API.User do @moduledoc false alias Hex.API def me(auth) do API.request(:get, nil, "users/me", auth) end def get(username) do API.request(:get, nil, "users/#{URI.encode(username)}") end def new(username, email, password) do Hex.API.check_write_api() API.erlang_post_request(nil, "users", %{username: username, email: email, password: password}) end def password_reset(name) do Hex.API.check_write_api() API.erlang_post_request(nil, "users/#{URI.encode(name)}/reset", %{}) end end hex-2.0.6/lib/hex/application.ex000066400000000000000000000030741437023760000165040ustar00rootroot00000000000000defmodule Hex.Application do @moduledoc false use Application def start(_, _) do dev_setup() Mix.SCM.append(Hex.SCM) Mix.RemoteConverger.register(Hex.RemoteConverger) warn_ssl() start_httpc() opts = [strategy: :one_for_one, name: Hex.Supervisor] Supervisor.start_link(children(), opts) end if Mix.env() in [:dev, :test] do defp dev_setup do :erlang.system_flag(:backtrace_depth, 20) end else defp dev_setup, do: :ok end defp warn_ssl() do case Application.load(:ssl) do :ok -> if :application.get_key(:ssl, :vsn) == {:ok, ~c"10.2"} do Hex.Shell.warn(""" You are using an OTP release with the application ssl-10.2 which has a vulnerability \ making it susceptible to man-in-the-middle attacks. You are strongly recommended to \ upgrade to newer version, ssl-10.2.1+ or OTP-23.2.2+. """) end {:error, _} -> :ok end end defp start_httpc() do :inets.start(:httpc, profile: :hex) opts = [ max_sessions: 8, max_keep_alive_length: 4, keep_alive_timeout: 120_000 ] :httpc.set_options(opts, :hex) end if Mix.env() == :test do defp children do [ Hex.Netrc.Cache, Hex.State, Hex.Server, {Hex.Parallel, [:hex_fetcher]} ] end else defp children do [ Hex.Netrc.Cache, Hex.State, Hex.Server, {Hex.Parallel, [:hex_fetcher]}, Hex.Registry.Server, Hex.UpdateChecker ] end end end hex-2.0.6/lib/hex/config.ex000066400000000000000000000052051437023760000154440ustar00rootroot00000000000000defmodule Hex.Config do @moduledoc false def read() do case File.read(config_path()) do {:ok, binary} -> case decode_term(binary) do {:ok, term} -> term {:error, _} -> config = decode_elixir(binary) write(config) config end {:error, _} -> [] end end def update(config) do read() |> Keyword.merge(config) |> write() end def remove(keys) do read() |> Keyword.drop(keys) |> write() end def write(config) do config = Enum.reject(config, fn {_key, value} -> is_nil(value) end) string = encode_term(config) path = config_path() File.mkdir_p!(Path.dirname(path)) File.write!(path, string) config end defp config_path() do Path.join(hex_home(), "hex.config") end defp hex_home() do state_pid = Process.whereis(Hex.State) if state_pid && state_pid != self() do Hex.State.fetch!(:config_home) else {_, config_home} = find_config_home(:user_config) config_home end end def find_config_home(setting) do cond do dir = System.get_env("HEX_HOME") -> {{:env, "HEX_HOME"}, dir} System.get_env("MIX_XDG") in ["1", "true"] -> user_setting_dir!(setting) true -> {:ok, Path.expand("~/.hex")} end end defp user_setting_dir!(setting) do {{:env, "MIX_XDG"}, :filename.basedir(setting, "hex", %{os: :linux})} rescue _ -> Mix.raise("MIX_XDG is only available in OTP 19+") end defp encode_term(list) do list |> Enum.map(&[:io_lib.print(&1) | ".\n"]) |> IO.iodata_to_binary() end defp decode_term(string) do {:ok, pid} = StringIO.open(string) try do consult(pid, [], string) after StringIO.close(pid) end end defp consult(pid, acc, string) when is_pid(pid) do case :io.read(pid, ~c"") do {:ok, term} -> consult(pid, [term | acc], string) {:error, reason} -> {:error, reason} :eof -> {:ok, Enum.reverse(acc)} end end defp decode_elixir(string) do {term, _binding} = Code.eval_string(string) term end def read_repos(config) do hexpm = Hex.Repo.default_hexpm_repo() (config[:"$repos"] || %{}) |> Hex.Repo.merge_hexpm(hexpm) |> Hex.Repo.update_organizations() end def update_repos(repos) do config_repos = repos |> Hex.Repo.clean_organizations() |> Hex.Repo.clean_hexpm() state_repos = repos |> Hex.Repo.merge_hexpm() |> Hex.Repo.update_organizations() Hex.Config.update([{:"$repos", config_repos}]) Hex.State.put(:repos, state_repos) end end hex-2.0.6/lib/hex/crypto.ex000066400000000000000000000040541437023760000155200ustar00rootroot00000000000000defmodule Hex.Crypto do @moduledoc false alias Hex.Crypto.Encryption def encrypt(plain_text, password, tag \\ "") do # TODO: Change :enc to "A256GCM" once support for OTP 17 is dropped. protected = %{ alg: "PBES2-HS512", enc: "A256CBC-HS512", p2c: Hex.State.fetch!(:pbkdf2_iters), p2s: :crypto.strong_rand_bytes(16) } Encryption.encrypt({tag, plain_text}, protected, password: password) end def decrypt(cipher_text, password, tag \\ "") do Encryption.decrypt({tag, cipher_text}, password: password) end def base64url_encode(binary) do try do Base.url_encode64(binary, padding: false) catch _, _ -> binary |> Base.encode64() |> urlsafe_encode64(<<>>) end end def base64url_decode(binary) do try do Base.url_decode64(binary, padding: false) catch _, _ -> try do binary = urlsafe_decode64(binary, <<>>) binary = case rem(byte_size(binary), 4) do 2 -> binary <> "==" 3 -> binary <> "=" _ -> binary end Base.decode64(binary) catch _, _ -> :error end end end defp urlsafe_encode64(<>, acc) do urlsafe_encode64(rest, <>) end defp urlsafe_encode64(<>, acc) do urlsafe_encode64(rest, <>) end defp urlsafe_encode64(<>, acc) do urlsafe_encode64(rest, acc) end defp urlsafe_encode64(<>, acc) do urlsafe_encode64(rest, <>) end defp urlsafe_encode64(<<>>, acc) do acc end defp urlsafe_decode64(<>, acc) do urlsafe_decode64(rest, <>) end defp urlsafe_decode64(<>, acc) do urlsafe_decode64(rest, <>) end defp urlsafe_decode64(<>, acc) do urlsafe_decode64(rest, <>) end defp urlsafe_decode64(<<>>, acc) do acc end end hex-2.0.6/lib/hex/crypto/000077500000000000000000000000001437023760000151575ustar00rootroot00000000000000hex-2.0.6/lib/hex/crypto/aes_cbc_hmac_sha2.ex000066400000000000000000000135371437023760000210120ustar00rootroot00000000000000defmodule Hex.Crypto.AES_CBC_HMAC_SHA2 do @moduledoc false # Content Encryption with AES_CBC_HMAC_SHA2. # See: https://tools.ietf.org/html/rfc7518#section-5.2.6 alias Hex.Crypto.ContentEncryptor @behaviour ContentEncryptor @spec content_encrypt({binary, binary}, <<_::32>> | <<_::48>> | <<_::64>>, <<_::16>>) :: {binary, <<_::16>> | <<_::24>> | <<_::32>>} def content_encrypt({aad, plain_text}, key, iv) when is_binary(aad) and is_binary(plain_text) and bit_size(key) in [256, 384, 512] and bit_size(iv) === 128 do mac_size = div(byte_size(key), 2) enc_size = mac_size tag_size = mac_size <> = key cipher_text = aes_cbc_encrypt(enc_key, iv, pkcs7_pad(plain_text)) aad_length = <> mac_data = aad <> iv <> cipher_text <> aad_length <> = hmac_sha2(mac_key, mac_data) {cipher_text, cipher_tag} end @spec content_decrypt( {binary, binary, <<_::16>> | <<_::24>> | <<_::32>>}, <<_::32>> | <<_::48>> | <<_::64>>, <<_::16>> ) :: {:ok, binary} | :error def content_decrypt({aad, cipher_text, cipher_tag}, key, iv) when is_binary(aad) and is_binary(cipher_text) and bit_size(cipher_tag) in [128, 192, 256] and bit_size(key) in [256, 384, 512] and bit_size(iv) === 128 do mac_size = div(byte_size(key), 2) enc_size = mac_size tag_size = mac_size <> = key aad_length = <> mac_data = aad <> iv <> cipher_text <> aad_length case hmac_sha2(mac_key, mac_data) do <<^cipher_tag::binary-size(tag_size), _::binary>> -> case aes_cbc_decrypt(enc_key, iv, cipher_text) do plain_text when is_binary(plain_text) -> pkcs7_unpad(plain_text) _ -> :error end _ -> :error end end def init(%{enc: enc}, _opts) do {:ok, %{key_length: encoding_to_key_length(enc)}} end def encrypt(%{key_length: key_length}, key, iv, {aad, plain_text}) when byte_size(key) == key_length do content_encrypt({aad, plain_text}, key, iv) end def decrypt(%{key_length: key_length}, key, iv, {aad, cipher_text, cipher_tag}) when byte_size(key) == key_length do content_decrypt({aad, cipher_text, cipher_tag}, key, iv) end def generate_key(%{key_length: key_length}) do :crypto.strong_rand_bytes(key_length) end def generate_iv(_params) do :crypto.strong_rand_bytes(16) end def key_length(%{key_length: key_length}) do key_length end # Support new and old style AES-CBC calls. defp aes_cbc_encrypt(key, iv, plain_text) do Hex.Stdlib.crypto_one_time_encrypt(:aes_cbc, key, iv, plain_text) rescue FunctionClauseError -> aes_cbc_encrypt_fallback(key, iv, plain_text) catch _, _ -> aes_cbc_encrypt_fallback(key, iv, plain_text) end defp aes_cbc_encrypt_fallback(key, iv, plain_text) do key |> bit_size() |> bit_size_to_cipher() |> Hex.Stdlib.crypto_one_time_encrypt(key, iv, plain_text) end # Support new and old style AES-CBC calls. defp aes_cbc_decrypt(key, iv, cipher_text) do Hex.Stdlib.crypto_one_time_decrypt(:aes_cbc, key, iv, cipher_text) rescue FunctionClauseError -> aes_cbc_decrypt_fallback(key, iv, cipher_text) catch _, _ -> aes_cbc_decrypt_fallback(key, iv, cipher_text) end defp aes_cbc_decrypt_fallback(key, iv, cipher_text) do key |> bit_size() |> bit_size_to_cipher() |> Hex.Stdlib.crypto_one_time_decrypt(key, iv, cipher_text) end defp hmac_sha2(mac_key, mac_data) when bit_size(mac_key) === 128 do Hex.Stdlib.crypto_hmac(:sha256, mac_key, mac_data) end defp hmac_sha2(mac_key, mac_data) when bit_size(mac_key) === 192 do Hex.Stdlib.crypto_hmac(:sha384, mac_key, mac_data) end defp hmac_sha2(mac_key, mac_data) when bit_size(mac_key) === 256 do Hex.Stdlib.crypto_hmac(:sha512, mac_key, mac_data) end # Pads a message using the PKCS #7 cryptographic message syntax. # # See: https://tools.ietf.org/html/rfc2315 # See: `pkcs7_unpad/1` defp pkcs7_pad(message) do bytes_remaining = rem(byte_size(message), 16) padding_size = 16 - bytes_remaining message <> :binary.copy(<>, padding_size) end # Unpads a message using the PKCS #7 cryptographic message syntax. # # See: https://tools.ietf.org/html/rfc2315 # See: `pkcs7_pad/1` defp pkcs7_unpad(<<>>) do :error end defp pkcs7_unpad(message) do padding_size = :binary.last(message) if padding_size <= 16 do message_size = byte_size(message) if binary_part(message, message_size, -padding_size) === :binary.copy(<>, padding_size) do {:ok, binary_part(message, 0, message_size - padding_size)} else :error end else :error end end defp encoding_to_key_length("A128CBC-HS256"), do: 32 defp encoding_to_key_length("A192CBC-HS384"), do: 48 defp encoding_to_key_length("A256CBC-HS512"), do: 64 # TODO: Remove this once we require OTP 19.0 defp bit_size_to_cipher(size) do {:ok, vsn} = :application.get_key(:crypto, :vsn) version = vsn |> List.to_string() |> String.split(".") |> Enum.map(&String.to_integer/1) if version >= [3, 7, 0] do new_bit_size_to_cipher(size) else old_bit_size_to_cipher(size) end end defp new_bit_size_to_cipher(128), do: :aes_128_cbc defp new_bit_size_to_cipher(192), do: :aes_192_cbc defp new_bit_size_to_cipher(256), do: :aes_256_cbc defp old_bit_size_to_cipher(128), do: :aes_cbc128 defp old_bit_size_to_cipher(192), do: :aes_cbc192 defp old_bit_size_to_cipher(256), do: :aes_cbc256 end hex-2.0.6/lib/hex/crypto/aes_gcm.ex000066400000000000000000000040651437023760000171200ustar00rootroot00000000000000defmodule Hex.Crypto.AES_GCM do @moduledoc false # Content Encryption with AES GCM # # See: https://tools.ietf.org/html/rfc7518#section-5.3 # See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf alias Hex.Crypto.ContentEncryptor @behaviour ContentEncryptor @spec content_encrypt({binary, binary}, <<_::16>> | <<_::24>> | <<_::32>>, <<_::12>>) :: {binary, <<_::16>>} def content_encrypt({aad, plain_text}, key, iv) when is_binary(aad) and is_binary(plain_text) and bit_size(key) in [128, 192, 256] and bit_size(iv) === 96 do Hex.Stdlib.crypto_one_time_aead_encrypt(:aes_gcm, key, iv, plain_text, aad) end @spec content_decrypt({binary, binary, <<_::16>>}, <<_::16>> | <<_::24>> | <<_::32>>, <<_::12>>) :: {:ok, binary} | :error def content_decrypt({aad, cipher_text, cipher_tag}, key, iv) when is_binary(aad) and is_binary(cipher_text) and bit_size(cipher_tag) === 128 and bit_size(key) in [128, 192, 256] and bit_size(iv) === 96 do case Hex.Stdlib.crypto_one_time_aead_decrypt(:aes_gcm, key, iv, cipher_text, aad, cipher_tag) do plain_text when is_binary(plain_text) -> {:ok, plain_text} _ -> :error end end def init(%{enc: enc}, _opts) do {:ok, %{key_length: encoding_to_key_length(enc)}} end def encrypt(%{key_length: key_length}, key, iv, {aad, plain_text}) when byte_size(key) == key_length do content_encrypt({aad, plain_text}, key, iv) end def decrypt(%{key_length: key_length}, key, iv, {aad, cipher_text, cipher_tag}) when byte_size(key) == key_length do content_decrypt({aad, cipher_text, cipher_tag}, key, iv) end def generate_key(%{key_length: key_length}) do :crypto.strong_rand_bytes(key_length) end def generate_iv(_params) do :crypto.strong_rand_bytes(12) end def key_length(%{key_length: key_length}) do key_length end defp encoding_to_key_length("A128GCM"), do: 16 defp encoding_to_key_length("A192GCM"), do: 24 defp encoding_to_key_length("A256GCM"), do: 32 end hex-2.0.6/lib/hex/crypto/content_encryptor.ex000066400000000000000000000050351437023760000212770ustar00rootroot00000000000000defmodule Hex.Crypto.ContentEncryptor do @moduledoc false alias Hex.Crypto alias __MODULE__ @type t :: %ContentEncryptor{ module: module, params: any } defstruct module: nil, params: nil @callback init(protected :: map, opts :: Keyword.t()) :: {:ok, any} | {:error, String.t()} @callback encrypt( params :: any, key :: binary, iv :: binary, {aad :: binary, plain_text :: binary} ) :: {binary, binary} @callback decrypt( params :: any, key :: binary, iv :: binary, {aad :: binary, cipher_text :: binary, cipher_tag :: binary} ) :: {:ok, binary} | :error @callback generate_key(params :: any) :: binary @callback generate_iv(params :: any) :: binary @callback key_length(params :: any) :: non_neg_integer def init(protected = %{enc: enc}, opts) do case content_encryptor_module(enc) do :error -> {:error, "Unrecognized ContentEncryptor algorithm: #{inspect(enc)}"} module -> case module.init(protected, opts) do {:ok, params} -> content_encryptor = %ContentEncryptor{module: module, params: params} {:ok, content_encryptor} content_encryptor_error -> content_encryptor_error end end end def encrypt(%ContentEncryptor{module: module, params: params}, key, iv, {aad, plain_text}) do module.encrypt(params, key, iv, {aad, plain_text}) end def decrypt( %ContentEncryptor{module: module, params: params}, key, iv, {aad, cipher_text, cipher_tag} ) do module.decrypt(params, key, iv, {aad, cipher_text, cipher_tag}) end def generate_key(%ContentEncryptor{module: module, params: params}) do module.generate_key(params) end def generate_iv(%ContentEncryptor{module: module, params: params}) do module.generate_iv(params) end def key_length(%ContentEncryptor{module: module, params: params}) do module.key_length(params) end defp content_encryptor_module("A128CBC-HS256"), do: Crypto.AES_CBC_HMAC_SHA2 defp content_encryptor_module("A192CBC-HS384"), do: Crypto.AES_CBC_HMAC_SHA2 defp content_encryptor_module("A256CBC-HS512"), do: Crypto.AES_CBC_HMAC_SHA2 defp content_encryptor_module("A128GCM"), do: Crypto.AES_GCM defp content_encryptor_module("A192GCM"), do: Crypto.AES_GCM defp content_encryptor_module("A256GCM"), do: Crypto.AES_GCM defp content_encryptor_module(_), do: :error end hex-2.0.6/lib/hex/crypto/encryption.ex000066400000000000000000000031211437023760000177040ustar00rootroot00000000000000defmodule Hex.Crypto.Encryption do @moduledoc false alias Hex.Crypto alias Hex.Crypto.ContentEncryptor alias Hex.Crypto.KeyManager def encrypt({tag, plain_text}, protected, opts) do case KeyManager.encrypt(protected, opts) do {:ok, protected, key, encrypted_key, content_encryptor} -> iv = ContentEncryptor.generate_iv(content_encryptor) protected = :erlang.term_to_binary(protected) aad = tag <> protected {cipher_text, cipher_tag} = ContentEncryptor.encrypt(content_encryptor, key, iv, {aad, plain_text}) %{ protected: protected, encrypted_key: encrypted_key, iv: iv, cipher_text: cipher_text, cipher_tag: cipher_tag } |> :erlang.term_to_binary() |> Crypto.base64url_encode() encrypt_init_error -> encrypt_init_error end end def decrypt({tag, cipher_text}, opts) do {:ok, cipher_text} = Crypto.base64url_decode(cipher_text) %{ protected: protected, encrypted_key: encrypted_key, iv: iv, cipher_text: cipher_text, cipher_tag: cipher_tag } = Hex.Utils.safe_binary_to_term!(cipher_text, [:safe]) aad = tag <> protected protected = Hex.Utils.safe_binary_to_term!(protected, [:safe]) case KeyManager.decrypt(protected, encrypted_key, opts) do {:ok, key, content_encryptor} -> ContentEncryptor.decrypt(content_encryptor, key, iv, {aad, cipher_text, cipher_tag}) decrypt_init_error -> decrypt_init_error end rescue ArgumentError -> :error end end hex-2.0.6/lib/hex/crypto/key_manager.ex000066400000000000000000000051441437023760000200030ustar00rootroot00000000000000defmodule Hex.Crypto.KeyManager do @moduledoc false alias Hex.Crypto alias Hex.Crypto.ContentEncryptor alias __MODULE__ @type t :: %KeyManager{ module: module, params: any } defstruct module: nil, params: nil @callback init(protected :: map, opts :: Keyword.t()) :: {:ok, any} | {:error, String.t()} @callback encrypt(params :: any, protected :: map, content_encryptor :: ContentEncryptor.t()) :: {:ok, map, binary, binary} | {:error, String.t()} @callback decrypt( params :: any, protected :: map, encrypted_key :: binary, content_encryptor :: ContentEncryptor.t() ) :: {:ok, binary} | {:error, String.t()} def init(%{alg: alg} = protected, opts) do case key_manager_module(alg) do {:ok, module} -> case module.init(protected, opts) do {:ok, params} -> key_manager = %KeyManager{module: module, params: params} fetch_content_encryptor(key_manager, protected, opts) key_manager_error -> key_manager_error end error -> error end end def encrypt(protected, opts) do case init(protected, opts) do {:ok, %KeyManager{module: module, params: params}, content_encryptor} -> case module.encrypt(params, protected, content_encryptor) do {:ok, protected, key, encrypted_key} -> {:ok, protected, key, encrypted_key, content_encryptor} key_manager_error -> key_manager_error end init_error -> init_error end end def decrypt(protected, encrypted_key, opts) do case init(protected, opts) do {:ok, %KeyManager{module: module, params: params}, content_encryptor} -> case module.decrypt(params, protected, encrypted_key, content_encryptor) do {:ok, key} -> {:ok, key, content_encryptor} key_manager_error -> key_manager_error end init_error -> init_error end end defp key_manager_module("PBES2-HS256"), do: {:ok, Crypto.PBES2_HMAC_SHA2} defp key_manager_module("PBES2-HS384"), do: {:ok, Crypto.PBES2_HMAC_SHA2} defp key_manager_module("PBES2-HS512"), do: {:ok, Crypto.PBES2_HMAC_SHA2} defp key_manager_module(alg), do: {:error, "Unrecognized KeyManager algorithm: #{inspect(alg)}"} defp fetch_content_encryptor(key_manager, protected, opts) do case ContentEncryptor.init(protected, opts) do {:ok, content_encryptor} -> {:ok, key_manager, content_encryptor} error -> error end end end hex-2.0.6/lib/hex/crypto/pbes2_hmac_sha2.ex000066400000000000000000000064111437023760000204370ustar00rootroot00000000000000defmodule Hex.Crypto.PBES2_HMAC_SHA2 do @moduledoc false # Direct Key Derivation with PBES2 and HMAC-SHA-2. # # See: https://tools.ietf.org/html/rfc7518#section-4.8 # See: https://tools.ietf.org/html/rfc2898#section-6.2 alias Hex.Crypto.ContentEncryptor alias Hex.Crypto.KeyManager alias Hex.Crypto.PKCS5 @behaviour KeyManager @spec derive_key(String.t(), binary, pos_integer, non_neg_integer, :sha256 | :sha384 | :sha512) :: binary def derive_key(password, salt_input, iterations, derived_key_length, hash) when is_binary(password) and is_binary(salt_input) and is_integer(iterations) and iterations >= 1 and is_integer(derived_key_length) and derived_key_length >= 0 and hash in [:sha256, :sha384, :sha512] do salt = wrap_salt_input(salt_input, hash) derived_key = PKCS5.pbkdf2(password, salt, iterations, derived_key_length, hash) derived_key end def init(%{alg: alg} = protected, opts) do hash = algorithm_to_hash(alg) case fetch_password(opts) do {:ok, password} -> case fetch_p2c(protected) do {:ok, _iteration} -> protected |> fetch_p2s() |> handle_p2s(hash, password) error -> error end error -> error end end def encrypt( %{password: password, hash: hash}, %{p2c: iterations, p2s: salt} = protected, content_encryptor ) do derived_key_length = ContentEncryptor.key_length(content_encryptor) key = derive_key(password, salt, iterations, derived_key_length, hash) encrypted_key = "" {:ok, protected, key, encrypted_key} end def decrypt( %{password: password, hash: hash}, %{p2c: iterations, p2s: salt}, "", content_encryptor ) do derived_key_length = ContentEncryptor.key_length(content_encryptor) key = derive_key(password, salt, iterations, derived_key_length, hash) {:ok, key} end def decrypt(_, _, _, _), do: :error defp handle_p2s({:ok, _salt}, hash, passwd), do: {:ok, %{hash: hash, password: passwd}} defp handle_p2s(error, _, _), do: error defp fetch_password(opts) do case Keyword.fetch(opts, :password) do {:ok, password} when is_binary(password) -> {:ok, password} _ -> {:error, "option :password (PBKDF2 password) must be a binary"} end end defp fetch_p2c(opts) do case Map.fetch(opts, :p2c) do {:ok, p2c} when is_integer(p2c) and p2c >= 1 -> {:ok, p2c} _ -> {:error, "protected :p2c (PBKDF2 iterations) must be a positive integer"} end end defp fetch_p2s(opts) do case Map.fetch(opts, :p2s) do {:ok, p2s} when is_binary(p2s) -> {:ok, p2s} _ -> {:error, "protected :p2s (PBKDF2 salt) must be a binary"} end end defp wrap_salt_input(salt_input, :sha256) do <<"PBES2-HS256", 0, salt_input::binary>> end defp wrap_salt_input(salt_input, :sha384) do <<"PBES2-HS384", 0, salt_input::binary>> end defp wrap_salt_input(salt_input, :sha512) do <<"PBES2-HS512", 0, salt_input::binary>> end defp algorithm_to_hash("PBES2-HS256"), do: :sha256 defp algorithm_to_hash("PBES2-HS384"), do: :sha384 defp algorithm_to_hash("PBES2-HS512"), do: :sha512 end hex-2.0.6/lib/hex/crypto/pkcs5.ex000066400000000000000000000041761437023760000165520ustar00rootroot00000000000000defmodule Hex.Crypto.PKCS5 do @moduledoc false # PKCS #5: Password-Based Cryptography Specification Version 2.0 # See: https://tools.ietf.org/html/rfc2898 def pbkdf2(password, salt, iterations, derived_key_length, hash) when is_binary(password) and is_binary(salt) and is_integer(iterations) and iterations >= 1 and is_integer(derived_key_length) and derived_key_length >= 0 do hash_length = byte_size(Hex.Stdlib.crypto_hmac(hash, <<>>, <<>>)) if derived_key_length > 0xFFFFFFFF * hash_length do raise ArgumentError, "derived key too long" else rounds = ceildiv(derived_key_length, hash_length) <> = pbkdf2_iterate(password, salt, iterations, hash, 1, rounds, "") derived_key end end defp ceildiv(a, b) do div(a, b) + if rem(a, b) === 0, do: 0, else: 1 end defp pbkdf2_iterate(password, salt, iterations, hash, rounds, rounds, derived_keying_material) do derived_keying_material <> pbkdf2_exor(password, salt, iterations, hash, 1, rounds, <<>>, <<>>) end defp pbkdf2_iterate(password, salt, iterations, hash, counter, rounds, derived_keying_material) do derived_keying_material = derived_keying_material <> pbkdf2_exor(password, salt, iterations, hash, 1, counter, <<>>, <<>>) pbkdf2_iterate(password, salt, iterations, hash, counter + 1, rounds, derived_keying_material) end defp pbkdf2_exor(_password, _salt, iterations, _hash, i, _counter, _prev, curr) when i > iterations do curr end defp pbkdf2_exor(password, salt, iterations, hash, i = 1, counter, <<>>, <<>>) do next = Hex.Stdlib.crypto_hmac( hash, password, <> ) pbkdf2_exor(password, salt, iterations, hash, i + 1, counter, next, next) end defp pbkdf2_exor(password, salt, iterations, hash, i, counter, prev, curr) do next = Hex.Stdlib.crypto_hmac(hash, password, prev) curr = :crypto.exor(next, curr) pbkdf2_exor(password, salt, iterations, hash, i + 1, counter, next, curr) end end hex-2.0.6/lib/hex/crypto/public_key.ex000066400000000000000000000010631437023760000176430ustar00rootroot00000000000000defmodule Hex.Crypto.PublicKey do @moduledoc false def decode!(id, key) do [rsa_public_key] = :public_key.pem_decode(key) :public_key.pem_entry_decode(rsa_public_key) rescue _ -> Mix.raise(""" Could not decode public key for #{id}. The public key contents are shown below. #{key} Public keys must be valid and be in the PEM format. """) end def verify(binary, hash, signature, keys, id) do Enum.any?(keys, fn key -> :public_key.verify(binary, hash, signature, decode!(id, key)) end) end end hex-2.0.6/lib/hex/dev.ex000066400000000000000000000042771437023760000147650ustar00rootroot00000000000000if Mix.env() == :dev do defmodule Hex.Dev do @moduledoc false @ets_name __MODULE__ @registry_filename "cache.ets" @repo "hexpm" @ets_version 3 def extract_registry(packages, new_path) do {:ok, original_ets} = :ets.file2tab(String.to_charlist(ets_path())) new_ets = :ets.new(@ets_name, []) try do :ets.insert(new_ets, {:version, @ets_version}) copy(original_ets, new_ets, :last_update) Enum.each(packages, fn package -> copy_package(original_ets, new_ets, package) end) :ok = :ets.tab2file(new_ets, String.to_charlist(new_path)) after :ets.delete(original_ets) :ets.delete(new_ets) end end defp copy_package(original_ets, new_ets, package) do unless :ets.member(new_ets, {:versions, @repo, package}) do copy(original_ets, new_ets, {:versions, @repo, package}) copy(original_ets, new_ets, {:registry_etag, @repo, package}) copy(original_ets, new_ets, {:timestamp, @repo, package}) case :ets.lookup(original_ets, {:versions, @repo, package}) do [{_, versions}] -> IO.puts("COPYING #{package}") Enum.each(versions, fn version -> copy(original_ets, new_ets, {:deps, @repo, package, version}) copy(original_ets, new_ets, {:inner_checksum, @repo, package, version}) copy(original_ets, new_ets, {:outer_checksum, @repo, package, version}) copy(original_ets, new_ets, {:retired, @repo, package, version}) copy(original_ets, new_ets, {:timestamp, @repo, package, version}) [{_, dep_tuples}] = :ets.lookup(original_ets, {:deps, @repo, package, version}) Enum.each(dep_tuples, fn {@repo, dependency, _app, _requirement, _optional} -> copy_package(original_ets, new_ets, dependency) end) end) [] -> :ok end end end defp copy(original_ets, new_ets, key) do tuples = :ets.lookup(original_ets, key) :ets.insert(new_ets, tuples) end defp ets_path() do Path.join(Hex.State.fetch!(:cache_home), @registry_filename) end end end hex-2.0.6/lib/hex/http.ex000066400000000000000000000202751437023760000151620ustar00rootroot00000000000000defmodule Hex.HTTP do @moduledoc false @request_timeout 15_000 @request_redirects 3 @request_retries 2 def request(method, url, headers, body, opts \\ []) do headers = headers |> build_headers() |> add_basic_auth_via_netrc(url) timeout = opts[:timeout] || Hex.State.fetch!(:http_timeout, fn val -> if is_integer(val), do: val * 1000 end) || @request_timeout http_opts = build_http_opts(url, timeout) opts = [body_format: :binary] request = build_request(url, headers, body) profile = Hex.State.fetch!(:httpc_profile) retry(method, request, http_opts, @request_retries, profile, fn request, http_opts -> redirect(request, http_opts, @request_redirects, fn request, http_opts -> timeout(request, http_opts, timeout, fn request, http_opts -> :httpc.request(method, request, http_opts, opts, profile) |> handle_response() end) end) end) end defp fallback(:inet), do: :inet6 defp fallback(:inet6), do: :inet defp build_headers(headers) do default_headers = %{~c"user-agent" => user_agent()} headers = Map.new(headers) Map.merge(default_headers, headers) end defp build_http_opts(url, timeout) do [ relaxed: true, timeout: timeout, ssl: Hex.HTTP.SSL.ssl_opts(url), autoredirect: false ] ++ proxy_config(url) end defp build_request(url, headers, body) do url = String.to_charlist(url) headers = Map.to_list(headers) case body do {content_type, body} -> {url, headers, content_type, body} nil -> {url, headers} end end defp retry(:get, request, http_opts, times, profile, fun) do result = case fun.(request, http_opts) do {:http_error, _, _} = error -> {:retry, error} {:error, :socket_closed_remotely} = error -> {:retry, error} {:error, {:failed_connect, [{:to_address, to_addr}, {inet, inet_l, reason}]}} when inet in [:inet, :inet6] and reason in [:ehostunreach, :enetunreach, :eprotonosupport, :nxdomain] -> :httpc.set_options([ipfamily: fallback(inet)], profile) {:retry, {:error, {:failed_connect, [{:to_address, to_addr}, {inet, inet_l, reason}]}}} other -> {:noretry, other} end case result do {:retry, _} when times > 0 -> retry(:get, request, http_opts, times - 1, profile, fun) {_other, result} -> result end end defp retry(_method, request, http_opts, _times, _profile, fun), do: fun.(request, http_opts) defp redirect(request, http_opts, times, fun) do case fun.(request, http_opts) do {:ok, response} -> case handle_redirect(response) do {:ok, location} when times > 0 -> ssl_opts = Hex.HTTP.SSL.ssl_opts(to_string(location)) http_opts = Keyword.put(http_opts, :ssl, ssl_opts) request |> update_request(location) |> redirect(http_opts, times - 0, fun) {:ok, _location} -> Mix.raise("Too many redirects") :error -> {:ok, response} end {:error, reason} -> {:error, reason} end end defp handle_redirect({code, _body, headers}) when code in [301, 302, 303, 307, 308] do headers = Map.new(headers) if location = headers[~c"location"] do {:ok, location} else :error end end defp handle_redirect(_) do :error end defp update_request({_url, headers, content_type, body}, new_url) do {new_url, headers, content_type, body} end defp update_request({_url, headers}, new_url) do {new_url, headers} end defp timeout(request, http_opts, timeout, fun) do Task.async(fn -> fun.(request, http_opts) end) |> task_await(:timeout, timeout) end defp task_await(%Task{ref: ref, pid: pid} = task, reason, timeout) do receive do {^ref, result} -> Process.demonitor(ref, [:flush]) result {:DOWN, ^ref, _, _, _reason} -> {:error, :timeout} after timeout -> Process.unlink(pid) Process.exit(pid, reason) task_await(task, :kill, timeout) end end defp handle_response({:ok, {{_version, code, _reason}, headers, body}}) do headers = Map.new(headers) handle_hex_message(headers[~c"x-hex-message"]) {:ok, {code, unzip(body, headers), headers}} end defp handle_response({:error, term}) do {:error, term} end defp unzip(body, headers) do content_encoding = List.to_string(headers[~c"content-encoding"] || ~c"") if String.contains?(content_encoding, "gzip") do :zlib.gunzip(body) else body end end def proxy_config(url) do {http_proxy, https_proxy} = proxy_setup() proxy_auth(URI.parse(url), http_proxy, https_proxy) end defp proxy_setup do no_proxy = no_proxy() http_proxy = (proxy = Hex.State.fetch!(:http_proxy)) && proxy(:http, proxy, no_proxy) https_proxy = (proxy = Hex.State.fetch!(:https_proxy)) && proxy(:https, proxy, no_proxy) {http_proxy, https_proxy} end defp proxy(scheme, proxy, no_proxy) do uri = URI.parse(proxy) if uri.host && uri.port do host = String.to_charlist(uri.host) :httpc.set_options([{proxy_scheme(scheme), {{host, uri.port}, no_proxy}}], :hex) end uri end defp proxy_scheme(scheme) do case scheme do :http -> :proxy :https -> :https_proxy end end defp proxy_auth(%URI{scheme: "http"}, http_proxy, _https_proxy) do proxy_auth(http_proxy) end defp proxy_auth(%URI{scheme: "https"}, _http_proxy, https_proxy) do proxy_auth(https_proxy) end defp proxy_auth(nil) do [] end defp proxy_auth(%URI{userinfo: nil}) do [] end defp proxy_auth(%URI{userinfo: auth}) do destructure [user, pass], String.split(auth, ":", parts: 2) user = String.to_charlist(user) pass = String.to_charlist(pass || "") [proxy_auth: {user, pass}] end defp no_proxy() do (Hex.State.fetch!(:no_proxy) || "") |> String.split(",", trim: true) |> Enum.map(&String.trim/1) |> Enum.map(&normalize_no_proxy_domain_desc/1) |> Enum.map(&String.to_charlist/1) end defp normalize_no_proxy_domain_desc(<<".", rest::binary>>) do "*." <> rest end defp normalize_no_proxy_domain_desc(host) do host end defp user_agent do ~c"Hex/#{Hex.version()} (Elixir/#{System.version()}) (OTP/#{Hex.Utils.otp_version()})" end def handle_hex_message(nil) do :ok end def handle_hex_message(header) do {message, level} = :binary.list_to_bin(header) |> parse_hex_message case level do "warn" -> Hex.Shell.info("API warning: " <> message) "fatal" -> Hex.Shell.error("API error: " <> message) _ -> :ok end end @space [?\s, ?\t] defp parse_hex_message(message) do {message, rest} = skip_ws(message) |> quoted level = skip_ws(rest) |> opt_level {message, level} end defp skip_ws(<>) when char in @space, do: skip_ws(rest) defp skip_ws(rest), do: rest defp skip_trail_ws(<>, str, ws) when char in @space do skip_trail_ws(rest, str, <>) end defp skip_trail_ws(<>, str, ws) do skip_trail_ws(rest, <>, "") end defp skip_trail_ws("", str, _ws) do str end defp quoted("\"" <> rest), do: do_quoted(rest, "") defp do_quoted("\"" <> rest, acc), do: {acc, rest} defp do_quoted(<>, acc), do: do_quoted(rest, <>) defp opt_level(";" <> rest), do: do_level(rest) defp opt_level(_), do: nil defp do_level(rest) do "level" <> rest = skip_ws(rest) "=" <> rest = skip_ws(rest) rest |> skip_ws() |> skip_trail_ws("", "") end defp add_basic_auth_via_netrc(%{~c"authorization" => _} = headers, _url), do: headers defp add_basic_auth_via_netrc(%{} = headers, url) do url = URI.parse(url) case Hex.Netrc.lookup(url.host) do {:ok, %{username: username, password: password}} -> base64 = :base64.encode_to_string("#{username}:#{password}") Map.put(headers, ~c"authorization", ~c"Basic #{base64}") _ -> headers end end end hex-2.0.6/lib/hex/http/000077500000000000000000000000001437023760000146165ustar00rootroot00000000000000hex-2.0.6/lib/hex/http/ca-bundle.crt000066400000000000000000006450041437023760000171730ustar00rootroot00000000000000## ## Bundle of CA Root Certificates ## ## Certificate data from Mozilla as of: Wed Apr 18 08:49:00 2018 GMT ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates ## file (certdata.txt). This file can be found in the mozilla source tree: ## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt ## ## It contains the certificates in PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with ## an Apache+mod_ssl webserver for SSL client authentication. ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.27. ## SHA256: 704f02707ec6b4c4a7597a8c6039b020def11e64f3ef0605a9c3543d48038a57 ## GlobalSign Root CA ================== -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- GlobalSign Root CA - R2 ======================= -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp 9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu 01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj 055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- Entrust.net Premium 2048 Secure Server CA ========================================= -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= -----END CERTIFICATE----- Baltimore CyberTrust Root ========================= -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- AddTrust External Root ====================== -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 +iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy 2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- Entrust Root Certification Authority ==================================== -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- GeoTrust Global CA ================== -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet 8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm Mw== -----END CERTIFICATE----- GeoTrust Universal CA ===================== -----BEGIN CERTIFICATE----- MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs 7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d 8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI P/rmMuGNG2+k5o7Y+SlIis5z/iw= -----END CERTIFICATE----- GeoTrust Universal CA 2 ======================= -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP 20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG 8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 +/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ 4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- Visa eCommerce Root =================== -----BEGIN CERTIFICATE----- MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI /k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt 398znM/jra6O1I7mT1GvFpLgXPYHDw== -----END CERTIFICATE----- Comodo AAA Services root ======================== -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm 7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z 8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- QuoVadis Root CA ================ -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi 5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi 5nrQNiOKSnQ2+Q== -----END CERTIFICATE----- QuoVadis Root CA 2 ================== -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt 66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK +JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II 4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- QuoVadis Root CA 3 ================== -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp 8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- Security Communication Root CA ============================== -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw 8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX 5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g 0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ 6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi FL39vmwLAw== -----END CERTIFICATE----- Sonera Class 2 Root CA ====================== -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 /Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt 0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH llpwrN9M -----END CERTIFICATE----- XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc /Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz 8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- Go Daddy Class 2 CA =================== -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b vZ8= -----END CERTIFICATE----- Starfield Class 2 CA ==================== -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- Taiwan GRCA =========== -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O 1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk 7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy +fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS -----END CERTIFICATE----- DigiCert Assured ID Root CA =========================== -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO 9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW /lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF 66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i 8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- DigiCert Global Root CA ======================= -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H 4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y 7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm 8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- DigiCert High Assurance EV Root CA ================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K -----END CERTIFICATE----- Certplus Class 2 Primary CA =========================== -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR 5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ 7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW //1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- DST Root CA X3 ============== -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- SwissSign Gold CA - G2 ====================== -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR 7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm 5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr 44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- SwissSign Silver CA - G2 ======================== -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm +/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH 6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P 4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L 3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx /uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- GeoTrust Primary Certification Authority ======================================== -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG 1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- thawte Primary Root CA ====================== -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ 1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== -----END CERTIFICATE----- VeriSign Class 3 Public Primary Certification Authority - G5 ============================================================ -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- SecureTrust CA ============== -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b 01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- Secure Global CA ================ -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g 8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi 0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- COMODO Certification Authority ============================== -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH +7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV 4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA 1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN +8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== -----END CERTIFICATE----- Network Solutions Certificate Authority ======================================= -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc /Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q 4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- COMODO ECC Certification Authority ================================== -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X 4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- OISTE WISeKey Global Root GA CA =============================== -----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ /yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 +vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= -----END CERTIFICATE----- Certigna ======== -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY 1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- Deutsche Telekom Root CA 2 ========================== -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- Cybertrust Global Root ====================== -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW 0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin 89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT 8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi 5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW WL1WMRJOEcgh4LMRkWXbtKaIOM5V -----END CERTIFICATE----- ePKI Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX 12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- certSIGN ROOT CA ================ -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD 0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD -----END CERTIFICATE----- GeoTrust Primary Certification Authority - G3 ============================================= -----BEGIN CERTIFICATE----- MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr 2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt -----END CERTIFICATE----- thawte Primary Root CA - G2 =========================== -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- thawte Primary Root CA - G3 =========================== -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC +BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY 7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC 8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- GeoTrust Primary Certification Authority - G2 ============================================= -----BEGIN CERTIFICATE----- MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 npaqBA+K -----END CERTIFICATE----- VeriSign Universal Root Certification Authority =============================================== -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj 1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 mJO37M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- VeriSign Class 3 Public Primary Certification Authority - G4 ============================================================ -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- NetLock Arany (Class Gold) Főtanúsítvány ======================================== -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu 0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw /HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- Staat der Nederlanden Root CA - G2 ================================== -----BEGIN CERTIFICATE----- MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ 5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz +51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm 66+KAQ== -----END CERTIFICATE----- Hongkong Post Root CA 1 ======================= -----BEGIN CERTIFICATE----- MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== -----END CERTIFICATE----- SecureSign RootCA11 =================== -----BEGIN CERTIFICATE----- MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= -----END CERTIFICATE----- Microsec e-Szigno Root CA 2009 ============================== -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG 0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm 1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi LXpUq3DDfSJlgnCW -----END CERTIFICATE----- GlobalSign Root CA - R3 ======================= -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ 0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- Autoridad de Certificacion Firmaprofesional CIF A62634068 ========================================================= -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY 7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx 51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi 6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- Izenpe.com ========== -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ 03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU +zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK 0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ 0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- Chambers of Commerce Root - 2008 ================================ -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ 0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH 3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF 9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ -----END CERTIFICATE----- Global Chambersign Root - 2008 ============================== -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB /gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp 1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG /5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg 9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B -----END CERTIFICATE----- Go Daddy Root Certificate Authority - G2 ======================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq 9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD +qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r 5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 -----END CERTIFICATE----- Starfield Root Certificate Authority - G2 ========================================= -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx 4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- Starfield Services Root Certificate Authority - G2 ================================================== -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 -----END CERTIFICATE----- AffirmTrust Commercial ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv 0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- AffirmTrust Networking ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 /PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 /ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- AffirmTrust Premium =================== -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV 5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs +7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 /bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo +Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC 6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK +4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== -----END CERTIFICATE----- AffirmTrust Premium ECC ======================= -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X 57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM eQ== -----END CERTIFICATE----- Certum Trusted Network CA ========================= -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- TWCA Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP 4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG 9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- Security Communication RootCA2 ============================== -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ +T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R 3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk 3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- EC-ACC ====== -----BEGIN CERTIFICATE----- MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw 0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D 5EI= -----END CERTIFICATE----- Hellenic Academic and Research Institutions RootCA 2011 ======================================================= -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI 1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa 71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u 8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH 3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD /md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N 7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- Actalis Authentication Root CA ============================== -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC 4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo 2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- Trustis FPS Root CA =================== -----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P 8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl iB6XzCGcKQENZetX2fNXlrtIzYE= -----END CERTIFICATE----- Buypass Class 2 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn 9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b /+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN rJgWVqA= -----END CERTIFICATE----- Buypass Class 3 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR 5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh 7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH 2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV /afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz 6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi Cp/HuZc= -----END CERTIFICATE----- T-TeleSec GlobalRoot Class 3 ============================ -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK 9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W 0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== -----END CERTIFICATE----- EE Certification Centre Root CA =============================== -----BEGIN CERTIFICATE----- MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw 93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU 3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM dcGWxZ0= -----END CERTIFICATE----- D-TRUST Root Class 3 CA 2 2009 ============================== -----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ 4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm 2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= -----END CERTIFICATE----- D-TRUST Root Class 3 CA 2 EV 2009 ================================= -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T 7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv w9y4AyHqnxbxLFS1 -----END CERTIFICATE----- CA Disig Root R2 ================ -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa 5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV 7+ZtsH8tZ/3zbBt1RqPlShfppNcL -----END CERTIFICATE----- ACCVRAIZ1 ========= -----BEGIN CERTIFICATE----- MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ 0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR 5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J 9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd 3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p EfbRD0tVNEYqi4Y7 -----END CERTIFICATE----- TWCA Global Root CA =================== -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M 8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg /eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= -----END CERTIFICATE----- TeliaSonera Root CA v1 ====================== -----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ 6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA 3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- E-Tugra Certification Authority =============================== -----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB /wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G C7TbO6Orb1wdtn7os4I07QZcJA== -----END CERTIFICATE----- T-TeleSec GlobalRoot Class 2 ============================ -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR 3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== -----END CERTIFICATE----- Atos TrustedRoot 2011 ===================== -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr 54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G 3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed -----END CERTIFICATE----- QuoVadis Root CA 1 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV 7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX 9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP +V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh 3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV hMJKzRwuJIczYOXD -----END CERTIFICATE----- QuoVadis Root CA 2 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD 6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr O3jtZsSOeWmD3n+M -----END CERTIFICATE----- QuoVadis Root CA 3 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe 6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX 0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 PpxxVJkES/1Y+Zj0 -----END CERTIFICATE----- DigiCert Assured ID Root G2 =========================== -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH 35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv 0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- DigiCert Assured ID Root G3 =========================== -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy 1vUhZscv6pZjamVFkpUBtA== -----END CERTIFICATE----- DigiCert Global Root G2 ======================= -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO 3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu 5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- DigiCert Global Root G3 ======================= -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y 3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 VOKa5Vt8sycX -----END CERTIFICATE----- DigiCert Trusted Root G4 ======================== -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy 7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN 5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb /UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa 5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP 82Z+ -----END CERTIFICATE----- COMODO RSA Certification Authority ================================== -----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ 5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX 2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I LaZRfyHBNVOFBkpdn627G190 -----END CERTIFICATE----- USERTrust RSA Certification Authority ===================================== -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz 0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O +T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq /nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ 7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM 8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 -----END CERTIFICATE----- USERTrust ECC Certification Authority ===================================== -----BEGIN CERTIFICATE----- MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu 9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= -----END CERTIFICATE----- GlobalSign ECC Root CA - R4 =========================== -----BEGIN CERTIFICATE----- MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q= -----END CERTIFICATE----- GlobalSign ECC Root CA - R5 =========================== -----BEGIN CERTIFICATE----- MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- Staat der Nederlanden Root CA - G3 ================================== -----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5 1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp 07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE 41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1 v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA 8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b 8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq 1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk= -----END CERTIFICATE----- Staat der Nederlanden EV Root CA ================================ -----BEGIN CERTIFICATE----- MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r 0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8 Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr 08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV 0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd 74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq 5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi 5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4 WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg== -----END CERTIFICATE----- IdenTrust Commercial Root CA 1 ============================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi 1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl 3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH 6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe 2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R cGzM7vRX+Bi6hG6H -----END CERTIFICATE----- IdenTrust Public Sector Root CA 1 ================================= -----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL 4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ 3Wl9af0AVqW3rLatt8o+Ae+c -----END CERTIFICATE----- Entrust Root Certification Authority - G2 ========================================= -----BEGIN CERTIFICATE----- MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP /vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO e4pIb4tF9g== -----END CERTIFICATE----- Entrust Root Certification Authority - EC1 ========================================== -----BEGIN CERTIFICATE----- MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef 9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G -----END CERTIFICATE----- CFCA EV ROOT ============ -----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD 7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua 4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su -----END CERTIFICATE----- TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5 ==================================================== -----BEGIN CERTIFICATE----- MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVFIxDzAN BgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1Qg RWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAw ODA3MDFaFw0yMzA0MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0w SwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnE n2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRp ZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEApCUZ4WWe60ghUEoI5RHwWrom/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537 jVJp45wnEFPzpALFp/kRGml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1m ep5Fimh34khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z5UNP 9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0hO8EuPbJbKoCPrZV 4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QIDAQABo0IwQDAdBgNVHQ4EFgQUVpkH HtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI hvcNAQELBQADggEBAJ5FdnsXSDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPo BP5yCccLqh0lVX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nfpeYVhDfwwvJl lpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CFYv4HAqGEVka+lgqaE9chTLd8 B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW+qtB4Uu2NQvAmxU= -----END CERTIFICATE----- Certinomis - Root CA ==================== -----BEGIN CERTIFICATE----- MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00 8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE 6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I 6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9 Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr hkIGuUE= -----END CERTIFICATE----- OISTE WISeKey Global Root GB CA =============================== -----BEGIN CERTIFICATE----- MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk 9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= -----END CERTIFICATE----- SZAFIR ROOT CA2 =============== -----BEGIN CERTIFICATE----- MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE 2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul 4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 +/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== -----END CERTIFICATE----- Certum Trusted Network CA 2 =========================== -----BEGIN CERTIFICATE----- MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ 9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 zAYspsbiDrW5viSP -----END CERTIFICATE----- Hellenic Academic and Research Institutions RootCA 2015 ======================================================= -----BEGIN CERTIFICATE----- MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ 6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn 82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q p/UsQu0yrbYhnr68 -----END CERTIFICATE----- Hellenic Academic and Research Institutions ECC RootCA 2015 =========================================================== -----BEGIN CERTIFICATE----- MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR -----END CERTIFICATE----- Certplus Root CA G1 =================== -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUAMD4xCzAJBgNV BAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTAe Fw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhD ZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHN r49aiZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt6kuJPKNx Qv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP0FG7Yn2ksYyy/yARujVj BYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTv LRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDEEW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2 z4QTd28n6v+WZxcIbekN1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc 4nBvCGrch2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCTmehd 4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV4EJQeIQEQWGw9CEj jy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPOWftwenMGE9nTdDckQQoRb5fc5+R+ ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G A1UdDgQWBBSowcCbkahDFXxdBie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHY lwuBsTANBgkqhkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh 66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7/SMNkPX0XtPG YX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BSS7CTKtQ+FjPlnsZlFT5kOwQ/ 2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F 6ALEUz65noe8zDUa3qHpimOHZR4RKttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilX CNQ314cnrUlZp5GrRHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWe tUNy6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEVV/xuZDDC VRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5g4VCXA9DO2pJNdWY9BW/ +mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl++O/QmueD6i9a5jc2NvLi6Td11n0bt3+ qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo= -----END CERTIFICATE----- Certplus Root CA G2 =================== -----BEGIN CERTIFICATE----- MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0 cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw== -----END CERTIFICATE----- OpenTrust Root CA G1 ==================== -----BEGIN CERTIFICATE----- MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcx MB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7fa Yp6bwiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX/uMftk87 ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR077F9jAHiOH3BX2pfJLKO YheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGPuY4zbGneWK2gDqdkVBFpRGZPTBKnjix9 xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLxp2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO 9z0M+Yo0FMT7MzUj8czxKselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq 3ywgsNw2TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+WG+Oi n6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPwvFEVVJSmdz7QdFG9 URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYYEQRVzXR7z2FwefR7LFxckvzluFqr TJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUl0YhVyE12jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/Px N3DlCPaTKbYwDQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kfgLMtMrpkZ2Cv uVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbSFXJfLkur1J1juONI5f6ELlgK n0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLh X4SPgPL0DTatdrOjteFkdjpY3H1PXlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80 nR14SohWZ25g/4/Ii+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcm GS3tTAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L9109S5zvE/ bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/KyPu1svf0OnWZzsD2097+o 4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJAwSQiumPv+i2tCqjI40cHLI5kqiPAlxA OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx -----END CERTIFICATE----- OpenTrust Root CA G2 ==================== -----BEGIN CERTIFICATE----- MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUAMEAxCzAJBgNV BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcy MB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+ Ntmh/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78eCbY2albz 4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/61UWY0jUJ9gNDlP7ZvyCV eYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fEFY8ElggGQgT4hNYdvJGmQr5J1WqIP7wt UdGejeBSzFfdNTVY27SPJIjki9/ca1TSgSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz 3GIZ38i1MH/1PCZ1Eb3XG7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj 3CzMpSZyYhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaHvGOz 9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4t/bQWVyJ98LVtZR0 0dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/gh7PU3+06yzbXfZqfUAkBXKJOAGT y3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zAdBgNVHQ4EFgQUajn6QiL35okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59 M4PLuG53hq8wDQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0nXGEL8pZ0keI mUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qTRmTFAHneIWv2V6CG1wZy7HBG S4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpTwm+bREx50B1ws9efAvSyB7DH5fitIw6mVskp EndI2S9G/Tvw/HRwkqWOOAgfZDC2t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ 6e18CL13zSdkzJTaTkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97kr gCf2o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU3jg9CcCo SmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eAiN1nE28daCSLT7d0geX0 YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14fWKGVyasvc0rQLW6aWQ9VGHgtPFGml4vm u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK -----END CERTIFICATE----- OpenTrust Root CA G3 ==================== -----BEGIN CERTIFICATE----- MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB /wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta 3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB -----END CERTIFICATE----- ISRG Root X1 ============ -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ 4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf 1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY 9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV 0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ m+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- AC RAIZ FNMT-RCM ================ -----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou 08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ 47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW +YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d 8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm 5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= -----END CERTIFICATE----- Amazon Root CA 1 ================ -----BEGIN CERTIFICATE----- MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy 8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa 2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 -----END CERTIFICATE----- Amazon Root CA 2 ================ -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ 3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY +gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= -----END CERTIFICATE----- Amazon Root CA 3 ================ -----BEGIN CERTIFICATE----- MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== -----END CERTIFICATE----- Amazon Root CA 4 ================ -----BEGIN CERTIFICATE----- MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN /sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri 83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== -----END CERTIFICATE----- LuxTrust Global Root 2 ====================== -----BEGIN CERTIFICATE----- MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQELBQAwRjELMAkG A1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNVBAMMFkx1eFRydXN0IEdsb2Jh bCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUwMzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEW MBQGA1UECgwNTHV4VHJ1c3QgUy5BLjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCC AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wm Kb3FibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTemhfY7RBi2 xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1EMShduxq3sVs35a0VkBC wGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsnXpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm 1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkm FRseTJIpgp7VkoGSQXAZ96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niF wpN6cj5mj5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4gDEa/ a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+8kPREd8vZS9kzl8U ubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2jX5t/Lax5Gw5CMZdjpPuKadUiDTSQ MC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmHhFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB /zBCBgNVHSAEOzA5MDcGByuBKwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5 Lmx1eHRydXN0Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT +Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQELBQADggIBAGoZ FO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9BzZAcg4atmpZ1gDlaCDdLnIN H2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTOjFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW 7MM3LGVYvlcAGvI1+ut7MV3CwRI9loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIu ZY+kt9J/Z93I055cqqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWA VWe+2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/JEAdemrR TxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKrezrnK+T+Tb/mjuuqlPpmt /f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQfLSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc 7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31I iyBMz2TWuJdGsE7RKlY6oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr -----END CERTIFICATE----- TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 ============================================= -----BEGIN CERTIFICATE----- MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= -----END CERTIFICATE----- GDCA TrustAUTH R5 ROOT ====================== -----BEGIN CERTIFICATE----- MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ 9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx 9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd +PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ 8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv /EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== -----END CERTIFICATE----- TrustCor RootCert CA-1 ====================== -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYDVQQGEwJQQTEP MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkx MjMxMTcyMzE2WjCBpDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFu YW1hIENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUGA1UECwwe VHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZUcnVzdENvciBSb290Q2Vy dCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv463leLCJhJrMxnHQFgKq1mq jQCj/IDHUHuO1CAmujIS2CNUSSUQIpidRtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4 pQa81QBeCQryJ3pS/C3Vseq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0 JEsq1pme9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CVEY4h gLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorWhnAbJN7+KIor0Gqw /Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/DeOxCbeKyKsZn3MzUOcwHwYDVR0j BBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AYYwDQYJKoZIhvcNAQELBQADggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5 mDo4Nvu7Zp5I/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZyonnMlo2HD6C qFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djtsL1Ac59v2Z3kf9YKVmgenFK+P 3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdNzl/HHk484IkzlQsPpTLWPFp5LBk= -----END CERTIFICATE----- TrustCor RootCert CA-2 ====================== -----BEGIN CERTIFICATE----- MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNVBAYTAlBBMQ8w DQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQwIgYDVQQKDBtUcnVzdENvciBT eXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0 eTEfMB0GA1UEAwwWVHJ1c3RDb3IgUm9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEy MzExNzI2MzlaMIGkMQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5h bWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29yIFJvb3RDZXJ0 IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnIG7CKqJiJJWQdsg4foDSq8Gb ZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9Nk RvRUqdw6VC0xK5mC8tkq1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1 oYxOdqHp2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nKDOOb XUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hapeaz6LMvYHL1cEksr1 /p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF3wP+TfSvPd9cW436cOGlfifHhi5q jxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQP eSghYA2FFn3XVDjxklb9tTNMg9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+Ctg rKAmrhQhJ8Z3mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh 8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAdBgNVHQ4EFgQU 2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6UnrybPZx9mCAZ5YwwYrIwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/h Osh80QA9z+LqBrWyOrsGS2h60COXdKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnp kpfbsEZC89NiqpX+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv 2wnL/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RXCI/hOWB3 S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYaZH9bDTMJBzN7Bj8RpFxw PIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dv DDqPys/cA8GiCcjl/YBeyGBCARsaU1q7N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYU RpFHmygk71dSTlxCnKr3Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANE xdqtvArBAs8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp5KeX RKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu1uwJ -----END CERTIFICATE----- TrustCor ECA-1 ============== -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJQQTEP MA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEkMCIGA1UECgwbVHJ1c3RDb3Ig U3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3Jp dHkxFzAVBgNVBAMMDlRydXN0Q29yIEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3Mjgw N1owgZwxCzAJBgNVBAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5 MSQwIgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRydXN0Q29y IENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3IgRUNBLTEwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb3w9U73NjKYKtR8aja+3+XzP4Q1HpGjOR MRegdMTUpwHmspI+ap3tDvl0mEDTPwOABoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23 xFUfJ3zSCNV2HykVh0A53ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmc p0yJF4OuowReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/wZ0+ fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZFZtS6mFjBAgMBAAGj YzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAfBgNVHSMEGDAWgBREnkj1zG1I1KBL f/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF AAOCAQEABT41XBVwm8nHc2FvcivUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u /ukZMjgDfxT2AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50soIipX1TH0Xs J5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BIWJZpTdwHjFGTot+fDz2LYLSC jaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1WitJ/X5g== -----END CERTIFICATE----- SSL.com Root Certification Authority RSA ======================================== -----BEGIN CERTIFICATE----- MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= -----END CERTIFICATE----- SSL.com Root Certification Authority ECC ======================================== -----BEGIN CERTIFICATE----- MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ 8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z 5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl -----END CERTIFICATE----- SSL.com EV Root Certification Authority RSA R2 ============================================== -----BEGIN CERTIFICATE----- MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim 9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 +qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 ++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX 9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== -----END CERTIFICATE----- SSL.com EV Root Certification Authority ECC =========================================== -----BEGIN CERTIFICATE----- MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy 3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe 5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== -----END CERTIFICATE----- hex-2.0.6/lib/hex/http/certs.ex000066400000000000000000000007421437023760000162770ustar00rootroot00000000000000defmodule Hex.HTTP.Certs do @moduledoc false crt_file = Path.join(__DIR__, "ca-bundle.crt") crt = File.read!(crt_file) pems = :public_key.pem_decode(crt) ders = Enum.map(pems, fn {:Certificate, der, _} -> der end) @der_encoded ders @external_resource crt_file def cacerts do @der_encoded end def decode_runtime(path) do crt = File.read!(path) pems = :public_key.pem_decode(crt) Enum.map(pems, fn {:Certificate, der, _} -> der end) end end hex-2.0.6/lib/hex/http/ssl.ex000066400000000000000000000075431437023760000157660ustar00rootroot00000000000000defmodule Hex.HTTP.SSL do @moduledoc false require Record alias Hex.HTTP.Certs alias Hex.HTTP.VerifyHostname # From https://www.ssllabs.com/ssltest/clients.html Android 7 @default_ciphers [ ~c"AES128-GCM-SHA256", ~c"AES128-SHA", ~c"AES256-GCM-SHA384", ~c"AES256-SHA", ~c"DES-CBC3-SHA", ~c"ECDHE-ECDSA-AES128-GCM-SHA256", ~c"ECDHE-ECDSA-AES128-SHA", ~c"ECDHE-ECDSA-AES256-GCM-SHA384", ~c"ECDHE-ECDSA-AES256-SHA", ~c"ECDHE-ECDSA-CHACHA20-POLY1305-SHA256", ~c"ECDHE-RSA-AES128-GCM-SHA256", ~c"ECDHE-RSA-AES128-SHA", ~c"ECDHE-RSA-AES256-GCM-SHA384", ~c"ECDHE-RSA-AES256-SHA", ~c"ECDHE-RSA-CHACHA20-POLY1305-SHA256" ] @default_versions [:"tlsv1.2", :"tlsv1.1", :tlsv1] @secure_ssl_version {5, 3, 7} Record.defrecordp( :certificate, :OTPCertificate, Record.extract(:OTPCertificate, from_lib: "public_key/include/OTP-PUB-KEY.hrl") ) Record.defrecordp( :tbs_certificate, :OTPTBSCertificate, Record.extract(:OTPTBSCertificate, from_lib: "public_key/include/OTP-PUB-KEY.hrl") ) def secure_ssl? do check? = not Hex.State.fetch!(:unsafe_https) if check? and Hex.State.fetch!(:ssl_version) <= @secure_ssl_version do Mix.raise( "Insecure HTTPS request (peer verification disabled), " <> "please update to OTP 17.4 or later, or disable by setting " <> "the environment variable HEX_UNSAFE_HTTPS=1" ) end check? end def get_ca_certs do case Hex.State.fetch!(:cacerts_path) do nil -> Certs.cacerts() path -> Certs.decode_runtime(path) end end def ssl_opts(url) do hostname = String.to_charlist(URI.parse(url).host) ciphers = filter_ciphers(@default_ciphers) if secure_ssl?() do partial_chain = &partial_chain(Certs.cacerts(), &1) [ verify: :verify_peer, depth: 4, partial_chain: partial_chain, cacerts: get_ca_certs(), server_name_indication: hostname, secure_renegotiate: true, reuse_sessions: true, versions: @default_versions, ciphers: ciphers ] |> customize_hostname_check(hostname) else [ verify: :verify_none, server_name_indication: hostname, secure_renegotiate: true, reuse_sessions: true, versions: @default_versions, ciphers: ciphers ] end end def partial_chain(cacerts, certs) do certs = Enum.map(certs, &{&1, :public_key.pkix_decode_cert(&1, :otp)}) cacerts = Enum.map(cacerts, &:public_key.pkix_decode_cert(&1, :otp)) trusted = Enum.find_value(certs, fn {der, cert} -> trusted? = Enum.find(cacerts, fn cacert -> extract_public_key_info(cacert) == extract_public_key_info(cert) end) if trusted?, do: der end) if trusted do {:trusted_ca, trusted} else :unknown_ca end end defp extract_public_key_info(cert) do cert |> certificate(:tbsCertificate) |> tbs_certificate(:subjectPublicKeyInfo) end defp filter_ciphers(allowed) do available = MapSet.new(Hex.Stdlib.ssl_cipher_suites(:openssl)) Enum.filter(allowed, &(&1 in available)) end defp customize_hostname_check(opts, hostname) do if ssl_major_version() >= 9 do # From OTP 20.0 use built-in support for custom hostname checks Keyword.put(opts, :customize_hostname_check, match_fun: &VerifyHostname.match_fun/2) else # Before OTP 20.0 use mint_shims for hostname check, from a custom verify_fun Keyword.put(opts, :verify_fun, {&VerifyHostname.verify_fun/3, check_hostname: hostname}) end end defp ssl_major_version do # Elixir 1.0.5 - 1.1.1 have no Application.spec/2 case :application.get_key(:ssl, :vsn) do {:ok, value} -> value :undefined -> nil end |> :string.to_integer() |> elem(0) end end hex-2.0.6/lib/hex/http/verify_hostname.ex000066400000000000000000000133721437023760000203640ustar00rootroot00000000000000defmodule Hex.HTTP.VerifyHostname do @moduledoc false # Based on https://github.com/deadtrickster/ssl_verify_hostname.erl require Record Record.defrecordp( :attribute_type_and_value, :AttributeTypeAndValue, Record.extract(:AttributeTypeAndValue, from_lib: "public_key/include/OTP-PUB-KEY.hrl") ) Record.defrecordp( :otp_tbs_certificate, :OTPTBSCertificate, Record.extract(:OTPTBSCertificate, from_lib: "public_key/include/OTP-PUB-KEY.hrl") ) Record.defrecordp( :otp_certificate, :OTPCertificate, Record.extract(:OTPCertificate, from_lib: "public_key/include/OTP-PUB-KEY.hrl") ) Record.defrecordp( :extension, :Extension, Record.extract(:Extension, from_lib: "public_key/include/OTP-PUB-KEY.hrl") ) @id_ce_subject_alt_name {2, 5, 29, 17} @id_at_common_name {2, 5, 4, 3} def verify_cert_hostname(otp_certificate(tbsCertificate: tbs_cert), hostname) do dns_names = extract_dns_names(tbs_cert) dns_name_matched = try_match_hostnames(dns_names, hostname) if maybe_check_subject_cn(dns_names, dns_name_matched, tbs_cert, hostname) do {:valid, hostname} else {:fail, :unable_to_match_altnames} end end def verify_fun(_, {:bad_cert, _} = reason, _) do {:fail, reason} end def verify_fun(_, {:extension, _}, state) do {:unknown, state} end def verify_fun(_, :valid, state) do {:valid, state} end def verify_fun(cert, :valid_peer, state) do if check_hostname = state[:check_hostname] do verify_cert_hostname(cert, check_hostname) else {:valid, state} end end def match_fun({:dns_id, reference_id}, {:dNSName, presented_id}) do try_match_hostname(presented_id, reference_id) end def match_fun(_reference, _presented), do: :default def validate_and_parse_wildcard_identifier(identifier, hostname) do wildcard_pos = :string.chr(identifier, ?*) valid? = wildcard_pos != 0 and length(hostname) >= length(identifier) and check_wildcard_in_leftmost_label(identifier, wildcard_pos) if valid? do before_w = :string.substr(identifier, 1, wildcard_pos - 1) after_w = :string.substr(identifier, wildcard_pos + 1) if :string.chr(after_w, ?*) == 0 do case check_two_labels_after_wildcard(after_w) do {:ok, dot_after_wildcard} -> single_char_w = dot_after_wildcard == wildcard_pos and length(before_w) == 0 {before_w, after_w, single_char_w} :error -> false end else false end else false end end def try_match_hostname(identifier, hostname) do identifier = :string.strip(identifier, :right, ?.) hostname = :string.strip(hostname, :right, ?.) if case_insensitve_match(identifier, hostname) do true else case validate_and_parse_wildcard_identifier(identifier, hostname) do {before_w, after_w, single_char_w} -> try_match_wildcard(before_w, after_w, single_char_w, hostname) false -> false end end end defp extract_cn({:rdnSequence, list}), do: do_extract_cn(list) defp do_extract_cn([[attribute_type_and_value(type: @id_at_common_name, value: cn)] | _]), do: cn defp do_extract_cn([_ | rest]), do: rest defp do_extract_cn([]), do: [] defp extract_dns_names(otp_tbs_certificate(extensions: extensions)) do extensions = :pubkey_cert.extensions_list(extensions) alt_subject = :pubkey_cert.select_extension(@id_ce_subject_alt_name, extensions) if alt_subject == :undefined do [] else extract_dns_names_from_alt_names(extension(alt_subject, :extnValue)) end end defp extract_dns_names_from_alt_names(extn_values) do Enum.reduce(extn_values, [], fn extn_value, acc -> case extn_value do {:dNSName, dns_name} -> [dns_name | acc] _ -> acc end end) end defp case_insensitve_match(string1, string2) do :string.to_lower(string1) == :string.to_lower(string2) end defp wildcard_not_in_label(before_w, after_w) do dot_pos = :string.chr(after_w, ?.) after_dot = :string.substr(after_w, 1, dot_pos) :string.str(before_w, ~c"xn--") == 0 and :string.str(after_dot, ~c"xn--") == 0 end defp try_match_wildcard(before_w, after_w, single_char_w, pattern) do dot_pos = :string.chr(pattern, ?.) if single_char_w do case_insensitve_match(after_w, :string.substr(pattern, dot_pos)) else if wildcard_not_in_label(before_w, after_w) do pattern_part1 = :string.substr(pattern, length(pattern) - length(after_w) + 1, length(after_w)) pattern_part2 = :string.substr(pattern, 1, length(before_w)) case_insensitve_match(after_w, pattern_part1) and case_insensitve_match(before_w, pattern_part2) else false end end end defp check_two_labels_after_wildcard(string) do {_, positions} = Enum.reduce(string, {1, []}, fn ?., {ix, acc} -> {ix + 1, [ix | acc]} _, {ix, acc} -> {ix + 1, acc} end) if length(positions) >= 2 do {:ok, List.last(positions)} else :error end end defp check_wildcard_in_leftmost_label(identifier, wildcard_pos) do dot_pos = :string.chr(identifier, ?.) dot_pos != 0 and dot_pos >= wildcard_pos end defp try_match_hostnames(dns_names, hostname) do Enum.any?(dns_names, &try_match_hostname(&1, hostname)) end defp maybe_check_subject_cn(_dns_names, true, _tbs_cert, _hostname) do true end defp maybe_check_subject_cn([_ | _], false, _tbs_cert, _hostname) do false end defp maybe_check_subject_cn(_dns_names, false, tbs_cert, hostname) do tbs_cert |> otp_tbs_certificate(:subject) |> extract_cn() |> try_match_hostname(hostname) end end hex-2.0.6/lib/hex/mix.ex000066400000000000000000000142041437023760000147730ustar00rootroot00000000000000defmodule Hex.Mix do @moduledoc false # Utility functions around Mix dependencies. @type deps :: %{String.t() => {boolean, deps}} @doc """ Given a tree of dependencies return a flat list of all dependencies in the tree. The returned flattened list is going to contain duplicated dependencies because we want to accumulate all of the different requirements. However we must skip overridden dependencies as their requirements are no longer relevant. We also skip dependencies that are not included in the original list of dependencies as they were likely filtered out due to options like `:only`. """ @spec flatten_deps([Mix.Dep.t()], [atom]) :: [Mix.Dep.t()] def flatten_deps(deps, overridden_map) do apps = Enum.map(deps, & &1.app) deps ++ for( dep <- deps, %{app: app} = child <- dep.deps, app in apps and !overridden_map[Atom.to_string(app)], do: child ) end def overridden_deps(deps) do for( dep <- deps, dep.opts[:override], into: %{}, do: {Atom.to_string(dep.app), true} ) end @doc """ Converts a list of dependencies to a requests to the resolver. Skips dependencies overriding with another SCM (but include dependencies overriding with Hex) and dependencies that are not Hex packages. """ def deps_to_requests(deps) do for %Mix.Dep{app: app, requirement: req, scm: Hex.SCM, opts: opts, from: from} <- deps do from = Path.relative_to_cwd(from) {opts[:repo], opts[:hex], Atom.to_string(app), req, from} end end @doc """ Returns all top level dependencies. """ @spec top_level([Mix.Dep.t()]) :: [atom] def top_level(deps) do deps |> Enum.filter(& &1.top_level) |> Enum.map(& &1.app) end @doc """ Normalises a dependency definition to its 3-tuple form. """ @spec dep(tuple) :: {String.t(), String.t(), Keyword.t()} def dep({app, opts}) when is_list(opts), do: {app, nil, opts} def dep({app, req}) when is_binary(req), do: {app, req, []} def dep({app, req, opts}), do: {app, req, opts} @doc """ Takes all Hex packages from the lock and returns them as `{name, app, version, repo}` tuples. """ @spec from_lock(%{}) :: [{String.t(), String.t(), String.t(), String.t()}] def from_lock(lock) do Enum.flat_map(lock, fn {app, info} -> case Hex.Utils.lock(info) do %{name: name, version: version, repo: repo} -> [{repo, name, Atom.to_string(app), version}] nil -> [] end end) end @doc """ Takes a map of `{name, version}` and returns them as a lock of Hex packages. """ def to_lock(result) do Map.new(result, fn {repo, name, app, version} -> inner_checksum = Hex.Registry.Server.inner_checksum(repo, name, version) |> Base.encode16(case: :lower) outer_checksum = Hex.Registry.Server.outer_checksum(repo, name, version) |> encode_outer_checksum() deps = Hex.Registry.Server.dependencies(repo, name, version) |> case(do: ({:ok, deps} -> deps)) |> Enum.map(®istry_dep_to_def/1) |> Enum.sort() managers = managers(app) |> Enum.sort() |> Enum.uniq() {String.to_atom(app), {:hex, String.to_atom(name), version, inner_checksum, managers, deps, repo, outer_checksum}} end) end defp encode_outer_checksum(nil) do nil end defp encode_outer_checksum(binary) do Base.encode16(binary, case: :lower) end # We need to get managers from manifest if a dependency is not in the lock # but it's already fetched. Without the manifest we would only get managers # from metadata during checkout or from the lock entry. defp managers(nil), do: [] defp managers(app) do path = Path.join([Mix.Project.deps_path(), app, ".hex"]) case File.read(path) do {:ok, file} -> case Hex.SCM.parse_manifest(file) do {:ok, %{managers: managers}} -> managers :error -> [] end _ -> [] end end defp registry_dep_to_def(%{ repo: repo, name: name, constraint: constraint, optional: optional, label: app }) do {String.to_atom(app), to_string(constraint), hex: String.to_atom(name), repo: repo || "hexpm", optional: optional} end def packages_from_lock(lock) do Enum.flat_map(lock, fn {_app, info} -> case Hex.Utils.lock(info) do %{name: name, repo: repo} -> [{repo, name}] nil -> [] end end) end def normalize_dep({app, opts}) when is_atom(app) and is_list(opts) do {app, nil, opts} end def normalize_dep({app, req}) when is_atom(app) do {app, req, []} end def normalize_dep({app, req, opts}) when is_atom(app) and is_list(opts) do {app, req, opts} end def top_level_deps() do config = Mix.Project.config() apps_paths = apps_paths(config) umbrella_deps = Enum.map(config[:deps], fn deps -> {"", deps} end) child_deps = Enum.flat_map(apps_paths || [], fn {app, path} -> Mix.Project.in_project(app, path, fn _module -> Enum.map(Mix.Project.config()[:deps], fn deps -> {path, deps} end) end) end) (umbrella_deps ++ child_deps) |> Enum.map(fn {src, dep} -> {src, normalize_dep(dep)} end) |> Enum.reduce(%{}, fn {src, {app, req, opts}}, acc -> Map.update(acc, app, [{src, req, opts}], &[{src, req, opts} | &1]) end) end def apps_paths(config) do if apps_path = config[:apps_path] do config[:apps] |> umbrella_apps(apps_path) |> to_apps_paths(apps_path) end end defp umbrella_apps(nil, apps_path) do case File.ls(apps_path) do {:ok, apps} -> Enum.map(apps, &String.to_atom/1) {:error, _} -> [] end end defp umbrella_apps(apps, _apps_path) when is_list(apps) do apps end defp to_apps_paths(apps, apps_path) do for app <- apps, path = path_with_mix_exs(app, apps_path), do: {app, path}, into: %{} end defp path_with_mix_exs(app, apps_path) do path = Path.join(apps_path, Atom.to_string(app)) if File.regular?(Path.join(path, "mix.exs")) do path end end end hex-2.0.6/lib/hex/netrc.ex000066400000000000000000000005151437023760000153110ustar00rootroot00000000000000defmodule Hex.Netrc do @moduledoc false alias Hex.Netrc.Cache alias Hex.Netrc.Parser def lookup(host, path \\ Parser.netrc_path()) when is_binary(host) and is_binary(path) do case Cache.fetch(path) do {:ok, %{} = machines} -> {:ok, Map.get(machines, host)} other -> other end end end hex-2.0.6/lib/hex/netrc/000077500000000000000000000000001437023760000147525ustar00rootroot00000000000000hex-2.0.6/lib/hex/netrc/cache.ex000066400000000000000000000012541437023760000163550ustar00rootroot00000000000000defmodule Hex.Netrc.Cache do @moduledoc false alias Hex.Netrc.Parser @agent_name __MODULE__ def start_link(_arg) do Agent.start_link(fn -> %{} end, name: @agent_name) end def child_spec(arg) do %{ id: __MODULE__, start: {__MODULE__, :start_link, [arg]} } end def fetch(path \\ Parser.netrc_path()) when is_binary(path) do Agent.get_and_update(@agent_name, fn cache -> case Map.fetch(cache, path) do {:ok, cached_parse_result} -> {cached_parse_result, cache} :error -> parse_result = Parser.parse(path) {parse_result, Map.put(cache, path, parse_result)} end end) end end hex-2.0.6/lib/hex/netrc/parser.ex000066400000000000000000000030121437023760000166000ustar00rootroot00000000000000defmodule Hex.Netrc.Parser do @moduledoc false def parse(path \\ netrc_path()) when is_binary(path) do case File.read(path) do {:ok, contents} -> parse_contents(contents) error -> error end end defp parse_contents(contents) when is_binary(contents) do parse_result = contents |> String.trim() |> String.split("\n", trim: true) |> Enum.map(&String.split/1) |> Enum.reduce({%{}, nil}, &parse_line/2) case parse_result do {machines, %{username: _, password: _} = current} -> {host, machine} = Map.pop(current, :host) {:ok, Map.put(machines, host, machine)} _ -> {:error, :parse} end end defp parse_line(_, :parse_error), do: :parse_error defp parse_line(["machine", host], {machines, nil}) do {machines, %{host: host}} end defp parse_line(["machine", next_host], {machines, %{username: _, password: _} = current}) do {host, machine} = Map.pop(current, :host) {Map.put(machines, host, machine), %{host: next_host}} end defp parse_line(["login", username], {machines, %{} = current}) do {machines, Map.put(current, :username, username)} end defp parse_line(["password", password], {machines, %{} = current}) do {machines, Map.put(current, :password, password)} end defp parse_line(_line, _parse_state), do: :parse_error def netrc_path() do System.get_env("NETRC") || default_path() end defp default_path() do Path.join(System.user_home!(), ".netrc") end end hex-2.0.6/lib/hex/package.ex000066400000000000000000000041631437023760000155740ustar00rootroot00000000000000defmodule Hex.Package do @moduledoc false def default_files() do ~w(lib priv .formatter.exs mix.exs README* readme* LICENSE* license* CHANGELOG* changelog* src c_src Makefile*) end def configuration_doc() do """ ## Configuration * `:app` - Package name (required). * `:version` - Package version (required). * `:deps` - List of package dependencies (see [Dependencies](#module-dependencies) below). * `:description` - Short description of the project. * `:package` - Hex specific configuration (see [Package configuration](#module-package-configuration) below). ## Dependencies Dependencies are defined in mix's dependency format. But instead of using `:git` or `:path` as the SCM `:package` is used. defp deps() do [ {:ecto, "~> 0.1.0"}, {:postgrex, "~> 0.3.0"}, {:cowboy, github: "extend/cowboy"} ] end As can be seen Hex package dependencies works alongside git dependencies. Important to note is that non-Hex dependencies will not be used during dependency resolution and neither will they be listed as dependencies of the package. ## Package configuration Additional metadata of the package can optionally be defined, but it is very recommended to do so. * `:name` - Set this if the package name is not the same as the application name. * `:files` - List of files and directories to include in the package, can include wildcards. Defaults to `#{inspect(default_files())}`. * `:exclude_patterns` - List of patterns matching files and directories to exclude from the package. * `:licenses` - List of licenses used by the package. * `:links` - Map of links relevant to the package. * `:build_tools` - List of build tools that can build the package. Hex will try to automatically detect the build tools based on the files in the package. If a `rebar` or `rebar.config` file is present Hex will mark it as able to build with rebar. This detection can be overridden by setting this field. """ end end hex-2.0.6/lib/hex/parallel.ex000066400000000000000000000065711437023760000160020ustar00rootroot00000000000000defmodule Hex.Parallel do @moduledoc false # Runs a number of jobs (with an upper bound) in parallel and # awaits them to finish. use GenServer require Logger def start_link([name]) do GenServer.start_link(__MODULE__, [], name: name) end def run(name, id, opts \\ [], fun) do GenServer.call(name, {:run, id, opts, fun}) end def await(name, id, timeout) do GenServer.call(name, {:await, id}, timeout) end def clear(name) do GenServer.call(name, :clear) end def init([]) do {:ok, new_state()} end def handle_call({:run, id, opts, fun}, {pid, _ref}, state) do await? = Keyword.get(opts, :await, true) state = run_task(id, fun, state) state = if await? do state else %{state | waiting_reply: Map.put(state.waiting_reply, id, {:send, pid})} end {:reply, :ok, state} end def handle_call({:await, id}, from, state) do if result = state.finished[id] do state = %{state | finished: Map.delete(state.finished, id)} {:reply, result, state} else state = %{state | waiting_reply: Map.put(state.waiting_reply, id, {:gen, from})} {:noreply, state} end end def handle_call(:clear, _from, state) do Enum.each(state.running, fn {%Task{pid: pid}, _} -> Process.unlink(pid) Process.exit(pid, :kill) end) state = %{state | running: %{}, finished: %{}, waiting: :queue.new(), waiting_reply: %{}} {:reply, :ok, state} end def handle_info({ref, message}, state) when is_reference(ref) do tasks = Map.keys(state.running) if task = Enum.find(tasks, &(&1.ref == ref)) do id = state.running[task] state = %{state | running: Map.delete(state.running, task)} |> reply(id, message) |> next_task() {:noreply, state} else Logger.error("[Hex] Hex.Parallel received unknown reply: #{inspect({ref, message})}") {:noreply, state} end end def handle_info({:DOWN, ref, _, proc, reason}, state) do tasks = Map.keys(state.running) if Enum.find(tasks, &(&1.ref == ref)) do Logger.error( "[Hex] Hex.Parallel task #{inspect(proc)} died with reason: #{inspect(reason)}" ) {:noreply, %{state | running: Map.delete(state.running, ref)}} else {:noreply, state} end end defp reply(state, id, message) do case state.waiting_reply[id] do {:gen, from} -> GenServer.reply(from, message) %{state | waiting_reply: Map.delete(state.waiting_reply, id)} {:send, pid} -> send(pid, message) %{state | waiting_reply: Map.delete(state.waiting_reply, id)} nil -> %{state | finished: Map.put(state.finished, id, message)} end end defp next_task(state) do case :queue.out(state.waiting) do {{:value, {id, fun}}, waiting} -> state = %{state | waiting: waiting} run_task(id, fun, state) {:empty, _} -> state end end defp run_task(id, fun, state) do if map_size(state.running) >= state.max_jobs do %{state | waiting: :queue.in({id, fun}, state.waiting)} else task = Task.async(fun) %{state | running: Map.put(state.running, task, id)} end end defp new_state() do %{ max_jobs: Hex.State.fetch!(:http_concurrency), running: %{}, finished: %{}, waiting: :queue.new(), waiting_reply: %{} } end end hex-2.0.6/lib/hex/registry/000077500000000000000000000000001437023760000155075ustar00rootroot00000000000000hex-2.0.6/lib/hex/registry/server.ex000066400000000000000000000322301437023760000173530ustar00rootroot00000000000000defmodule Hex.Registry.Server do @moduledoc false use GenServer @behaviour Hex.Solver.Registry @name __MODULE__ @filename "cache.ets" @timeout 60_000 @ets_version 3 def start_link(opts \\ []) do opts = Keyword.put_new(opts, :name, @name) GenServer.start_link(__MODULE__, [], opts) end def open(opts \\ []) do GenServer.call(@name, {:open, opts}, @timeout) end def close() do GenServer.call(@name, :close, @timeout) end def persist() do GenServer.call(@name, :persist, @timeout) end def prefetch(packages) do :ok = GenServer.call(@name, {:prefetch, packages}, @timeout) end def versions(repo, package) do GenServer.call(@name, {:versions, repo, package}, @timeout) end def dependencies(repo, package, version) do GenServer.call(@name, {:dependencies, repo, package, version}, @timeout) end def inner_checksum(repo, package, version) do GenServer.call(@name, {:inner_checksum, repo, package, version}, @timeout) end def outer_checksum(repo, package, version) do GenServer.call(@name, {:outer_checksum, repo, package, version}, @timeout) end def retired(repo, package, version) do GenServer.call(@name, {:retired, repo, package, version}, @timeout) end def last_update() do GenServer.call(@name, :last_update, @timeout) end def last_update(time) do GenServer.call(@name, {:last_update, time}, @timeout) end def init([]) do {:ok, state()} end defp state() do %{ ets: nil, path: nil, pending: MapSet.new(), fetched: MapSet.new(), waiting: %{}, closing_fun: nil } end def handle_call({:open, opts}, _from, %{ets: nil} = state) do if Keyword.get(opts, :check_version, true) do Hex.UpdateChecker.start_check() end path = opts[:registry_path] || path() ets = String.to_charlist(path) |> open_ets() |> check_version() |> set_version() state = %{state | ets: ets, path: path} {:reply, :ok, state} end def handle_call({:open, opts}, _from, state) do if Keyword.get(opts, :check_version, true) do Hex.UpdateChecker.start_check() end {:reply, :ok, state} end def handle_call(:close, from, %{ets: tid, path: path} = state) do state = wait_closing(state, fn -> if tid do persist(tid, path) :ets.delete(tid) end GenServer.reply(from, :ok) state() end) {:noreply, state} end def handle_call(:persist, _from, state) do persist(state.ets, state.path) {:reply, :ok, state} end def handle_call({:prefetch, packages}, _from, state) do packages = packages |> Enum.map(fn {repo, package} -> {repo || "hexpm", package} end) |> Enum.uniq() |> Enum.reject(&(&1 in state.fetched)) |> Enum.reject(&(&1 in state.pending)) purge_repo_from_cache(packages, state) if Hex.State.fetch!(:offline) do prefetch_offline(packages, state) else prefetch_online(packages, state) end end def handle_call({:versions, repo, package}, from, state) do maybe_wait({repo, package}, from, state, fn -> case lookup(state.ets, {:versions, repo || "hexpm", package}) do nil -> :error versions -> versions = versions |> Enum.map(&Hex.Solver.parse_constraint!/1) |> Enum.sort(&(Version.compare(&1, &2) in [:lt, :eq])) {:ok, versions} end end) end def handle_call({:dependencies, repo, package, version}, from, state) do maybe_wait({repo, package}, from, state, fn -> case lookup(state.ets, {:deps, repo || "hexpm", package, to_string(version)}) do nil -> :error deps -> deps = Enum.map(deps, fn {repo, package, app, requirement, optional} -> %{ repo: if(repo != "hexpm", do: repo), name: package, constraint: Hex.Solver.parse_constraint!(requirement || ">= 0.0.0"), optional: optional, label: app } end) {:ok, deps} end end) end def handle_call({:inner_checksum, repo, package, version}, from, state) do maybe_wait({repo, package}, from, state, fn -> lookup(state.ets, {:inner_checksum, repo || "hexpm", package, version}) end) end def handle_call({:outer_checksum, repo, package, version}, from, state) do maybe_wait({repo, package}, from, state, fn -> lookup(state.ets, {:outer_checksum, repo || "hexpm", package, version}) end) end def handle_call({:retired, repo, package, version}, from, state) do maybe_wait({repo, package}, from, state, fn -> lookup(state.ets, {:retired, repo || "hexpm", package, version}) end) end def handle_call(:last_update, _from, state) do time = lookup(state.ets, :last_update) {:reply, time, state} end def handle_call({:last_update, time}, _from, state) do :ets.insert(state.ets, {:last_update, time}) {:reply, :ok, state} end def handle_info({:DOWN, _ref, :process, _pid, :normal}, state) do {:noreply, state} end def handle_info({:get_package, repo, package, result}, state) do repo = repo || "hexpm" repo_package = {repo, package} pending = MapSet.delete(state.pending, repo_package) fetched = MapSet.put(state.fetched, repo_package) {replys, waiting} = Map.pop(state.waiting, repo_package, []) write_result(result, repo, package, state) Enum.each(replys, fn {from, fun} -> GenServer.reply(from, fun.()) end) state = %{state | pending: pending, waiting: waiting, fetched: fetched} state = maybe_close(state) {:noreply, state} end defp open_ets(path) do case :ets.file2tab(path) do {:ok, tid} -> tid {:error, {:read_error, {:file_error, _path, :enoent}}} -> :ets.new(@name, []) {:error, reason} -> Hex.Shell.error("Error opening ETS file #{path}: #{inspect(reason)}") File.rm(path) :ets.new(@name, []) end end defp check_version(ets) do case :ets.lookup(ets, :version) do [{:version, @ets_version}] -> ets _ -> :ets.delete(ets) :ets.new(@name, []) end end defp set_version(ets) do :ets.insert(ets, {:version, @ets_version}) ets end defp persist(tid, path) do dir = Path.dirname(path) File.mkdir_p!(dir) :ok = :ets.tab2file(tid, String.to_charlist(path)) end defp purge_repo_from_cache(packages, %{ets: ets}) do Enum.each(packages, fn {repo, _package} -> repo = repo || "hexpm" config = Hex.Repo.get_repo(repo) url = config.url case :ets.lookup(ets, {:repo, repo}) do [{_key, ^url}] -> :ok [] -> :ok _ -> purge_repo(repo, ets) end :ets.insert(ets, {{:repo, repo}, url}) end) end # :ets.fun2ms(fn # {{:versions, ^repo, _package}, _} -> true # {{:deps, ^repo, _package, _version}, _} -> true # {{:inner_checksum, ^repo, _package, _version}, _} -> true # {{:outer_checksum, ^repo, _package, _version}, _} -> true # {{:retired, ^repo, _package, _version}, _} -> true # {{:registry_etag, ^repo, _package}, _} -> true # {{:timestamp, ^repo, _package}, _} -> true # {{:timestamp, ^repo, _package, _version}, _} -> true # _ -> false # end) defp purge_repo_matchspec(repo) do [ {{{:versions, :"$1", :"$2"}, :_}, [{:"=:=", {:const, repo}, :"$1"}], [true]}, {{{:deps, :"$1", :"$2", :"$3"}, :_}, [{:"=:=", {:const, repo}, :"$1"}], [true]}, {{{:inner_checksum, :"$1", :"$2", :"$3"}, :_}, [{:"=:=", {:const, repo}, :"$1"}], [true]}, {{{:outer_checksum, :"$1", :"$2", :"$3"}, :_}, [{:"=:=", {:const, repo}, :"$1"}], [true]}, {{{:retired, :"$1", :"$2", :"$3"}, :_}, [{:"=:=", {:const, repo}, :"$1"}], [true]}, {{{:registry_etag, :"$1", :"$2"}, :_}, [{:"=:=", {:const, repo}, :"$1"}], [true]}, {{{:timetamp, :"$1", :"$2"}, :_}, [{:"=:=", {:const, repo}, :"$1"}], [true]}, {{{:timetamp, :"$1", :"$2", :"$3"}, :_}, [{:"=:=", {:const, repo}, :"$1"}], [true]}, {:_, [], [false]} ] end defp purge_repo(repo, ets) do :ets.select_delete(ets, purge_repo_matchspec(repo)) end defp prefetch_online(packages, state) do Enum.each(packages, fn {repo, package} -> etag = package_etag(repo, package, state) Hex.Parallel.run(:hex_fetcher, {:registry, repo, package}, [await: false], fn -> {:get_package, repo, package, Hex.Repo.get_package(repo, package, etag)} end) end) pending = MapSet.union(MapSet.new(packages), state.pending) state = %{state | pending: pending} {:reply, :ok, state} end defp prefetch_offline(packages, state) do missing = Enum.find(packages, fn {repo, package} -> unless lookup(state.ets, {:versions, repo, package}) do package end end) if missing do {repo, package} = missing message = "Hex is running in offline mode and the registry entry for " <> "package #{Hex.Utils.package_name(repo, package)} is not cached locally" {:reply, {:error, message}, state} else fetched = MapSet.union(MapSet.new(packages), state.fetched) {:reply, :ok, %{state | fetched: fetched}} end end defp write_result({:ok, {code, body, headers}}, repo, package, %{ets: tid}) when code in 200..299 do releases = body |> :zlib.gunzip() |> Hex.Repo.verify(repo) |> Hex.Repo.decode_package(repo, package) delete_package(repo, package, tid) now = :calendar.universal_time() Enum.each(releases, fn %{version: version} = release -> :ets.insert(tid, {{:timestamp, repo, package, version}, now}) :ets.insert(tid, {{:inner_checksum, repo, package, version}, release[:inner_checksum]}) :ets.insert(tid, {{:outer_checksum, repo, package, version}, release[:outer_checksum]}) :ets.insert(tid, {{:retired, repo, package, version}, release[:retired]}) deps = Enum.map(release[:dependencies], fn dep -> {dep[:repository] || repo, dep[:package], dep[:app] || dep[:package], dep[:requirement], !!dep[:optional]} end) :ets.insert(tid, {{:deps, repo, package, version}, deps}) end) :ets.insert(tid, {{:timestamp, repo, package}, now}) versions = Enum.map(releases, & &1[:version]) :ets.insert(tid, {{:versions, repo, package}, versions}) if etag = headers[~c"etag"] do :ets.insert(tid, {{:registry_etag, repo, package}, List.to_string(etag)}) end end defp write_result({:ok, {304, _, _}}, _repo, _package, _state) do :ok end defp write_result(other, repo, package, %{ets: tid}) do cached? = !!:ets.lookup(tid, {:versions, package}) print_error(other, repo, package, cached?) unless cached? do raise "Stopping due to errors" end end defp print_error(result, repo, package, cached?) do cached_message = if cached?, do: " (using cache instead)" Hex.Shell.error( "Failed to fetch record for #{Hex.Utils.package_name(repo, package)} from registry#{cached_message}" ) if missing_status?(result) do Hex.Shell.error( "This could be because the package does not exist, it was spelled " <> "incorrectly or you don't have permissions to it" ) end if not missing_status?(result) or Mix.debug?() do Hex.Utils.print_error_result(result) end end defp missing_status?({:ok, {status, _, _}}), do: status in [403, 404] defp missing_status?(_), do: false defp maybe_wait({repo, package}, from, state, fun) do repo = repo || "hexpm" cond do {repo, package} in state.fetched -> {:reply, fun.(), state} {repo, package} in state.pending -> tuple = {from, fun} waiting = Map.update(state.waiting, {repo, package}, [tuple], &[tuple | &1]) state = %{state | waiting: waiting} {:noreply, state} true -> repo = if repo, do: "#{repo}/" Mix.raise("Package #{repo}#{package} not prefetched, please report this issue") end end defp wait_closing(state, fun) do if MapSet.size(state.pending) == 0 do state = fun.() %{state | closing_fun: nil} else %{state | closing_fun: fun} end end defp maybe_close(%{closing_fun: nil} = state) do state end defp maybe_close(%{closing_fun: fun} = state) do wait_closing(state, fun) end defp package_etag(repo, package, %{ets: tid}) do case :ets.lookup(tid, {:registry_etag, repo, package}) do [{_, etag}] -> etag [] -> nil end end defp path do Path.join(Hex.State.fetch!(:cache_home), @filename) end defp delete_package(repo, package, tid) do :ets.delete(tid, {:registry_etag, repo, package}) versions = lookup(tid, {:versions, repo, package}) || [] :ets.delete(tid, {:versions, repo, package}) Enum.each(versions, fn version -> :ets.delete(tid, {:checksum, repo, package, version}) :ets.delete(tid, {:retired, repo, package, version}) :ets.delete(tid, {:deps, repo, package, version}) end) end defp lookup(tid, key) do case :ets.lookup(tid, key) do [{^key, element}] -> element [] -> nil end end end hex-2.0.6/lib/hex/remote_converger.ex000066400000000000000000000446501437023760000175530ustar00rootroot00000000000000defmodule Hex.RemoteConverger do @moduledoc false @behaviour Mix.RemoteConverger alias Hex.Registry.Server, as: Registry def post_converge() do Hex.UpdateChecker.check() if Hex.State.get(:print_sponsored_tip) do Hex.Shell.info( "You have added/upgraded packages you could sponsor, " <> "run `mix hex.sponsor` to learn more" ) Hex.State.put(:print_sponsored_tip, false) end Registry.close() end def remote?(dep) do !!dep.opts[:hex] end def converge(deps, lock) do Registry.open() # We cannot use given lock here, because all deps that are being # converged have been removed from the lock by Mix # We need the old lock to get the children of Hex packages old_lock = Mix.Dep.Lock.read() overridden = Hex.Mix.overridden_deps(deps) flat_deps = Hex.Mix.flatten_deps(deps, overridden) requests = Hex.Mix.deps_to_requests(flat_deps) [ Hex.Mix.packages_from_lock(lock), Hex.Mix.packages_from_lock(old_lock), packages_from_requests(requests) ] |> Enum.concat() |> verify_prefetches() |> Registry.prefetch() locked = prepare_locked(lock, old_lock, deps) verify_lock(lock) verify_deps(deps, Hex.Mix.top_level(deps)) verify_input(requests, locked) Hex.Shell.info("Resolving Hex dependencies...") run_solver(lock, old_lock, requests, locked, overridden) end defp run_solver(lock, old_lock, requests, locked, overridden) do start_time = System.monotonic_time(:millisecond) dependencies = Enum.reduce(requests, %{}, fn {repo, name, app, requirement, from}, map -> repo = if(repo != "hexpm", do: repo) constraint = Hex.Solver.parse_constraint!(requirement || ">= 0.0.0-0") dependency = %{ repo: repo, name: name, constraint: constraint, optional: false, label: app, from: from } Map.update(map, {repo, name}, dependency, fn existing_dependency -> if existing_dependency.label != dependency.label do name = Hex.Utils.package_name(repo, name) Mix.raise(""" Conflicting OTP application names in dependency definition of #{inspect(name)}, in the following locations: * #{existing_dependency.from} defined application :#{existing_dependency.label} * #{dependency.from} defined application :#{dependency.label} """) end constraint = Hex.Solver.Constraint.intersect( existing_dependency.constraint, dependency.constraint ) optional = existing_dependency.optional and dependency.optional %{existing_dependency | constraint: constraint, optional: optional} end) end) |> Map.values() locked = Enum.map(locked, fn {repo, name, app, version} -> %{ repo: if(repo != "hexpm", do: repo), name: name, version: Hex.Solver.parse_constraint!(version), label: app } end) level = Logger.level() Logger.configure(level: if(Hex.State.fetch!(:debug_solver), do: :debug, else: :info)) solution = try do Hex.Solver.run( Registry, dependencies, locked, Map.keys(overridden), ansi: IO.ANSI.enabled?() ) after Logger.configure(level: level) end current_time = System.monotonic_time(:millisecond) total_time = Float.round((current_time - start_time) / 1000, 3) Hex.Shell.info("Resolution completed in #{total_time}s") case solution do {:ok, resolved} -> resolved = normalize_resolved(resolved) solver_success(resolved, requests, lock, old_lock) {:error, message} -> Hex.Shell.warn([IO.ANSI.reset(), message]) Mix.raise("Hex dependency resolution failed") end end def normalize_resolved(resolved) do resolved |> Enum.map(fn {name, {version, repo}} -> {repo || "hexpm", name, to_string(version)} end) |> Enum.sort() end defp solver_success(resolved, requests, lock, old_lock) do resolved = add_apps_to_resolved(resolved, requests) print_success(resolved, old_lock) verify_resolved(resolved, old_lock) new_lock = Hex.Mix.to_lock(resolved) Hex.SCM.prefetch(new_lock) lock_merge(lock, new_lock) end defp add_apps_to_resolved(resolved, requests) do resolved = Enum.map(resolved, fn {repo, package, version} -> apps = Enum.flat_map(resolved, fn {parent_repo, parent_package, parent_version} -> repo = if repo != "hexpm", do: repo deps = case Registry.dependencies(parent_repo, parent_package, parent_version) do {:ok, deps} -> deps :error -> [] end app = Enum.find_value(deps, fn %{repo: ^repo, name: ^package, label: app} -> app %{} -> nil end) if app do [{parent_repo, parent_package, app}] else [] end end) root_app = Enum.find_value(requests, fn {^repo, ^package, app, _requirement, _from} -> {"hexpm", "myapp", app} {_repo, _package, _app, _requirement, _from} -> nil end) apps = Enum.uniq_by(List.wrap(root_app) ++ apps, fn {_repo, _package, app} -> app end) case apps do [{_repo, _package, app}] -> {repo, package, app, version} apps when apps != [] -> name = Hex.Utils.package_name(repo, package) header = "Conflicting OTP application names in dependency definition of " <> "\"#{name} {version}\", in the following packages:\n\n" list = Enum.map_join(apps, "\n", fn {parent_repo, parent_package, app} -> name = Hex.Utils.package_name(parent_repo, parent_package) " * #{name} defined application :#{app}" end) Mix.raise(header <> list) end end) Enum.each(resolved, fn {_repo, _package, app, _version} -> conflicting = Enum.filter(resolved, fn {_repo, _package, ^app, _version} -> true {_repo, _package, _app, _version} -> false end) unless length(conflicting) == 1 do header = "Multiple packages resolved with the same OTP application name of \"#{app}\":\n\n" list = Enum.map_join(conflicting, "\n", fn {repo, package, _app, version} -> name = Hex.Utils.package_name(repo, package) " * #{name} #{version}" end) Mix.raise(header <> list) end end) resolved end defp packages_from_requests(deps) do Enum.map(deps, fn {repo, package, _app, _req, _from} -> {repo, package} end) end defp lock_merge(old, new) do Map.merge(old, new, fn _key, old_tuple, new_tuple -> if lock_tuple_needs_update?(old_tuple, new_tuple) do new_tuple else old_tuple end end) end defp lock_tuple_needs_update?(old_tuple, new_tuple) do old_info = Hex.Utils.lock(old_tuple) new_info = Hex.Utils.lock(new_tuple) not (old_info != nil and new_info != nil and old_info.name == new_info.name and old_info.version == new_info.version and old_info.inner_checksum == new_info.inner_checksum and old_info.outer_checksum == new_info.outer_checksum and old_info.repo == new_info.repo) end def deps(%Mix.Dep{app: app}, lock) do case Hex.Utils.lock(lock[app]) do %{name: name, version: version, deps: nil, repo: repo} -> Registry.open() Registry.prefetch([{repo, name}]) get_deps(repo, name, version) %{deps: deps} -> deps nil -> [] end end defp get_deps(repo, name, version) do deps = case Registry.dependencies(repo, name, version) do {:ok, deps} -> deps :error -> [] end for %{repo: repo, name: name, constraint: req, optional: optional, label: app} <- deps do app = String.to_atom(app) opts = [optional: optional, hex: name, repo: repo] {app, to_string(req), opts} end end defp verify_deps(deps, top_level) do Enum.each(deps, fn dep -> if dep.app in top_level and dep.scm == Hex.SCM and dep.requirement == nil do Hex.Shell.warn( "#{dep.app} is missing its version requirement, " <> "use \">= 0.0.0\" if it should match any version" ) end end) end defp verify_input(requests, locked) do Enum.each(requests, fn {repo, name, _app, req, from} -> verify_package_req(repo, name, req, from) end) Enum.each(locked, fn {repo, name, _app, req} -> verify_package_req(repo, name, req, "mix.lock") end) end defp verify_package_req(repo, name, req, from) do if Registry.versions(repo, name) == :error do Mix.raise("No package with name #{name} (from: #{from}) in registry") end if req != nil and Version.parse_requirement(req) == :error do Mix.raise( "Required version #{inspect(req)} for package #{name} is incorrectly specified (from: #{from})" ) end end defp print_success(resolved, old_lock) do if resolved != [] do previously_locked_versions = dep_info_from_lock(old_lock) dep_changes = group_dependency_changes(resolved, previously_locked_versions) Enum.each(dep_changes, fn {mod, deps} -> unless length(deps) == 0, do: print_category(mod) print_dependency_group(deps, mod) end) end end defp group_dependency_changes(resolved, previously_locked_versions) do state = %{new: [], eq: [], gt: [], lt: []} resolved |> Enum.map(fn {repo, name, _app, version} -> {name, {repo, version}} end) |> Enum.sort() |> Enum.reduce(state, fn {name, {repo, version}}, acc -> previous_version = previously_locked_versions |> Map.get(name) |> version_string_or_nil() change = categorize_dependency_change(previous_version, version) warning = warning_message(previous_version, version) Map.put(acc, change, acc[change] ++ [{name, repo, previous_version, version, warning}]) end) end defp dep_info_from_lock(lock) do Enum.flat_map(lock, fn {_app, info} -> case Hex.Utils.lock(info) do %{name: name, repo: repo, version: version} -> [{name, {repo, version}}] nil -> [] end end) |> Map.new() end defp version_string_or_nil(nil), do: nil defp version_string_or_nil({_repo, version_string}), do: version_string defp categorize_dependency_change(nil, _version), do: :new defp categorize_dependency_change(previous_version, version) do Version.compare(version, previous_version) end defp warning_message(nil, _version), do: nil defp warning_message(previous_version, version) do prev_ver = Version.parse!(previous_version) new_ver = Version.parse!(version) cond do major_version_change?(prev_ver, new_ver) -> " (major)" breaking_minor_version_change?(prev_ver, new_ver) -> " (minor)" true -> nil end end defp print_category(mod) do case mod do :new -> Hex.Shell.info("New:") :eq -> Hex.Shell.info("Unchanged:") :lt -> Hex.Shell.info("Downgraded:") :gt -> Hex.Shell.info("Upgraded:") end end defp print_dependency_group(deps, mod) do Enum.each(deps, fn {name, repo, previous_version, version, warning} -> print_status( Registry.retired(repo, name, version), mod, name, previous_version, version, warning ) end) end defp print_status(nil, mod, name, previous_version, version, warning) do case mod do :new -> Hex.Shell.info(Hex.Shell.format([:green, " #{name} #{version}", :red, "#{warning}"])) :eq -> Hex.Shell.info(" #{name} #{version}") :lt -> Hex.Shell.info( Hex.Shell.format([ :yellow, " #{name} #{previous_version} => #{version}", :red, "#{warning}" ]) ) :gt -> Hex.Shell.info( Hex.Shell.format([ :green, " #{name} #{previous_version} => #{version}", :red, "#{warning}" ]) ) end end defp print_status(retired, mod, name, previous_version, version, _warning) do case mod do mod when mod in [:eq, :new] -> Hex.Shell.warn(" #{name} #{version} RETIRED!") Hex.Shell.warn(" #{Hex.Utils.package_retirement_message(retired)}") _ -> Hex.Shell.warn(" #{name} #{previous_version} => #{version} RETIRED!") Hex.Shell.warn(" #{Hex.Utils.package_retirement_message(retired)}") end end defp verify_prefetches(prefetches) do prefetches |> Enum.map(fn {repo, _package} -> repo end) |> Enum.uniq() |> Enum.each(&verify_repo/1) prefetches end defp verify_repo(repo) do case Hex.Repo.fetch_repo(repo) do {:ok, _} -> :ok :error -> case repo do "hexpm:" <> organization -> if Hex.Shell.yes?( "No authenticated organization found for #{organization}. Do you want to authenticate it now?" ) do Mix.Tasks.Hex.Organization.run(["auth", organization]) else Hex.Repo.get_repo(repo) end _ -> Mix.raise( "Unknown repository #{inspect(repo)}, add new repositories " <> "with the `mix hex.repo add` task" ) end end end defp verify_resolved(resolved, lock) do Enum.each(resolved, fn {repo, name, app, version} -> atom_name = String.to_atom(name) case Hex.Utils.lock(lock[String.to_atom(app)]) do %{name: ^atom_name, version: ^version, repo: ^repo} = lock -> verify_inner_checksum(repo, name, version, lock.inner_checksum) verify_outer_checksum(repo, name, version, lock.outer_checksum) verify_deps(repo, name, version, lock.deps) _ -> :ok end end) end defp verify_inner_checksum(repo, name, version, checksum) do registry_checksum = Registry.inner_checksum(repo, name, version) if checksum && Base.decode16!(checksum, case: :lower) != registry_checksum do Mix.raise("Registry checksum mismatch against lock (#{name} #{version})") end end defp verify_outer_checksum(repo, name, version, checksum) do registry_checksum = Registry.outer_checksum(repo, name, version) if checksum && Base.decode16!(checksum, case: :lower) != registry_checksum do Mix.raise("Registry checksum mismatch against lock (#{name} #{version})") end end defp verify_deps(nil, _name, _version, _deps), do: :ok defp verify_deps(repo, name, version, deps) do deps = Enum.map(deps, fn {app, req, opts} -> %{ repo: opts[:repo], name: opts[:hex], constraint: Hex.Solver.parse_constraint!(req), optional: !!opts[:optional], label: Atom.to_string(app) } end) registry_deps = case Registry.dependencies(repo, name, version) do {:ok, deps} -> deps :error -> [] end if Enum.sort(deps) != Enum.sort(registry_deps) do Mix.raise("Registry dependencies mismatch against lock (#{name} #{version})") end end defp verify_lock(lock) do Enum.each(lock, fn {_app, info} -> case Hex.Utils.lock(info) do %{name: name, version: version, repo: repo} -> verify_dep(repo, name, version) nil -> :ok end end) end defp verify_dep(repo, name, version) do Hex.Repo.get_repo(repo) case Registry.versions(repo, name) do {:ok, versions} -> versions = Enum.map(versions, &to_string/1) unless version in versions do Mix.raise("Unknown package version #{name} #{version} in lockfile") end :error -> Mix.raise("Unknown package #{name} in lockfile") end end defp with_children(apps, lock) do [apps, do_with_children(apps, lock)] |> List.flatten() end defp do_with_children(names, lock) do Enum.map(names, fn name -> case Hex.Utils.lock(lock[String.to_atom(name)]) do %{name: name, version: version, deps: nil, repo: repo} -> # Do not error on bad data in the old lock because we should just # fix it automatically case Registry.dependencies(repo, name, version) do {:ok, deps} -> apps = Enum.map(deps, fn %{label: app} -> app end) [apps, do_with_children(apps, lock)] :error -> [] end %{deps: deps} -> apps = Enum.map(deps, &Atom.to_string(elem(&1, 0))) [apps, do_with_children(apps, lock)] nil -> [] end end) end defp prepare_locked(lock, old_lock, deps) do # Remove dependencies from the lock if: # 1. They are defined as git or path in mix.exs # 2. If the requirement or repo in mix.exs does not match the locked version # 3. If it's a child of another Hex package being unlocked/updated unlock_without_children = for {app, _} <- old_lock, not Map.has_key?(lock, app), do: Atom.to_string(app) unlock = (unlock_deps(deps, old_lock) ++ unlock_without_children) |> Enum.uniq() |> with_children(old_lock) |> Enum.uniq() old_lock |> Hex.Mix.from_lock() |> Enum.reject(fn {_repo, _name, app, _version} -> app in unlock end) end defp unlock_deps(deps, old_lock) do Enum.filter(deps, fn %Mix.Dep{scm: Hex.SCM, app: app, requirement: req, opts: opts} -> name = opts[:hex] case Hex.Utils.lock(old_lock[app]) do %{name: ^name, version: version, repo: repo} -> (req && not Version.match?(version, req)) || repo != opts[:repo] %{} -> false nil -> true end %Mix.Dep{} -> true end) |> Enum.map(&Atom.to_string(&1.app)) end defp major_version_change?(%Version{} = version1, %Version{} = version2) do version1.major != version2.major end defp breaking_minor_version_change?(%Version{} = version1, %Version{} = version2) do version1.major == 0 and version2.major == 0 and version1.minor != version2.minor end end hex-2.0.6/lib/hex/repo.ex000066400000000000000000000237161437023760000151530ustar00rootroot00000000000000defmodule Hex.Repo do @moduledoc false alias Hex.HTTP @public_keys_html "https://hex.pm/docs/public_keys" @hexpm_url "https://repo.hex.pm" @hexpm_public_key """ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApqREcFDt5vV21JVe2QNB Edvzk6w36aNFhVGWN5toNJRjRJ6m4hIuG4KaXtDWVLjnvct6MYMfqhC79HAGwyF+ IqR6Q6a5bbFSsImgBJwz1oadoVKD6ZNetAuCIK84cjMrEFRkELtEIPNHblCzUkkM 3rS9+DPlnfG8hBvGi6tvQIuZmXGCxF/73hU0/MyGhbmEjIKRtG6b0sJYKelRLTPW XgK7s5pESgiwf2YC/2MGDXjAJfpfCd0RpLdvd4eRiXtVlE9qO9bND94E7PgQ/xqZ J1i2xWFndWa6nfFnRxZmCStCOZWYYPlaxr+FZceFbpMwzTNs4g3d4tLNUcbKAIH4 0wIDAQAB -----END PUBLIC KEY----- """ def fetch_repo(repo) do repo = repo || "hexpm" repos = Hex.State.fetch!(:repos) case Map.fetch(repos, repo) do {:ok, config} when repo == "hexpm" -> hexpm = hexpm_repo() url = hexpm.url || config.url auth_key = hexpm.auth_key || config.auth_key {:ok, %{config | url: url, trusted: hexpm.trusted, auth_key: auth_key}} {:ok, config} -> {:ok, config} :error -> fetch_organization_fallback(repo) end end def get_repo(repo) do case fetch_repo(repo) do {:ok, config} -> config :error -> unknown_repo_error(repo) end end defp default_organization(repo, source, name) do url = merge_values(Map.get(repo, :url), source.url <> "/repos/#{name}") public_key = merge_values(Map.get(repo, :public_key), source.public_key) auth_key = merge_values(Map.get(repo, :auth_key), source.auth_key) repo |> Map.put(:url, url) |> Map.put(:public_key, public_key) |> Map.put(:auth_key, auth_key) |> Map.put(:trusted, Map.has_key?(repo, :auth_key) or source.trusted) end def hexpm_repo() do trusted_mirror_url = Hex.State.fetch!(:trusted_mirror_url) mirror_url = Hex.State.fetch!(:mirror_url) auth_key = Hex.State.fetch!(:repos_key) %{ url: trusted_mirror_url || mirror_url, public_key: @hexpm_public_key, auth_key: auth_key, trusted: trusted_mirror_url != nil or mirror_url == nil } end def default_hexpm_repo() do %{ url: @hexpm_url, public_key: @hexpm_public_key, auth_key: nil, trusted: true } end defp fetch_organization_fallback(repo) do case String.split(repo, ":", parts: 2) do [source, organization] -> source = get_repo(source) {:ok, default_organization(%{}, source, organization)} _ -> :error end end defp unknown_repo_error("hexpm:" <> organization) do Mix.raise( "Unknown organization #{inspect(organization)}, authorize with `mix hex.user auth` " <> "or add new organizations with the `mix hex.organization auth` task" ) end defp unknown_repo_error(repo) do Mix.raise( "Unknown repository #{inspect(repo)}, add new repositories " <> "with the `mix hex.repo add` task" ) end def merge_hexpm(repos, hexpm \\ hexpm_repo()) do Map.update(repos, "hexpm", hexpm, &Map.merge(hexpm, &1)) end def update_organizations(repos) do Map.new(repos, fn {name, repo} -> case split_repo_name(name) do [source, organization] -> state_pid = Process.whereis(Hex.State) source = if state_pid && state_pid != self() do get_repo(source) else Map.fetch!(repos, source) end repo = default_organization(repo, source, organization) {name, repo} _ -> {name, Map.put(repo, :trusted, true)} end end) end def clean_organizations(repos) do Map.new(repos, fn {name, repo} -> case split_repo_name(name) do [source, organization] -> source = get_repo(source) repo = repo |> put_organization_url(organization, source) |> clean_repo(source) {name, repo} _ -> {name, Map.delete(repo, :trusted)} end end) end defp put_organization_url(repo, organization, source_repo) do if repo.url == source_repo.url <> "/repos/#{organization}" do Map.delete(repo, :url) else repo end end def clean_hexpm(repos) do hexpm = hexpm_repo() repo = Map.get(repos, "hexpm", hexpm) repo = clean_repo(repo, hexpm) if repo == %{} do Map.delete(repos, "hexpm") else Map.put(repos, "hexpm", repo) end end defp clean_repo(repo, default) do repo |> Map.delete(:trusted) |> Enum.reject(fn {key, value} -> value in [nil, Map.get(default, key)] end) |> Map.new() end defp merge_values(nil, right), do: right defp merge_values(left, _right), do: left def get_package(repo, package, etag) do headers = Map.merge(etag_headers(etag), auth_headers(repo)) HTTP.request(:get, package_url(repo, package), headers, nil) end def get_docs(repo, package, version) do headers = auth_headers(repo) HTTP.request(:get, docs_url(repo, package, version), headers, nil) end def get_tarball(repo, package, version) do headers = auth_headers(repo) HTTP.request(:get, tarball_url(repo, package, version), headers, nil) end def get_public_key(repo) do headers = auth_headers(repo) HTTP.request(:get, public_key_url(repo), headers, nil) end def verify(body, repo) do public_key = get_repo(repo).public_key if Hex.State.fetch!(:unsafe_registry) do %{payload: payload} = :mix_hex_registry.decode_signed(body) payload else do_verify(body, public_key, repo) end end def get_installs() do config = Hex.State.fetch!(:repos)["hexpm"] url = config.url <> "/installs/hex-1.x.csv" HTTP.request(:get, url, %{}, nil) end def find_new_version_from_csv(body) do body |> parse_csv() |> find_latest_eligible_version() |> version_latest() end defp package_url(repo, package) do config = get_repo(repo) config.url <> "/packages/#{URI.encode(package)}" end defp docs_url(repo, package, version) do config = get_repo(repo) config.url <> "/docs/#{URI.encode(package)}-#{URI.encode(version)}.tar.gz" end def tarball_url(repo, package, version) do config = get_repo(repo) config.url <> "/tarballs/#{URI.encode(package)}-#{URI.encode(version)}.tar" end defp public_key_url(repo), do: repo.url <> "/public_key" defp etag_headers(nil), do: %{} defp etag_headers(etag), do: %{~c"if-none-match" => String.to_charlist(etag)} defp auth_headers(repo) when is_binary(repo) or repo == nil do repo |> get_repo() |> auth_headers() end defp auth_headers(%{trusted: true, auth_key: key}) when is_binary(key) do %{~c"authorization" => String.to_charlist(key)} end defp auth_headers(%{trusted: _, auth_key: _}) do %{} end defp parse_csv(body) do body |> :binary.split("\n", [:global, :trim]) |> Enum.map(&:binary.split(&1, ",", [:global, :trim])) end defp find_latest_eligible_version(entries) do elixir_version = Version.parse!(System.version()) entries |> Enum.reverse() |> Enum.find_value(&find_version(&1, elixir_version)) end defp find_version([hex_version, _digest | compatible_versions], elixir_version) do if Enum.find(compatible_versions, &(Version.compare(&1, elixir_version) != :gt)) do hex_version end end # Treat missing as latest defp version_latest(nil), do: :latest defp version_latest(hex_version) do if Version.compare(hex_version, Hex.version()) == :gt do {:version, hex_version} else :latest end end defp do_verify(body, public_key, repo) do unless public_key do Mix.raise( "No public key stored for #{repo}. Either install a public " <> "key with `mix hex.repo` or disable the registry " <> "verification check by setting `HEX_UNSAFE_REGISTRY=1`." ) end case :mix_hex_registry.decode_and_verify_signed(body, public_key) do {:ok, payload} -> payload {:error, :unverified} -> Mix.raise( "Could not verify authenticity of fetched registry file. " <> "This may happen because a proxy or some entity is " <> "interfering with the download or because you don't have a " <> "public key to verify the registry.\n\nYou may try again " <> "later or check if a new public key has been released " <> public_key_message(repo) ) {:error, :bad_key} -> Mix.raise("invalid public key") end end defp public_key_message("hexpm:" <> _), do: "on our public keys page: #{@public_keys_html}" defp public_key_message("hexpm"), do: "on our public keys page: #{@public_keys_html}" defp public_key_message(repo), do: "for repo #{repo}" def decode_package(body, repo, package) do repo = repo_name(repo) if Hex.State.fetch!(:no_verify_repo_origin) do {:ok, releases} = :mix_hex_registry.decode_package(body, :no_verify, :no_verify) releases else case :mix_hex_registry.decode_package(body, repo, package) do {:ok, releases} -> outer_checksum? = Enum.all?(releases, &Map.has_key?(&1, :outer_checksum)) if not outer_checksum? and Hex.Server.should_warn_registry_version?() do Hex.Shell.warn( "Fetched old registry record version from repo #{repo}. The " <> "repository you are using should update to include the new :outer_checksum field" ) end releases {:error, :unverified} -> Mix.raise( "Fetched deprecated registry record version from repo #{repo}. For security " <> "reasons this registry version is no longer supported. The repository " <> "you are using should update to fix the security reason. Set " <> "HEX_NO_VERIFY_REPO_ORIGIN=1 to disable this check." ) end end end defp split_repo_name(name) do String.split(name, ":", parts: 2) end defp repo_name(name) do name |> split_repo_name() |> List.last() end end hex-2.0.6/lib/hex/scm.ex000066400000000000000000000276671437023760000150010ustar00rootroot00000000000000defmodule Hex.SCM do alias Hex.Registry.Server, as: Registry @moduledoc false @behaviour Mix.SCM @packages_dir "packages" @request_timeout 60_000 @fetch_timeout @request_timeout * 2 def fetchable? do true end def format(_opts) do "Hex package" end def format_lock(opts) do case Hex.Utils.lock(opts[:lock]) do %{outer_checksum: <>, repo: "hexpm"} = lock -> "#{lock.version} (#{lock.name}) #{checksum}" %{outer_checksum: <>} = lock -> "#{lock.version} (#{lock.repo}/#{lock.name}) #{checksum}" %{outer_checksum: nil, repo: "hexpm"} = lock -> "#{lock.version} (#{lock.name}) " <> ~s("Checksum missing in old lock, run mix deps.get to update") %{outer_checksum: nil} = lock -> "#{lock.version} (#{lock.repo}/#{lock.name}) " <> ~s("Checksum missing in old lock, run mix deps.get to update") nil -> nil end end def accepts_options(name, opts) do opts |> organization_to_repo() |> Keyword.put_new(:hex, name) |> Keyword.update(:repo, "hexpm", &(&1 || "hexpm")) |> Keyword.update!(:hex, &to_string/1) |> Keyword.update!(:repo, &to_string/1) end defp organization_to_repo(opts) do case Keyword.fetch(opts, :organization) do {:ok, org} -> opts |> Keyword.delete(:organization) |> Keyword.put(:repo, "hexpm:#{org}") :error -> opts end end def checked_out?(opts) do File.dir?(opts[:dest]) end def lock_status(opts) do case Hex.Utils.lock(opts[:lock]) do %{} = lock -> lock_status( opts[:dest], lock.name, lock.version, lock.inner_checksum, lock.outer_checksum, lock.repo ) nil -> :mismatch end end defp lock_status(dest, name, version, inner_checksum, outer_checksum, repo) do case File.read(Path.join(dest, ".hex")) do {:ok, file} -> case parse_manifest(file) do {:ok, manifest} -> match? = manifest.name == name and manifest.version == version and manifest.inner_checksum == inner_checksum and (is_nil(manifest.outer_checksum) or is_nil(outer_checksum) or manifest.outer_checksum == outer_checksum) and manifest.repo == repo if match?, do: :ok, else: :mismatch _ -> :mismatch end {:error, _} -> :mismatch end end def equal?(opts1, opts2) do opts1[:hex] == opts2[:hex] and opts1[:repo] == opts2[:repo] end def managers(opts) do case Hex.Utils.lock(opts[:lock]) do %{managers: managers} -> managers || [] nil -> [] end end def update(opts) do Registry.open() lock = Hex.Utils.lock(opts[:lock]) |> ensure_lock(opts) name = opts[:hex] dest = opts[:dest] repo = opts[:repo] || "hexpm" path = cache_path(repo, name, lock.version) case Hex.Parallel.await(:hex_fetcher, {:tarball, repo, name, lock.version}, @fetch_timeout) do {:ok, :cached} -> Hex.Shell.debug(" Using locally cached package (#{path})") {:ok, :offline} -> Hex.Shell.debug(" [OFFLINE] Using locally cached package (#{path})") {:ok, :new} -> tarball_url = tarball_url(repo, name, lock.version) Hex.Shell.debug(" Fetched package (#{tarball_url})") {:error, reason} -> Hex.Shell.error(reason) unless File.exists?(path) do tarball_url = tarball_url(repo, name, lock.version) Mix.raise("Package fetch failed and no cached copy available (#{tarball_url})") end Hex.Shell.info(" Fetch failed. Using locally cached package (#{path})") end File.rm_rf!(dest) registry_inner_checksum = Registry.inner_checksum(repo, to_string(name), lock.version) registry_outer_checksum = Registry.outer_checksum(repo, to_string(name), lock.version) %{ inner_checksum: tarball_inner_checksum, outer_checksum: tarball_outer_checksum, metadata: meta } = try do Hex.Tar.unpack!(path, dest) rescue exception -> require Hex.Stdlib stacktrace = Hex.Stdlib.stacktrace() File.rm(path) reraise(exception, stacktrace) end if tarball_inner_checksum != registry_inner_checksum do File.rm(path) raise("Checksum mismatch against registry (inner)") end if tarball_outer_checksum != registry_outer_checksum do File.rm(path) raise("Checksum mismatch against registry (outer)") end build_tools = guess_build_tools(meta) managers = build_tools |> Enum.map(&String.to_atom/1) |> Enum.sort() manifest = encode_manifest( name, lock.version, lock.inner_checksum, lock.outer_checksum, repo, managers ) File.write!(Path.join(dest, ".hex"), manifest) if Hex.Sponsor.get_link(dest) != nil do Hex.State.put(:print_sponsored_tip, true) end deps = lock.deps |> Enum.map(fn {dep, req, opts} -> {dep, req, Keyword.update!(opts, :hex, &String.to_atom/1)} end) |> Enum.sort() {:hex, String.to_atom(lock.name), lock.version, lock.inner_checksum, managers, deps, lock.repo, lock.outer_checksum} end def checkout(opts) do # For checkout (deps.get) it's important the lock is not modified in the parts of # the lock entries that actually locks the dependency. Those entries are the package repo, # name, version and checksum. We have additional entries that describe the dependency, # the managers and the deps, these are used for optimizations such as avoiding # loading the `mix.exs` for dependencies. # # We need to retrieve the managers in the SCM because the RemoteConverger, where # the lock is initially is built does not have this information. # # Here we update the lock entry with additional information but make sure we only # change the lock when the dependency is being updated or changed in some way. fetched_lock = update(opts) maybe_use_fetched_lock(opts[:lock], fetched_lock) end defp maybe_use_fetched_lock(current_lock, fetched_lock) do case Hex.Utils.lock(current_lock) do %{managers: []} -> fetched_lock _ -> current_lock end end @build_tools [ {"mix.exs", "mix"}, {"rebar.config", "rebar"}, {"rebar", "rebar"}, {"Makefile", "make"}, {"Makefile.win", "make"} ] def guess_build_tools(%{"build_tools" => tools}) do if tools do Enum.uniq(tools) else [] end end def guess_build_tools(meta) do base_files = (meta["files"] || []) |> Enum.filter(&(Path.dirname(&1) == ".")) |> MapSet.new() Enum.flat_map(@build_tools, fn {file, tool} -> if file in base_files do [tool] else [] end end) |> Enum.uniq() end defp ensure_lock(nil, opts) do Mix.raise( "The lock is missing for package #{opts[:hex]}. This could be " <> "because another package has configured the application name " <> "for the dependency incorrectly. Verify with the maintainer of " <> "the parent application" ) end defp ensure_lock(lock, _opts), do: lock def parse_manifest(file) do case :erlang.binary_to_term(file) do {{:hex, 1, _}, map} -> {:ok, add_outer_checksum(map)} {{:hex, 2, _}, map} -> {:ok, map} _other -> :error end rescue ArgumentError -> {:ok, parse_old_manifest(file)} end defp add_outer_checksum(%{outer_checksum: _} = map), do: map defp add_outer_checksum(map), do: Map.put(map, :outer_checksum, nil) defp parse_old_manifest(file) do lines = file |> String.trim() |> String.split("\n") case lines do [first] -> destructure [name, version, inner_checksum, repo], String.split(first, ",") %{ name: name, version: version, inner_checksum: inner_checksum, outer_checksum: nil, repo: repo, managers: [] } [first, managers] -> managers = managers |> String.split(",") |> Enum.map(&String.to_atom/1) destructure [name, version, inner_checksum, repo], String.split(first, ",") %{ name: name, version: version, inner_checksum: inner_checksum, outer_checksum: nil, repo: repo, managers: managers } end end defp encode_manifest(name, version, inner_checksum, outer_checksum, repo, managers) do map = %{ name: name, version: version, inner_checksum: inner_checksum, outer_checksum: outer_checksum, repo: repo, managers: managers || [] } :erlang.term_to_binary({{:hex, 2, 0}, map}) end def prefetch(lock) do fetch = fetch_from_lock(lock) Enum.each(fetch, fn {repo, package, version} -> Hex.Parallel.run(:hex_fetcher, {:tarball, repo || "hexpm", package, version}, fn -> fetch(repo, package, version) end) end) end defp fetch_from_lock(lock) do deps_path = Mix.Project.deps_path() Enum.flat_map(lock, fn {app, info} -> case Hex.Utils.lock(info) do %{name: name, version: version, repo: repo} -> dest = Path.join(deps_path, "#{app}") case lock_status(dest: dest, lock: info) do :ok -> [] :mismatch -> [{repo, name, version}] :outdated -> [{repo, name, version}] end nil -> [] end end) end defp tarball_url(repo, package, version) do filename = "#{package}-#{version}.tar" prune_uri_userinfo(Hex.Repo.get_repo(repo).url <> "/tarballs/#{filename}") end defp prune_uri_userinfo(url) do case URI.parse(url) do %URI{userinfo: nil} -> url uri -> URI.to_string(%{uri | userinfo: "******"}) end end def cache_path(repo, package, version) do repo = Hex.Utils.windows_repo_path_fix(repo) filename = "#{package}-#{version}.tar" Path.join([Hex.State.fetch!(:cache_home), @packages_dir, repo, filename]) end def fetch(repo, package, version) do if Hex.State.fetch!(:offline) do {:ok, :offline} else outer_checksum = Registry.outer_checksum(repo, package, version) path = cache_path(repo, package, version) case Hex.Tar.outer_checksum(path) do {:ok, ^outer_checksum} -> {:ok, :cached} {:ok, other_outer_checksum} -> Hex.Shell.warn(""" Checksum mismatch between registry and the cached package for #{package} #{version} Registry checksum: #{Base.encode16(outer_checksum, case: :lower)} Package checksum: #{Base.encode16(other_outer_checksum, case: :lower)} This may happen when the previously cached package got re-published, but it may also indicate a security issue so verify the new package. Re-fetching...\ """) do_fetch(path, repo, package, version) {:error, _reason} -> do_fetch(path, repo, package, version) end end end defp do_fetch(path, repo, package, version) do case Hex.Repo.get_tarball(repo, package, version) do {:ok, {200, body, _headers}} -> File.mkdir_p!(Path.dirname(path)) File.write!(path, body) {:ok, :new} {:ok, {304, _body, _headers}} -> {:ok, :cached} {:ok, {code, _body, _headers}} -> {:error, "Request failed (#{code})"} {:error, :timeout} -> reason = [ "Request failed (:timeout)", :reset, "\nIf this happens consistently, adjust your concurrency and timeout settings:", "\n\n HEX_HTTP_CONCURRENCY=1 HEX_HTTP_TIMEOUT=120 mix deps.get" ] {:error, reason} {:error, reason} -> {:error, "Request failed (#{inspect(reason)})"} end end end hex-2.0.6/lib/hex/server.ex000066400000000000000000000025121437023760000155030ustar00rootroot00000000000000defmodule Hex.Server do @moduledoc false use GenServer @name __MODULE__ def start_link(opts) do opts = Keyword.put_new(opts, :name, @name) GenServer.start_link(__MODULE__, [], opts) end def reset() do GenServer.call(@name, :reset) end def should_warn_lock_version?(name \\ @name) do GenServer.call(name, :should_warn_lock_version?) end def should_warn_registry_version?(name \\ @name) do GenServer.call(name, :should_warn_registry_version?) end def init([]) do {:ok, state()} end def handle_call(:reset, _from, _state) do {:reply, :ok, state()} end def handle_call(:should_warn_lock_version?, _from, %{warned_lock_version: false} = state) do {:reply, true, %{state | warned_lock_version: true}} end def handle_call(:should_warn_lock_version?, _from, %{warned_lock_version: true} = state) do {:reply, false, state} end def handle_call( :should_warn_registry_version?, _from, %{warned_registry_version: false} = state ) do {:reply, true, %{state | warned_registry_version: true}} end def handle_call(:should_warn_registry_version?, _from, %{warned_registry_version: true} = state) do {:reply, false, state} end defp state() do %{ warned_lock_version: false, warned_registry_version: false } end end hex-2.0.6/lib/hex/shell.ex000066400000000000000000000056651437023760000153200ustar00rootroot00000000000000defmodule Hex.Shell do @moduledoc false def info(output) do validate_output!(output) Mix.shell().info(output) end def warn(output) do validate_output!(output) Mix.shell().info([IO.ANSI.yellow(), output, IO.ANSI.reset()]) end def error(output) do validate_output!(output) Mix.shell().error(output) end def debug(output) do validate_output!(output) if Mix.debug?() do info(output) end end def yes?(output) do validate_output!(output) Mix.shell().yes?(output) end def prompt(output) do validate_output!(output) Mix.shell().prompt(output) end def format(output, emit? \\ Hex.Shell.ansi_enabled?()) do IO.ANSI.format(output, emit?) end def cmd(command, options \\ [], callback) when is_function(callback, 1) do callback = if Keyword.get(options, :quiet, false) do fn x -> x end else callback end env = validate_env(Keyword.get(options, :env, [])) args = if Keyword.get(options, :stderr_to_stdout, true) do [:stderr_to_stdout] else [] end opts = [:stream, :binary, :exit_status, :hide, :use_stdio, {:env, env} | args] port = Port.open({:spawn, shell_command(command)}, opts) port_read(port, callback) end defp port_read(port, callback) do receive do {^port, {:data, data}} -> _ = callback.(data) port_read(port, callback) {^port, {:exit_status, status}} -> status end end # Finding shell command logic from :os.cmd in OTP # https://github.com/erlang/otp/blob/8deb96fb1d017307e22d2ab88968b9ef9f1b71d0/lib/kernel/src/os.erl#L184 defp shell_command(command) do case :os.type() do {:unix, _} -> command = command |> String.replace("\"", "\\\"") |> String.to_charlist() ~c"sh -c \"" ++ command ++ ~c"\"" {:win32, osname} -> command = ~c"\"" ++ String.to_charlist(command) ++ ~c"\"" case {System.get_env("COMSPEC"), osname} do {nil, :windows} -> ~c"command.com /s /c " ++ command {nil, _} -> ~c"cmd /s /c " ++ command {cmd, _} -> ~c"#{cmd} /s /c " ++ command end end end defp validate_env(enum) do Enum.map(enum, fn {k, nil} -> {String.to_charlist(k), false} {k, v} -> {String.to_charlist(k), String.to_charlist(v)} other -> raise ArgumentError, "invalid environment key-value #{inspect(other)}" end) end if Mix.env() == :test do defp validate_output!(output) do formatted_output = output |> IO.ANSI.format_fragment(true) |> IO.chardata_to_string() unless String.printable?(formatted_output) do raise ArgumentError, "string not printable" end end else defp validate_output!(_output), do: :ok end if Mix.env() == :test do def ansi_enabled?(), do: false else def ansi_enabled?(), do: IO.ANSI.enabled?() end end hex-2.0.6/lib/hex/shell/000077500000000000000000000000001437023760000147465ustar00rootroot00000000000000hex-2.0.6/lib/hex/shell/process.ex000066400000000000000000000031641437023760000167660ustar00rootroot00000000000000defmodule Hex.Shell.Process do @moduledoc false @behaviour Mix.Shell def flush(callback \\ fn x -> x end) do receive do {:mix_shell, _, _} = message -> callback.(message) flush(callback) {:mix_shell_input, _, _} = message -> callback.(message) flush(callback) after 0 -> :done end end def print_app do if name = Mix.Shell.printable_app_name() do send(process(), {:mix_shell, :info, ["==> #{name}"]}) end end def info(message) do print_app() send(process(), {:mix_shell, :info, [format(message)]}) :ok end def error(message) do print_app() send(process(), {:mix_shell, :error, [format(message)]}) :ok end defp format(message) do message |> IO.ANSI.format(false) |> IO.iodata_to_binary() end def prompt(message) do print_app() send(process(), {:mix_shell, :prompt, [message]}) receive do {:mix_shell_input, :prompt, response} -> response after 0 -> raise "no shell process input given for prompt/1" end end def yes?(message, _options \\ []) do print_app() send(process(), {:mix_shell, :yes?, [message]}) receive do {:mix_shell_input, :yes?, response} -> response after 0 -> raise "no shell process input given for yes?/1" end end def cmd(command, opts \\ []) do print_app? = Keyword.get(opts, :print_app, true) Hex.Shell.cmd(command, opts, fn data -> if print_app?, do: print_app() send(process(), {:mix_shell, :run, [data]}) end) end defp process() do Hex.State.fetch!(:shell_process) || self() end end hex-2.0.6/lib/hex/solver.ex000066400000000000000000000051731437023760000155150ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver do _ = """ A version solver. """ @type dependency() :: %{ repo: repo(), name: package(), constraint: constraint(), optional: optional(), label: label() } @type locked() :: %{ repo: repo(), name: package(), version: Version.t(), label: label() } @type repo() :: String.t() | nil @type package() :: String.t() @type label() :: String.t() @type optional() :: boolean() @type result() :: %{package() => {Version.t(), repo()}} @opaque constraint() :: Hex.Solver.Requirement.t() alias Hex.Solver.{Failure, Requirement, Solver} @doc """ Runs the version solver. Takes a `Hex.Solver.Registry` implementation, a list of root dependencies, a list of locked package versions, and a list of packages that are overridden by the root dependencies. Locked dependencies are treated as optional dependencies with a single version as their constraint. The overrides are a set of labels. If a dependency with a matching label is declared the solver will ignore that dependency unless it's a root dependency. Returns a map of packages and their selected versions or a human readable explanation of why a solution could not be found. ## Options * `:ansi` - If `true` adds ANSI formatting to the failure message (Default: `false`) """ @spec run(module(), [dependency()], [locked()], [label()], ansi: boolean()) :: {:ok, result()} | {:error, String.t()} def run(registry, dependencies, locked, overrides, opts \\ []) do case Solver.run(registry, dependencies, locked, overrides) do {:ok, solution} -> {:ok, Map.drop(solution, ["$root", "$lock"])} {:error, incompatibility} -> {:error, Failure.write(incompatibility, opts)} end end @doc """ Parses or converts a SemVer version or Elixir version requirement to an internal solver constraint that can be returned by the `Hex.Solver.Registry` or passed to `Hex.Solver.run/4`. """ @spec parse_constraint(String.t() | Version.t() | Version.Requirement.t()) :: {:ok, constraint()} | :error def parse_constraint(string) do Requirement.to_constraint(string) end @doc """ Parses or converts a SemVer version or Elixir version requirement to an internal solver constraint that can be returned by the `Hex.Solver.Registry` or passed to `Hex.Solver.run/4`. """ @spec parse_constraint!(String.t() | Version.t() | Version.Requirement.t()) :: constraint() def parse_constraint!(string) do Requirement.to_constraint!(string) end end hex-2.0.6/lib/hex/solver/000077500000000000000000000000001437023760000151515ustar00rootroot00000000000000hex-2.0.6/lib/hex/solver/assignment.ex000066400000000000000000000020551437023760000176610ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Assignment do @moduledoc false alias Hex.Solver.{Assignment, Term} defstruct term: nil, decision_level: nil, index: nil, cause: nil def intersect(%Assignment{} = left, %Assignment{} = right) do %{left | term: Term.intersect(left.term, right.term)} end def decision?(%Assignment{cause: cause}) do cause == nil end def to_string(%Assignment{term: term}) do Kernel.to_string(term) end defimpl String.Chars do defdelegate to_string(assignment), to: Hex.Solver.Assignment end defimpl Inspect do def inspect( %{ term: term, decision_level: decision_level, index: index, cause: cause }, _opts ) do "#Assignment" end defp maybe(_prefix, nil), do: "" defp maybe(prefix, value), do: "#{prefix}#{value}" end end hex-2.0.6/lib/hex/solver/constraint.ex000066400000000000000000000006001437023760000176670ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defprotocol Hex.Solver.Constraint do @moduledoc false def any?(constraint) def empty?(constraint) def allows?(constraint, version) def allows_any?(left, right) def allows_all?(left, right) def difference(left, right) def intersect(left, right) def union(left, right) def compare(left, right) end hex-2.0.6/lib/hex/solver/constraints/000077500000000000000000000000001437023760000175205ustar00rootroot00000000000000hex-2.0.6/lib/hex/solver/constraints/empty.ex000066400000000000000000000021231437023760000212120ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Constraints.Empty do @moduledoc false use Hex.Solver.Constraints.Impl alias Hex.Solver.Constraint alias Hex.Solver.Constraints.Empty defstruct [] def any?(%Empty{}), do: false def empty?(%Empty{}), do: true def allows?(%Empty{}, %Version{}), do: false def allows_any?(%Empty{}, constraint), do: Constraint.empty?(constraint) def allows_all?(%Empty{}, constraint), do: Constraint.empty?(constraint) def difference(%Empty{}, _constraint), do: %Empty{} def intersect(%Empty{}, _constraint), do: %Empty{} def union(%Empty{}, constraint), do: constraint def compare(left, right) do raise FunctionClauseError, module: __MODULE__, function: :compare, arity: 2, kind: :def, args: [left, right], clauses: [] end def to_string(%Empty{}) do "empty" end defimpl String.Chars do defdelegate to_string(empty), to: Hex.Solver.Constraints.Empty end defimpl Inspect do def inspect(_, _opts) do "#Empty<>" end end end hex-2.0.6/lib/hex/solver/constraints/impl.ex000066400000000000000000000022711437023760000210210ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Constraints.Impl do @moduledoc false defmacro __using__(opts) do for = Keyword.get(opts, :for, __CALLER__.module) quote do defimpl Hex.Solver.Constraint, for: unquote(for) do def any?(constraint), do: unquote(__CALLER__.module).any?(constraint) def empty?(constraint), do: unquote(__CALLER__.module).empty?(constraint) def allows?(constraint, version), do: unquote(__CALLER__.module).allows?(constraint, version) def allows_any?(left, right), do: unquote(__CALLER__.module).allows_any?(left, right) def allows_all?(left, right), do: unquote(__CALLER__.module).allows_all?(left, right) def difference(left, right), do: unquote(__CALLER__.module).difference(left, right) def intersect(left, right), do: unquote(__CALLER__.module).intersect(left, right) def union(left, right), do: unquote(__CALLER__.module).union(left, right) def compare(left, right), do: unquote(__CALLER__.module).compare(left, right) end end end end hex-2.0.6/lib/hex/solver/constraints/range.ex000066400000000000000000000272421437023760000211610ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Constraints.Range do @moduledoc false use Hex.Solver.Constraints.Impl alias Hex.Solver.Constraint alias Hex.Solver.Constraints.{Empty, Range, Union, Util, Version} # %Range{min: nil, max: nil} allows any version. # %Range{min: min, max: max, include_min: true, include_max: true} # when min == max is a single version. defstruct min: nil, max: nil, include_min: false, include_max: false def valid?(%Range{min: min, max: max, include_min: include_min, include_max: include_max}) do case version_compare(min, max) do :lt -> true :eq -> include_min and include_max :gt -> false end end def any?(%Range{min: nil, max: nil}), do: true def any?(%Range{}), do: false def empty?(%Range{}), do: false def allows?(%Range{} = range, %Elixir.Version{} = version) do compare_min = version_compare(range.min, version) if compare_min == :lt or (compare_min == :eq and range.include_min) do compare_max = version_compare(version, range.max) compare_max == :lt or (compare_max == :eq and range.include_max) else false end end def allows_all?(%Range{}, %Empty{}), do: true def allows_all?(%Range{} = range, %Elixir.Version{} = version), do: allows?(range, version) def allows_all?(%Range{} = left, %Range{} = right) do not allows_lower?(right, left) and not allows_higher?(right, left) end def allows_all?(%Range{} = range, %Union{ranges: ranges}) do Enum.all?(ranges, &allows_all?(range, &1)) end def allows_any?(%Range{}, %Empty{}), do: true def allows_any?(%Range{} = range, %Elixir.Version{} = version), do: allows?(range, version) def allows_any?(%Range{} = left, %Range{} = right) do not strictly_lower?(right, left) and not strictly_higher?(right, left) end def allows_any?(%Range{} = range, %Union{ranges: ranges}) do Enum.any?(ranges, &allows_any?(range, &1)) end def allows_lower?(%Range{} = left, %Range{} = right) do cond do left.min == nil -> right.min != nil right.min == nil -> false true -> case Version.compare(left.min, right.min) do :lt -> true :gt -> false :eq -> left.include_min and not right.include_min end end end def allows_higher?(%Range{} = left, %Range{} = right) do cond do left.max == nil -> right.max != nil right.max == nil -> false true -> case Version.compare(left.max, right.max) do :lt -> false :gt -> true :eq -> left.include_max and not right.include_max end end end def strictly_lower?(%Elixir.Version{} = left, %Elixir.Version{} = right) do Version.compare(left, right) == :lt end def strictly_lower?(%Range{} = range, %Elixir.Version{} = version) do range.max != nil and Version.compare(range.max, version) == :lt end def strictly_lower?(%Elixir.Version{} = version, %Range{} = range) do range.min != nil and Version.compare(version, range.min) == :lt end def strictly_lower?(%Range{} = left, %Range{} = right) do if left.max == nil or right.min == nil do false else case Version.compare(left.max, right.min) do :lt -> true :gt -> false :eq -> not left.include_max or not right.include_min end end end def strictly_higher?(left, right) do strictly_lower?(right, left) end def difference(%Range{} = range, %Empty{}) do range end def difference(%Range{} = range, %Elixir.Version{} = version) do cond do not allows?(range, version) -> range range.min == version -> %{range | include_min: false} range.max == version -> %{range | include_max: false} true -> %Union{ ranges: [ %{range | max: version, include_max: false}, %{range | min: version, include_min: false} ] } end end def difference(%Range{} = left, %Range{} = right) do if allows_any?(left, right) do before_range = cond do not allows_lower?(left, right) -> nil left.min == right.min -> true = left.include_min and not right.include_min true = left.min != nil left.min true -> %Range{ min: left.min, max: right.min, include_min: left.include_min, include_max: not right.include_min } end after_range = cond do not allows_higher?(left, right) -> nil left.max == right.max -> true = left.include_max and not right.include_max true = left.max != nil left.max true -> %Range{ min: right.max, max: left.max, include_min: not right.include_max, include_max: left.include_max } end cond do before_range == nil and after_range == nil -> %Empty{} before_range == nil -> after_range after_range == nil -> before_range true -> %Union{ranges: [before_range, after_range]} end else left end end def difference(%Range{} = range, %Union{} = union) do {range, ranges} = Enum.reduce_while(union.ranges, {range, []}, fn union_range, {range, acc} -> cond do strictly_lower?(union_range, range) -> {:cont, {range, acc}} strictly_higher?(union_range, range) -> {:halt, {range, acc}} true -> case Constraint.difference(range, union_range) do %Empty{} -> {:halt, {range, %Empty{}}} %Union{ranges: [first, last]} -> {:cont, {last, [first | acc]}} constraint -> {:cont, {constraint, acc}} end end end) case ranges do %Empty{} -> %Empty{} [] -> range _ -> %Union{ranges: Enum.reverse([range | ranges])} end end def intersect(%Range{}, %Empty{}) do %Empty{} end def intersect(%Range{} = range, %Elixir.Version{} = version) do if allows?(range, version) do version else %Empty{} end end def intersect(%Range{} = left, %Range{} = right) do if strictly_lower?(left, right) or strictly_lower?(right, left) do %Empty{} else {intersect_min, intersect_include_min} = if allows_lower?(left, right) do {right.min, right.include_min} else {left.min, left.include_min} end {intersect_max, intersect_include_max} = if allows_higher?(left, right) do {right.max, right.include_max} else {left.max, left.include_max} end cond do intersect_min == nil and intersect_max == nil -> # Open range %Range{} intersect_min == intersect_max -> # There must be overlap since we already checked none of # the ranges are strictly lower true = intersect_include_min and intersect_include_max intersect_min true -> %Range{ min: intersect_min, max: intersect_max, include_min: intersect_include_min, include_max: intersect_include_max } end end end def intersect(%Range{} = range, %Union{} = union) do Union.intersect(union, range) end def union(%Range{} = range, %Empty{}) do range end def union(%Range{} = range, %Elixir.Version{} = version) do if allows?(range, version) do range else case range do %Range{min: ^version} -> %{range | include_min: true} %Range{max: ^version} -> %{range | include_max: true} _ -> Util.union([range, version]) end end end def union(%Range{} = left, %Range{} = right) do if not edges_touch?(left, right) and not Range.allows_any?(left, right) do Util.union([left, right]) else min = if allows_lower?(left, right), do: left, else: right max = if allows_higher?(left, right), do: left, else: right %Range{ min: min.min, max: max.max, include_min: min.include_min, include_max: max.include_max } end end def union(%Range{} = range, %Union{} = union) do Util.union([range, union]) end defp edges_touch?(left, right) do (left.max != nil and left.max == right.min and (left.include_max or right.include_min)) or (left.min != nil and left.min == right.max and (left.include_min or right.include_max)) end def compare(%Range{min: min, include_min: include_min}, %Elixir.Version{} = version) do if min == nil do :lt else case Version.compare(min, version) do :eq when include_min -> :eq :eq -> :gt :lt -> :lt :gt -> :gt end end end def compare(%Range{} = left, %Range{} = right) do cond do left.min == nil and right.min == nil -> :eq left.min == nil -> :lt right.min == nil -> :gt true -> left_include_min = left.include_min right_include_min = right.include_min case Version.compare(left.min, right.min) do :eq when left_include_min == right_include_min -> :eq :eq when left_include_min -> :lt :eq when right_include_min -> :gt :lt -> :lt :gt -> :gt end end end def compare(%Range{} = left, %Union{ranges: [right | _]}) do compare(left, right) end def single_version?(%Range{min: min, max: max, include_min: true, include_max: true}) do min == max end def single_version?(%Range{}) do false end defp version_compare(nil, _right), do: :lt defp version_compare(_left, nil), do: :lt defp version_compare(left, right), do: Version.compare(left, right) def normalize(%Range{min: version, max: version, include_min: true, include_max: true}), do: version def normalize(%Range{} = range), do: range def normalize(%Elixir.Version{} = version), do: version def to_string(%Range{min: nil, max: nil}) do "any" end def to_string(%Range{min: version, max: version, include_min: true, include_max: true}) do Kernel.to_string(version) end def to_string(%Range{ min: %Elixir.Version{major: min_major, minor: min_minor, patch: 0, pre: pre}, max: %Elixir.Version{major: max_major, minor: 0, patch: 0, pre: [0]}, include_min: true, include_max: false }) when min_major + 1 == max_major do "~> #{min_major}.#{min_minor}#{pre_to_string(pre)}" end def to_string(%Range{ min: %Elixir.Version{major: min_major, minor: min_minor, patch: min_patch, pre: pre}, max: %Elixir.Version{major: max_major, minor: max_minor, patch: 0, pre: [0]}, include_min: true, include_max: false }) when min_major == max_major and min_minor + 1 == max_minor do "~> #{min_major}.#{min_minor}.#{min_patch}#{pre_to_string(pre)}" end def to_string(%Range{min: min, max: max, include_min: include_min, include_max: include_max}) do min_string = if min, do: ">#{include(include_min)} #{min}" max_string = if max, do: "<#{include(include_max)} #{max}" if min_string && max_string do "#{min_string} and #{max_string}" else min_string || max_string end end defp pre_to_string([]), do: "" defp pre_to_string(pre), do: "-" <> Enum.join(pre, ".") defp include(true), do: "=" defp include(false), do: "" defimpl String.Chars do defdelegate to_string(range), to: Hex.Solver.Constraints.Range end defimpl Inspect do def inspect(range, _opts) do "#Range<#{range}>" end end end hex-2.0.6/lib/hex/solver/constraints/union.ex000066400000000000000000000117441437023760000212150ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Constraints.Union do @moduledoc false use Hex.Solver.Constraints.Impl alias Hex.Solver.Constraint alias Hex.Solver.Constraints.{Empty, Range, Union, Util, Version} # We will always work under the following assumptions for unions: # * Minimum of two elements # * Only %Range{} and %Version{}, no %Empty{} # * No "any range" (%Range{min: nil, max: nil}) # * Elements sorted by their minimum version # * Ranges do not overlap defstruct ranges: [] def empty?(%Union{}), do: false def any?(%Union{}), do: false def allows?(%Union{ranges: ranges}, %Elixir.Version{} = version) do Enum.any?(ranges, &Constraint.allows?(&1, version)) end def allows_all?(%Union{ranges: left}, %Union{ranges: right}) do do_allows_all?(left, right) end def allows_all?(%Union{ranges: left}, right) do do_allows_all?(left, [right]) end # We can recurse left and right together since they are # sorted on minimum version defp do_allows_all?([left | lefts], [right | rights]) do if Constraint.allows_all?(left, right) do do_allows_all?([left | lefts], rights) else do_allows_all?(lefts, [right | rights]) end end defp do_allows_all?(_lefts, []), do: true defp do_allows_all?([], _rights), do: false def allows_any?(%Union{}, %Empty{}), do: true def allows_any?(%Union{} = left, right) do do_allows_any?(to_ranges(left), to_ranges(right)) end # We can recurse left and right together since they are # sorted on minimum version defp do_allows_any?([left | lefts], [right | rights]) do cond do Range.allows_any?(left, right) -> true # Move forward with the range with the lower max value Range.allows_higher?(right, left) -> do_allows_any?(lefts, [right | rights]) true -> do_allows_any?([left | lefts], rights) end end defp do_allows_any?(_lefts, _rights), do: false def difference(%Union{} = left, right) do do_difference(to_ranges(left), to_ranges(right), []) end defp do_difference(lefts, [], acc) do # If there are no more "right" ranges, none of the rest needs to # be subtracted and can be added as-is Util.from_list(Enum.reverse(acc) ++ lefts) end defp do_difference([], _rights, acc) do Util.from_list(Enum.reverse(acc)) end defp do_difference([left | lefts], [right | rights], acc) do cond do Range.strictly_lower?(right, left) -> do_difference([left | lefts], rights, acc) Range.strictly_higher?(right, left) -> do_difference(lefts, [right | rights], [left | acc]) true -> # Left and right overlaps case maybe_to_range(Range.difference(left, right)) do %Union{ranges: [first, last]} -> # If right splits left in half, we only need to check future ranges # against the latter half do_difference([last | lefts], rights, [first | acc]) %Range{} = range -> # Move the constraint with the lower max value forward. Ensures # we keep both lists in sync as much as possible and that large # ranges have a chance to subtract or be subtracted of multiple # small ranges if Range.allows_higher?(range, right) do do_difference([range | lefts], rights, acc) else do_difference(lefts, [right | rights], [range | acc]) end %Empty{} -> do_difference(lefts, [right | rights], acc) end end end def intersect(%Union{} = left, right) do do_intersect(to_ranges(left), to_ranges(right), []) end defp do_intersect([left | lefts], [right | rights], acc) do acc = case Constraint.intersect(left, right) do %Empty{} -> acc intersection -> [intersection | acc] end if Range.allows_higher?(right, left) do do_intersect(lefts, [right | rights], acc) else do_intersect([left | lefts], rights, acc) end end defp do_intersect(_lefts, [], acc), do: Util.from_list(Enum.reverse(acc)) defp do_intersect([], _rights, acc), do: Util.from_list(Enum.reverse(acc)) def union(%Union{} = left, right) do Util.union([left, right]) end def compare(%Union{ranges: [range | _]}, right) do Constraint.compare(range, right) end defp to_ranges(%Empty{}), do: [] defp to_ranges(%Elixir.Version{} = version), do: [Version.to_range(version)] defp to_ranges(%Range{} = range), do: [range] defp to_ranges(%Union{ranges: ranges}), do: Enum.map(ranges, &Version.to_range/1) defp maybe_to_range(%Elixir.Version{} = version), do: Version.to_range(version) defp maybe_to_range(other), do: other def to_string(%Union{ranges: ranges}) do Enum.map_join(ranges, " or ", &Kernel.to_string/1) end defimpl String.Chars do defdelegate to_string(union), to: Hex.Solver.Constraints.Union end defimpl Inspect do def inspect(union, _opts) do "#Union<#{union}>" end end end hex-2.0.6/lib/hex/solver/constraints/util.ex000066400000000000000000000042751437023760000210430ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Constraints.Util do @moduledoc false alias Hex.Solver.{Constraint, Util} alias Hex.Solver.Constraints.{Empty, Range, Union, Version} def any(), do: %Range{} def from_list([]), do: %Empty{} def from_list([single]), do: Range.normalize(single) def from_list(acc), do: %Union{ranges: Enum.map(acc, &Range.normalize/1)} def union(list) do list = flatten(list) cond do list == [] -> %Empty{} Enum.any?(list, &Constraint.any?/1) -> %Range{} true -> list |> Enum.sort(Util.compare(Constraint)) |> Enum.reduce([], fn constraint, acc -> previous = List.first(acc) cond do acc == [] -> [constraint] not Constraint.allows_any?(previous, constraint) and not adjacent?(previous, constraint) -> [constraint | acc] true -> # Merge this constraint with previous, but only if they touch List.replace_at(acc, 0, Constraint.union(previous, constraint)) end end) |> Enum.reverse() |> from_list() end end defp flatten(list) do Enum.flat_map(list, fn %Union{ranges: ranges} -> ranges %Empty{} -> [] other -> [other] end) end @doc """ Returns `true` if `left` is immediately next to, but not overlapping, `right`. Assumes `left` is lower than `right`. """ def adjacent?(left, right) do left = Version.to_range(left) right = Version.to_range(right) left.max == right.min and ((left.include_max and not right.include_min) or (not left.include_max and right.include_min)) end def from_bounds(%Elixir.Version{} = lower, %Elixir.Version{} = upper) do case Version.compare(lower, upper) do :eq -> lower :lt -> %Range{min: lower, max: upper, include_min: true, include_max: true} end end def from_bounds(%Elixir.Version{} = lower, nil), do: %Range{min: lower, include_min: true} def from_bounds(nil, %Elixir.Version{} = upper), do: %Range{max: upper, include_max: true} def from_bounds(nil, nil), do: %Range{} end hex-2.0.6/lib/hex/solver/constraints/version.ex000066400000000000000000000060421437023760000215450ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Constraints.Version do @moduledoc false use Hex.Solver.Constraints.Impl, for: Version import Kernel, except: [match?: 2] alias Hex.Solver.Constraint alias Hex.Solver.Constraints.{Empty, Range, Union, Util} def any?(%Version{}), do: false def empty?(%Version{}), do: false def allows?(%Version{} = left, %Version{} = right), do: left == right def allows_any?(%Version{}, %Empty{}), do: true def allows_any?(%Version{} = left, right), do: Constraint.allows?(right, left) def allows_all?(%Version{}, %Empty{}) do true end def allows_all?(%Version{} = left, %Version{} = right) do left == right end def allows_all?(%Version{}, %Range{min: nil}) do false end def allows_all?(%Version{}, %Range{max: nil}) do false end def allows_all?(%Version{} = version, %Range{ min: min, max: max, include_min: true, include_max: true }) do version == min and version == max end def allows_all?(%Version{}, %Range{}) do false end def allows_all?(%Version{} = version, %Union{ranges: ranges}) do Enum.all?(ranges, &allows_all?(version, &1)) end def difference(%Version{} = version, constraint) do if Constraint.allows?(constraint, version), do: %Empty{}, else: version end def intersect(%Version{} = version, constraint) do if Constraint.allows?(constraint, version), do: version, else: %Empty{} end def union(%Version{} = version, constraint) do if Constraint.allows?(constraint, version) do constraint else case constraint do %Range{min: ^version} = range -> %{range | include_min: true} %Range{max: ^version} = range -> %{range | include_max: true} _ -> Util.union([version, constraint]) end end end def compare(%Version{} = left, %Version{} = right) do Version.compare(left, right) end def compare(%Version{} = version, %Range{min: min, include_min: include_min}) do if min == nil do :gt else case Version.compare(version, min) do :eq when include_min -> :eq :eq -> :lt :lt -> :lt :gt -> :gt end end end def compare(%Version{} = version, %Union{ranges: [range | _]}) do compare(version, range) end def min(left, right) do case compare(left, right) do :lt -> left :eq -> left :gt -> right end end def max(left, right) do case compare(left, right) do :lt -> right :eq -> left :gt -> left end end def to_range(%Version{} = version) do %Range{min: version, max: version, include_min: true, include_max: true} end def to_range(%Range{} = range) do range end def prioritize(%Version{} = left, %Version{} = right) do do_prioritize(left, right) == :gt end defp do_prioritize(left, right) do cond do left.pre != [] and right.pre == [] -> :lt left.pre == [] and right.pre != [] -> :gt true -> Version.compare(left, right) end end end hex-2.0.6/lib/hex/solver/failure.ex000066400000000000000000000173261437023760000171470ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Failure do @moduledoc false alias Hex.Solver.Incompatibility def write(root, opts \\ []) do derivations = count_derivations(%{}, root) state = state(root, derivations, opts) state = case root.cause do {:conflict, _, _} -> visit(state, root) _ -> write(state, root, false, [ "Because ", Incompatibility.to_string(root, ansi: state.ansi), " version solving failed." ]) end numbers = state.lines |> Enum.map(fn {number, _message} -> number end) |> Enum.filter(&is_integer/1) indent? = numbers != [] indent = if indent?, do: Enum.max_by(numbers, &byte_size(Integer.to_string(&1))) + 3 Enum.map_join(Enum.reverse(state.lines), "\n", fn {number, message} -> if number do "(#{number}) #{message}" else "#{message && indent && String.duplicate(" ", indent)}#{message}" end end) end defp count_derivations(derivations, incompatibility) do case Map.fetch(derivations, incompatibility) do {:ok, value} -> Map.put(derivations, incompatibility, value + 1) :error -> derivations = case incompatibility.cause do {:conflict, conflict, other} -> derivations |> count_derivations(conflict) |> count_derivations(other) _ -> derivations end Map.update(derivations, incompatibility, 1, &(&1 + 1)) end end defp visit(state, incompatibility, conclusion? \\ false) do numbered? = conclusion? or Map.fetch!(state.derivations, incompatibility) > 1 conjunction = if conclusion? or incompatibility == state.root, do: "So,", else: "And" incompatibility_string = Incompatibility.to_string(incompatibility, ansi: state.ansi) {:conflict, conflict, other} = incompatibility.cause case {conflict.cause, other.cause} do {{:conflict, _, _}, {:conflict, _, _}} -> conflict_line = state.line_numbers[conflict] other_line = state.line_numbers[other] single_line_conflict? = single_line?(conflict.cause) single_line_other? = single_line?(other.cause) cond do conflict_line && other_line -> write(state, incompatibility, numbered?, [ "Because ", Incompatibility.to_string_and(conflict, other, left_line: conflict_line, right_line: other_line, ansi: state.ansi ), ", ", incompatibility_string ]) conflict_line || other_line -> {with_line, without_line, line} = if conflict_line do {conflict, other, conflict_line} else {other, conflict, other_line} end state |> visit(without_line) |> write(incompatibility, numbered?, [ conjunction, " because ", Incompatibility.to_string(with_line, ansi: state.ansi), " (#{line}), ", incompatibility_string ]) single_line_conflict? or single_line_other? -> first = if single_line_other?, do: conflict, else: other second = if single_line_other?, do: other, else: conflict state |> visit(first) |> visit(second) |> write(incompatibility, numbered?, ["This, ", incompatibility_string]) true -> state |> visit(conflict, _conclusion? = true) |> add_line() |> visit(other) |> write(incompatibility, numbered?, fn state -> [ conjunction, " because ", Incompatibility.to_string(conflict, ansi: state.ansi), maybe_line(state.line_numbers[conflict]), ", ", incompatibility_string, "." ] end) end {left, right} when elem(left, 0) == :conflict when elem(right, 0) == :conflict -> derived = if match?({:conflict, _, _}, conflict.cause), do: conflict, else: other ext = if match?({:conflict, _, _}, conflict.cause), do: other, else: conflict cond do derived_line = state.line_numbers[derived] -> write(state, incompatibility, numbered?, [ "Because ", Incompatibility.to_string_and(ext, derived, right_line: derived_line, ansi: state.ansi ), ", ", incompatibility_string ]) collapsible?(state, derived) -> {:conflict, derived_conflict, derived_other} = derived.cause collapsed_derived = if match?({:conflict, _, _}, derived_conflict.cause), do: derived_conflict, else: derived_other collapsed_ext = if match?({:conflict, _, _}, derived_conflict.cause), do: derived_other, else: derived_conflict state |> visit(collapsed_derived) |> write(incompatibility, numbered?, [ conjunction, " because ", Incompatibility.to_string_and(collapsed_ext, ext, ansi: state.ansi), ", ", incompatibility_string, "." ]) true -> state |> visit(derived) |> write(incompatibility, numbered?, [ conjunction, " because ", Incompatibility.to_string(ext, ansi: state.ansi), ", ", incompatibility_string, "." ]) end _ -> write(state, incompatibility, numbered?, [ "Because ", Incompatibility.to_string_and(conflict, other, ansi: state.ansi), ", ", incompatibility_string, "." ]) end end defp write(state, incompatibility, numbered?, message) do message = maybe_fun(state, message) if numbered? do number = map_size(state.line_numbers) + 1 %{ state | lines: [{number, message} | state.lines], line_numbers: Map.put(state.line_numbers, incompatibility, number) } else %{state | lines: [{nil, message} | state.lines]} end end defp add_line(state, message \\ nil) do %{state | lines: [{nil, message} | state.lines]} end defp maybe_fun(state, fun) when is_function(fun, 1), do: fun.(state) defp maybe_fun(_state, other), do: other defp maybe_line(nil), do: "" defp maybe_line(line), do: " (#{line})" defp collapsible?( state, %Incompatibility{cause: {:conflict, conflict, other}} = incompatibility ) do complex = if match?({:conflict, _, _}, conflict), do: conflict, else: other cond do state.derivations[incompatibility] > 1 -> false match?({:conflict, _, _}, conflict) and match?({:conflict, _, _}, other) -> false not match?({:conflict, _, _}, conflict) and not match?({:conflict, _, _}, other) -> false true -> not Map.has_key?(state.line_numbers, complex) end end defp single_line?({ :conflict, %Incompatibility{cause: {:conflict, _, _}}, %Incompatibility{cause: {:conflict, _, _}} }), do: true defp single_line?({:conflict, %Incompatibility{}, %Incompatibility{}}), do: false defp state(root, derivations, opts) do %{ root: root, lines: [], line_numbers: %{}, derivations: derivations, ansi: Keyword.get(opts, :ansi, false) } end end hex-2.0.6/lib/hex/solver/incompatibility.ex000066400000000000000000000307561437023760000207220ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Incompatibility do @moduledoc false import Kernel, except: [to_string: 1] alias Hex.Solver.{Constraint, Incompatibility, PackageRange, Term} alias Hex.Solver.Constraints.Range defstruct terms: [], cause: nil # Causes: # * {:conflict, incompatibility, cause} # * :root # * :dependency # * :no_versions # * :package_not_found def new(terms, cause) do terms = if length(terms) != 1 and match?({:conflict, _, _}, cause) and Enum.any?(terms, &(&1.positive or &1.package_range.name == "$root")) do Enum.filter(terms, &(not &1.positive or &1.package_range.name != "$root")) else terms end case terms do [_first] -> %Incompatibility{terms: terms, cause: cause} [%{package_range: %{name: first}}, %{package_range: %{name: second}}] when first != second -> %Incompatibility{terms: terms, cause: cause} _ -> terms = Enum.reduce(terms, %{}, fn term, map -> Map.update(map, term.package_range.name, term, &Term.intersect(&1, term)) end) %Incompatibility{terms: Map.values(terms), cause: cause} end end def failure?(%Incompatibility{terms: []}), do: true def failure?(%Incompatibility{terms: [%{package_range: %{name: "$root"}}]}), do: true def failure?(%Incompatibility{}), do: false def to_string(incompatibilty, opts \\ []) def to_string( %Incompatibility{ cause: :dependency, terms: [ %Term{package_range: %PackageRange{name: "$lock"}, positive: true}, %Term{positive: false} = dependee ] }, opts ) do "\"the lock\" specifies #{bright_term_abs(dependee, opts)}" end def to_string( %Incompatibility{ cause: :dependency, terms: [%Term{positive: true} = depender, %Term{positive: false} = dependee] }, opts ) do "#{terse_every(depender, opts)} depends on #{bright_term_abs(dependee, opts)}" end def to_string(%Incompatibility{cause: :no_versions, terms: terms}, opts) do [%Term{positive: true} = term] = terms "no versions of #{package_name(term, opts)} match #{bright(term.package_range.constraint, opts)}" end def to_string(%Incompatibility{cause: :package_not_found, terms: terms}, opts) do [%Term{positive: true} = term] = terms "#{package_name(term, opts)} doesn't exist" end def to_string(%Incompatibility{cause: :root, terms: terms}, opts) do [%Term{positive: false} = term] = terms "#{package_name(term, opts)} is #{bright(term.package_range.constraint, opts)}" end def to_string(%Incompatibility{terms: []}, _opts) do "version solving failed" end def to_string( %Incompatibility{terms: [%Term{package_range: %PackageRange{name: "$root"}}]}, _opts ) do "version solving failed" end def to_string( %Incompatibility{ terms: [ %Term{ positive: true, package_range: %PackageRange{constraint: %Range{min: nil, max: nil}} } = term ] }, opts ) do "no version of #{package_name(term, opts)} is allowed" end def to_string(%Incompatibility{terms: [%Term{positive: true} = term]}, opts) do "#{terse_name(term, opts)} is forbidden" end def to_string(%Incompatibility{terms: [%Term{positive: false} = term]}, opts) do "#{terse_name(%Term{term | positive: true}, opts)} is required" end def to_string( %Incompatibility{terms: [%{positive: true} = left, %{positive: true} = right]}, opts ) do "#{terse_name(left, opts)} is incompatible with #{terse_name(right, opts)}" end def to_string( %Incompatibility{terms: [%{positive: false} = left, %{positive: false} = right]}, opts ) do "either #{bright_term_abs(left, opts)} or #{bright_term_abs(right, opts)}" end def to_string(%Incompatibility{terms: terms}, opts) do {positive, negative} = Enum.split_with(terms, & &1.positive) cond do positive != [] and negative != [] -> case positive do [term] -> "#{bright_term_abs(term, opts)} requires #{Enum.map_join(negative, " or ", &bright_term_abs(&1, opts))}" _ -> "if #{Enum.map_join(positive, " and ", &bright_term_abs(&1, opts))} then #{Enum.map_join(negative, " or ", &bright_term_abs(&1, opts))}" end positive != [] -> "one of #{Enum.map_join(positive, " or ", &bright_term_abs(&1, opts))} must be false" negative != [] -> "one of #{Enum.map_join(negative, " or ", &bright_term_abs(&1, opts))} must be true" end end def to_string_and(left, right, opts \\ []) def to_string_and( %Incompatibility{ terms: [%{package_range: %{name: "$lock"}}, _dependency], cause: :dependency } = left, %Incompatibility{ terms: [%{package_range: %{name: "$root"}}, %{package_range: %{name: "$lock"}}], cause: :dependency }, opts ) do to_string(left, opts) end def to_string_and(%Incompatibility{} = left, %Incompatibility{} = right, opts) do cond do requires_both = try_requires_both(left, right, opts) -> requires_both requires_through = try_requires_through(left, right, opts) -> requires_through requires_forbidden = try_requires_forbidden(left, right, opts) -> requires_forbidden true -> [ to_string(left, opts), maybe_line(opts[:left_line]), " and ", to_string(right, opts), maybe_line(opts[:right_line]) ] end |> IO.chardata_to_string() end defp try_requires_both(left, right, opts) do if length(left.terms) == 1 or length(right.terms) == 1 do throw({__MODULE__, :try_requires_both}) end left_positive = single_term(left, & &1.positive) right_positive = single_term(right, & &1.positive) if !left_positive || !right_positive || left_positive.package_range != right_positive.package_range do throw({__MODULE__, :try_requires_both}) end left_negatives = left.terms |> Enum.reject(& &1.positive) |> Enum.map_join(" or ", &bright_term_abs(&1, opts)) right_negatives = right.terms |> Enum.reject(& &1.positive) |> Enum.map_join(" or ", &bright_term_abs(&1, opts)) dependency? = left.cause == :dependency and right.cause == :dependency [ terse_every(left_positive, opts), " ", cause_verb(dependency?), " both ", left_negatives, maybe_line(opts[:left_line]), " and ", right_negatives, maybe_line(opts[:right_line]) ] catch {__MODULE__, :try_requires_both} -> nil end defp try_requires_through(right, left, opts) do if length(left.terms) == 1 or length(right.terms) == 1 do throw({__MODULE__, :try_requires_through}) end left_negative = single_term(left, &(not &1.positive)) right_negative = single_term(right, &(not &1.positive)) left_positive = single_term(left, & &1.positive) right_positive = single_term(right, & &1.positive) if !left_negative && !right_negative do throw({__MODULE__, :try_requires_through}) end {prior, prior_negative, prior_line, latter, latter_line} = cond do left_negative && right_positive && left_negative.package_range.name == right_positive.package_range.name && Term.satisfies?(Term.inverse(left_negative), right_positive) -> {left, left_negative, opts[:left_line], right, opts[:right_line]} right_negative && left_positive && right_negative.package_range.name == left_positive.package_range.name && Term.satisfies?(Term.inverse(right_negative), left_positive) -> {right, right_negative, opts[:right_line], left, opts[:left_line]} true -> throw({__MODULE__, :try_requires_through}) end prior_positives = Enum.filter(prior.terms, & &1.positive) buffer = if length(prior_positives) > 1 do prior_string = Enum.map_join(prior_positives, " or ", &bright_term_abs(&1, opts)) "if #{prior_string} then " else "#{terse_every(List.first(prior_positives), opts)} #{cause_verb(prior)} " end buffer = [ buffer, bright_term_abs(prior_negative, opts), maybe_line(prior_line), " which ", cause_verb(latter) ] latter_string = latter.terms |> Enum.reject(& &1.positive) |> Enum.map_join(" or ", &bright_term_abs(&1, opts)) [buffer, " ", latter_string, maybe_line(latter_line)] catch {__MODULE__, :try_requires_through} -> nil end defp try_requires_forbidden(left, right, opts) do if length(left.terms) != 1 and length(right.terms) != 1 do throw({__MODULE__, :try_requires_forbidden}) end {prior, prior_line, latter, latter_line} = if length(left.terms) == 1 do {right, opts[:right_line], left, opts[:left_line]} else {left, opts[:left_line], right, opts[:right_line]} end negative = single_term(prior, &(not &1.positive)) unless negative do throw({__MODULE__, :try_requires_forbidden}) end unless Term.satisfies?(Term.inverse(negative), List.first(latter.terms)) do throw({__MODULE__, :try_requires_forbidden}) end positives = Enum.filter(prior.terms, & &1.positive) buffer = case positives do [positive] -> [terse_every(positive, opts), " ", cause_verb(prior), " "] _ -> ["if ", Enum.map_join(positives, " or ", &bright_term_abs(&1, opts)), " then "] end buffer = [ buffer, bright_term_abs(List.first(latter.terms), opts), maybe_line(prior_line), " " ] buffer = case latter.cause do :no_versions -> [buffer, "which doesn't match any versions"] :package_not_found -> [buffer, "which doesn't exist"] _ -> [buffer, "which is forbidden"] end [buffer, maybe_line(latter_line)] catch {__MODULE__, :try_requires_forbidden} -> nil end defp bright(string, opts) do if Keyword.get(opts, :ansi, false) do [IO.ANSI.bright(), Kernel.to_string(string), IO.ANSI.reset()] else ~s("#{string}") end end defp cause_verb(true), do: "depends on" defp cause_verb(false), do: "requires" defp cause_verb(%Incompatibility{cause: :dependency}), do: "depends on" defp cause_verb(%Incompatibility{cause: _}), do: "requires" defp maybe_line(nil), do: "" defp maybe_line(line), do: " (#{line})" defp single_term(%Incompatibility{terms: terms}, fun) do Enum.reduce_while(terms, nil, fn term, found -> if fun.(term) do if found do {:halt, nil} else {:cont, term} end else {:cont, found} end end) end defp package_name(%Term{package_range: %PackageRange{name: "$root"}}, opts), do: bright("your app", opts) defp package_name(%Term{package_range: %PackageRange{name: "$lock"}}, opts), do: bright("the lock", opts) defp package_name(%Term{package_range: %PackageRange{repo: nil, name: name}}, opts), do: bright(name, opts) defp package_name(%Term{package_range: %PackageRange{repo: repo, name: name}}, opts), do: bright("#{repo}/#{name}", opts) defp terse_name(term, opts) do if Constraint.any?(term.package_range.constraint) do package_name(term, opts) else bright(PackageRange.to_string(term.package_range), opts) end end defp terse_every(%Term{package_range: %PackageRange{name: "$root"}}, opts), do: bright("your app", opts) defp terse_every(%Term{package_range: %PackageRange{name: "$lock"}}, opts), do: bright("the lock", opts) defp terse_every(term, opts) do if Constraint.any?(term.package_range.constraint) do "every version of #{package_name(term, opts)}" else bright(PackageRange.to_string(term.package_range), opts) end end defp term_abs(term), do: %Term{term | positive: true} defp bright_term_abs(term, opts), do: bright(term_abs(term), opts) defimpl String.Chars do defdelegate to_string(incompatibility), to: Hex.Solver.Incompatibility end defimpl Inspect do def inspect(%{terms: terms, cause: cause}, _opts) do "#Incompatibility<#{Enum.map_join(terms, ", ", &Kernel.inspect/1)}#{maybe(", cause: ", cause)}>" end defp maybe(_prefix, nil), do: "" defp maybe(prefix, value), do: "#{prefix}#{inspect(value)}" end end hex-2.0.6/lib/hex/solver/package_lister.ex000066400000000000000000000203741437023760000204720ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.PackageLister do @moduledoc false alias Hex.Solver.{Constraint, Incompatibility, PackageLister, PackageRange, Term} alias Hex.Solver.Constraints.{Range, Version} defstruct registry: nil, root_dependencies: [], locked: [], overrides: [], already_prefetched: MapSet.new([{nil, "$lock"}]), already_returned: %{} # Prefer packages with few remaining versions so that if there is conflict # later it will be forced quickly def pick_package(lister, package_ranges) do {package_range, versions} = package_ranges |> Enum.sort_by(& &1.name) |> Enum.map(fn package_range -> case versions(lister, package_range.repo, package_range.name) do {:ok, versions} -> allowed = Enum.filter(versions, &Constraint.allows?(package_range.constraint, &1)) {package_range, allowed} :error -> throw({__MODULE__, :minimal_versions, package_range}) end end) |> Enum.min_by(fn {_package_range, versions} -> length(versions) end) {:ok, package_range, List.first(Enum.sort(versions, &Version.prioritize/2))} catch :throw, {__MODULE__, :minimal_versions, package_range} -> {:error, package_range} end def dependencies_as_incompatibilities(%PackageLister{} = lister, package_repo, package, version) do {:ok, versions} = versions(lister, package_repo, package) already_returned = Map.get(lister.already_returned, {package_repo, package}, %{}) # Dependencies of package keyed on package version versions_dependencies = Enum.map(versions, fn version -> {:ok, dependencies} = dependencies(lister, package_repo, package, version) {version, dependencies} end) {_version, dependencies} = List.keyfind(versions_dependencies, version, 0) # Dependencies of package version filtered of overrides and already returned dependencies dependencies = dependencies |> Enum.sort() |> Enum.reject(fn {_dependency, %{label: label}} -> package not in ["$root", "$lock"] and label in lister.overrides end) |> Enum.reject(fn {dependency, _} -> case Map.fetch(already_returned, dependency) do {:ok, returned_constraint} -> Constraint.allows?(returned_constraint, version) :error -> false end end) incompatibilities = Enum.map(dependencies, fn {dependency, %{ repo: dependency_repo, constraint: constraint, optional: optional }} -> version_constraints = Enum.map(versions_dependencies, fn {version, dependencies} -> case Map.fetch(dependencies, dependency) do {:ok, %{constraint: constraint, optional: optional}} -> {version, {constraint, optional}} :error -> {version, nil} end end) # Find range of versions around the current version for which the # constraint is the same to create an incompatibility based on a # larger set of versions for the parent package. # This optimization let us skip many versions during conflict resolution. lower = lower_bound(Enum.reverse(version_constraints), version, {constraint, optional}) upper = upper_bound(version_constraints, version, {constraint, optional}) range = %Range{min: lower, max: upper, include_min: !!lower} package_range = %PackageRange{repo: package_repo, name: package, constraint: range} package_term = %Term{positive: true, package_range: package_range} dependency_range = %PackageRange{ repo: dependency_repo, name: dependency, constraint: constraint } dependency_term = %Term{ positive: false, package_range: dependency_range, optional: optional } Incompatibility.new([package_term, dependency_term], :dependency) end) prefetch = dependencies |> MapSet.new(fn {dependency, %{repo: repo}} -> {repo, dependency} end) |> MapSet.difference(lister.already_prefetched) if MapSet.size(prefetch) > 0 do lister.registry.prefetch(Enum.to_list(prefetch)) end # Dependencies already returned already_returned = Enum.reduce(incompatibilities, already_returned, fn incompatibility, already_returned -> [package_term, dependency_term] = case incompatibility do %Incompatibility{terms: [single]} -> [single, single] %Incompatibility{terms: [package, dependency]} -> [package, dependency] end name = dependency_term.package_range.name constraint = package_term.package_range.constraint Map.update(already_returned, name, constraint, &Constraint.union(&1, constraint)) end) lister = %{ lister | already_prefetched: MapSet.union(lister.already_prefetched, prefetch), already_returned: Map.put(lister.already_returned, package, already_returned) } {lister, incompatibilities} end defp lower_bound(versions_dependencies, version, constraint) do [{version, _} | versions_dependencies] = skip_to_version(versions_dependencies, version) skip_to_last_constraint(versions_dependencies, constraint, version) end defp upper_bound(versions_dependencies, version, constraint) do versions_dependencies = skip_to_version(versions_dependencies, version) skip_to_after_constraint(versions_dependencies, constraint) end defp skip_to_version([{version, _constraint} | _] = versions_dependencies, version) do versions_dependencies end defp skip_to_version([_ | versions_dependencies], version) do skip_to_version(versions_dependencies, version) end defp skip_to_last_constraint( [{version, constraint} | versions_dependencies], {_constraint, _optional} = constraint, _last ) do skip_to_last_constraint(versions_dependencies, constraint, version) end defp skip_to_last_constraint([], _constraint, _last) do nil end defp skip_to_last_constraint(_versions_dependencies, _constraint, last) do last end defp skip_to_after_constraint( [{_, constraint}, {version, constraint} | versions_dependencies], {_constraint, _optional} = constraint ) do skip_to_after_constraint([{version, constraint} | versions_dependencies], constraint) end defp skip_to_after_constraint([_, {version, _} | _versions_dependencies], _) do version end defp skip_to_after_constraint(_, _constraint) do nil end @version_1 Elixir.Version.parse!("1.0.0") defp versions(_lister, _repo, "$root"), do: {:ok, [@version_1]} defp versions(_lister, _repo, "$lock"), do: {:ok, [@version_1]} defp versions(%PackageLister{registry: registry}, repo, package), do: registry.versions(repo, package) defp dependencies( %PackageLister{root_dependencies: dependencies, locked: locked}, _repo, "$root", @version_1 ) do lock_dependency = if locked == [] do [] else [%{repo: nil, name: "$lock", constraint: @version_1, optional: false, label: "$lock"}] end {:ok, dependency_map(lock_dependency ++ dependencies)} end defp dependencies(%PackageLister{locked: locked}, _repo, "$lock", @version_1) do {:ok, Map.new(locked, fn dependency -> {dependency.name, %{ repo: dependency.repo, constraint: dependency.constraint, optional: true, label: dependency.label }} end)} end defp dependencies(%PackageLister{registry: registry}, repo, package, version) do case registry.dependencies(repo, package, version) do {:ok, dependencies} -> {:ok, dependency_map(dependencies)} :error -> :error end end defp dependency_map(dependencies) do Map.new(dependencies, fn dependency -> {dependency.name, %{ repo: dependency.repo, constraint: dependency.constraint, optional: dependency.optional, label: dependency.label }} end) end end hex-2.0.6/lib/hex/solver/package_range.ex000066400000000000000000000021721437023760000202600ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.PackageRange do @moduledoc false alias Hex.Solver.PackageRange alias Hex.Solver.Constraints.Range defstruct repo: nil, name: nil, constraint: nil def to_string(%PackageRange{name: "$root"}), do: "your app" def to_string(%PackageRange{name: "$lock"}), do: "the lock" def to_string(%PackageRange{repo: nil, name: name, constraint: constraint}), do: "#{name}#{constraint(constraint)}" def to_string(%PackageRange{repo: repo, name: name, constraint: constraint}), do: "#{repo}/#{name}#{constraint(constraint)}" defp constraint(%Range{min: nil, max: nil}), do: "" defp constraint(constraint), do: " #{constraint}" defimpl String.Chars do defdelegate to_string(package_range), to: Hex.Solver.PackageRange end defimpl Inspect do def inspect(%{repo: nil, name: name, constraint: constraint}, _opts), do: "#PackageRange<#{name} #{constraint}>" def inspect(%{repo: repo, name: name, constraint: constraint}, _opts), do: "#PackageRange<#{repo}/#{name} #{constraint}>" end end hex-2.0.6/lib/hex/solver/partial_solution.ex000066400000000000000000000122351437023760000211020ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.PartialSolution do @moduledoc false alias Hex.Solver.{Assignment, PackageRange, PartialSolution, Term} defstruct assignments: [], decisions: %{}, positive: %{}, negative: %{}, backtracking: false, attempted_solutions: 1 def relation(%PartialSolution{} = solution, %Term{} = term, opts \\ []) do name = term.package_range.name case Map.fetch(solution.positive, name) do {:ok, positive} -> Term.relation(positive.term, term, opts) :error -> case Map.fetch(solution.negative, name) do {:ok, negative} -> Term.relation(negative.term, term, opts) :error -> :overlapping end end end def satisfies?(%PartialSolution{} = solution, %Term{} = term, opts \\ []) do relation(solution, term, opts) == :subset end def satisfier(%PartialSolution{} = solution, term, opts \\ []) do {:satisfier, assignment} = Enum.reduce_while(Enum.reverse(solution.assignments), nil, fn assignment, assigned_term -> if assignment.term.package_range.name == term.package_range.name do if Term.compatible_package?(assignment.term, term) do assigned_term = if assigned_term do Assignment.intersect(assigned_term, assignment) else assignment end if Term.satisfies?(assigned_term.term, term, opts) do {:halt, {:satisfier, assignment}} else {:cont, assigned_term} end else if assignment.term.positive do false = term.positive {:halt, {:satisfier, assignment}} else {:cont, assigned_term} end end else {:cont, assigned_term} end end) assignment end def backtrack(%PartialSolution{} = solution, decision_level) do {removed, assignments} = Enum.split_while(solution.assignments, &(&1.decision_level > decision_level)) removed_names = Enum.map(removed, & &1.term.package_range.name) removed_decisions = Enum.filter(removed, &Assignment.decision?/1) decisions = Map.drop(solution.decisions, Enum.map(removed_decisions, & &1.term.package_range.name)) positive = Map.drop(solution.positive, removed_names) negative = Map.drop(solution.negative, removed_names) solution = %{ solution | assignments: assignments, decisions: decisions, positive: positive, negative: negative, backtracking: true } Enum.reduce(assignments, solution, fn assignment, solution -> if assignment.term.package_range.name in removed_names do register(solution, assignment) else solution end end) end def derive(%PartialSolution{} = solution, term, incompatibility) do {assignment, solution} = assign(solution, term, incompatibility) register(solution, assignment) end def decide( %PartialSolution{} = solution, %PackageRange{repo: repo, name: package, constraint: version} = package_range ) do attempted_solutions = solution.attempted_solutions + if solution.backtracking, do: 1, else: 0 decisions = Map.put(solution.decisions, package, {version, repo}) term = %Term{package_range: package_range, positive: true} solution = %{ solution | attempted_solutions: attempted_solutions, backtracking: false, decisions: decisions } {assignment, solution} = assign(solution, term, nil) register(solution, assignment) end defp assign(solution, term, incompatibility) do assignment = %Assignment{ term: term, decision_level: map_size(solution.decisions), index: length(solution.assignments), cause: incompatibility } solution = %{solution | assignments: [assignment | solution.assignments]} {assignment, solution} end defp register(solution, assignment) do name = assignment.term.package_range.name case Map.fetch(solution.positive, name) do {:ok, old_assignment} -> assignment = Assignment.intersect(old_assignment, assignment) positive = Map.put(solution.positive, name, assignment) %{solution | positive: positive} :error -> assignment = if old_assignment = Map.get(solution.negative, name) do Assignment.intersect(old_assignment, assignment) else assignment end if assignment.term.positive do negative = Map.delete(solution.negative, name) positive = Map.put(solution.positive, name, assignment) %{solution | negative: negative, positive: positive} else negative = Map.put(solution.negative, name, assignment) %{solution | negative: negative} end end end def unsatisfied(%PartialSolution{} = solution) do solution.positive |> Map.values() |> Enum.reject(&Map.has_key?(solution.decisions, &1.term.package_range.name)) |> Enum.reject(& &1.term.optional) |> Enum.map(& &1.term.package_range) end end hex-2.0.6/lib/hex/solver/registry.ex000066400000000000000000000016141437023760000173610ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Registry do _ = """ The registry is used by the solver to discover package versions and their dependencies. """ @doc """ Returns all versions of the given package sorted from lowest to highest or `:error` if the package does not exist. """ @callback versions(Hex.Solver.repo(), Hex.Solver.package()) :: {:ok, [Version.t()]} | :error @doc """ Returns all dependencies of the given package version or `:error` if the package or version does not exist. """ @callback dependencies(Hex.Solver.repo(), Hex.Solver.package(), Version.t()) :: {:ok, [Hex.Solver.dependency()]} | :error @doc """ Called when the solver first discovers a set of packages so that the registry can be lazily preloaded. """ @callback prefetch([{Hex.Solver.repo(), Hex.Solver.package()}]) :: :ok end hex-2.0.6/lib/hex/solver/requirement.ex000066400000000000000000000203651437023760000200550ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Requirement do @moduledoc false alias Hex.Solver.Constraints.{Range, Util} alias Hex.Solver.Requirement.Parser @allowed_range_ops [:>, :>=, :<, :<=, :~>] def to_constraint(string) when is_binary(string) do case Parser.parse(string) do {:ok, lexed} -> {:ok, delex(lexed, [])} :error -> :error end catch {__MODULE__, :invalid_constraint} -> :error end def to_constraint(%Elixir.Version{} = version) do {:ok, version} end def to_constraint(%Elixir.Version.Requirement{} = requirement) do to_constraint(to_string(requirement)) end def to_constraint!(string) when is_binary(string) do case Parser.parse(string) do {:ok, lexed} -> delex(lexed, []) :error -> raise Elixir.Version.InvalidRequirementError, string end catch {__MODULE__, :invalid_constraint} -> raise Elixir.Version.InvalidRequirementError, string end def to_constraint!(%Elixir.Version{} = version) do %{version | build: nil} end def to_constraint!(%Elixir.Version.Requirement{} = requirement) do to_constraint!(to_string(requirement)) end defp delex([], acc) do Util.union(acc) end defp delex([op | rest], acc) when op in [:||, :or] do delex(rest, acc) end defp delex([op1, version1, op, op2, version2 | rest], acc) when op in [:&&, :and] do range = to_range(op1, version1, op2, version2) delex(rest, [range | acc]) end defp delex([op, version | rest], acc) do range = to_range(op, version) delex(rest, [range | acc]) end defp to_range(:==, version) do to_version(version) end defp to_range(:~>, {major, minor, nil, pre, _build}) do %Range{ min: to_version({major, minor, 0, pre, nil}), max: to_version({major + 1, 0, 0, [0], nil}), include_min: true } end defp to_range(:~>, {major, minor, patch, pre, _build}) do %Range{ min: to_version({major, minor, patch, pre, nil}), max: to_version({major, minor + 1, 0, [0], nil}), include_min: true } end defp to_range(:>, version) do %Range{min: to_version(version)} end defp to_range(:>=, version) do %Range{min: to_version(version), include_min: true} end defp to_range(:<, version) do %Range{max: to_version(version)} end defp to_range(:<=, version) do %Range{max: to_version(version), include_max: true} end defp to_range(:~>, _version1, :~>, _version2) do throw({__MODULE__, :invalid_constraint}) end defp to_range(op1, version1, :~>, version2) do to_range(:~>, version2, op1, version1) end defp to_range(:~>, version1, op2, version2) do range1 = to_range(:~>, version1) range2 = to_range(op2, version2) range = Range.intersect(range1, range2) unless Range.valid?(range) and Range.allows_any?(range1, range2) do throw({__MODULE__, :invalid_constraint}) end range end defp to_range(op1, version1, op2, version2) when op1 in @allowed_range_ops and op2 in @allowed_range_ops do range = Map.merge(to_range(op1, version1), to_range(op2, version2), fn :__struct__, Range, Range -> Range :min, nil, value -> value :min, value, nil -> value :max, nil, value -> value :max, value, nil -> value :include_min, value, value -> value :include_min, false, value -> value :include_min, value, false -> value :include_max, value, value -> value :include_max, false, value -> value :include_max, value, false -> value end) unless Range.valid?(range) do throw({__MODULE__, :invalid_constraint}) end range end defp to_version({major, minor, patch, pre, _build}), do: %Elixir.Version{major: major, minor: minor, patch: patch, pre: pre} # Vendored from https://github.com/elixir-lang/elixir/blob/0ff6522/lib/elixir/lib/version.ex#L495 defmodule Parser do @moduledoc false operators = [ {">=", :>=}, {"<=", :<=}, {"~>", :~>}, {">", :>}, {"<", :<}, {"==", :==}, {" or ", :or}, {" and ", :and} ] def parse(string) do revert_lexed(lexer(string), []) end defp lexer(string) do lexer(string, "", []) end for {string_op, atom_op} <- operators do defp lexer(unquote(string_op) <> rest, buffer, acc) do lexer(rest, "", [unquote(atom_op) | maybe_prepend_buffer(buffer, acc)]) end end defp lexer(" " <> rest, buffer, acc) do lexer(rest, "", maybe_prepend_buffer(buffer, acc)) end defp lexer(<>, buffer, acc) do lexer(rest, <>, acc) end defp lexer(<<>>, buffer, acc) do maybe_prepend_buffer(buffer, acc) end defp maybe_prepend_buffer("", acc), do: acc defp maybe_prepend_buffer(buffer, [head | _] = acc) when is_atom(head) and head not in [:and, :or], do: [buffer | acc] defp maybe_prepend_buffer(buffer, acc), do: [buffer, :== | acc] defp revert_lexed([version, op, cond | rest], acc) when is_binary(version) and is_atom(op) and cond in [:or, :and] do with {:ok, version} <- validate_requirement(op, version) do revert_lexed(rest, [cond, op, version | acc]) end end defp revert_lexed([version, op], acc) when is_binary(version) and is_atom(op) do with {:ok, version} <- validate_requirement(op, version) do {:ok, [op, version | acc]} end end defp revert_lexed(_rest, _acc), do: :error defp validate_requirement(op, version) do case parse_version(version, true) do {:ok, version} when op == :~> -> {:ok, version} {:ok, {_, _, patch, _, _} = version} when is_integer(patch) -> {:ok, version} _ -> :error end end defp parse_version(string, approximate?) when is_binary(string) do destructure [version_with_pre, build], String.split(string, "+", parts: 2) destructure [version, pre], String.split(version_with_pre, "-", parts: 2) destructure [major, minor, patch, next], String.split(version, ".") with nil <- next, {:ok, major} <- require_digits(major), {:ok, minor} <- require_digits(minor), {:ok, patch} <- maybe_patch(patch, approximate?), {:ok, pre_parts} <- optional_dot_separated(pre), {:ok, pre_parts} <- convert_parts_to_integer(pre_parts, []), {:ok, build_parts} <- optional_dot_separated(build) do {:ok, {major, minor, patch, pre_parts, build_parts}} else _other -> :error end end defp require_digits(nil), do: :error defp require_digits(string) do if leading_zero?(string), do: :error, else: parse_digits(string, "") end defp leading_zero?(<>), do: true defp leading_zero?(_), do: false defp parse_digits(<>, acc) when char in ?0..?9, do: parse_digits(rest, <>) defp parse_digits(<<>>, acc) when byte_size(acc) > 0, do: {:ok, String.to_integer(acc)} defp parse_digits(_, _acc), do: :error defp maybe_patch(patch, approximate?) defp maybe_patch(nil, true), do: {:ok, nil} defp maybe_patch(patch, _), do: require_digits(patch) defp optional_dot_separated(nil), do: {:ok, []} defp optional_dot_separated(string) do parts = String.split(string, ".") if Enum.all?(parts, &(&1 != "" and valid_identifier?(&1))) do {:ok, parts} else :error end end defp convert_parts_to_integer([part | rest], acc) do case parse_digits(part, "") do {:ok, integer} -> if leading_zero?(part) do :error else convert_parts_to_integer(rest, [integer | acc]) end :error -> convert_parts_to_integer(rest, [part | acc]) end end defp convert_parts_to_integer([], acc) do {:ok, Enum.reverse(acc)} end defp valid_identifier?(<>) when char in ?0..?9 when char in ?a..?z when char in ?A..?Z when char == ?- do valid_identifier?(rest) end defp valid_identifier?(<<>>) do true end defp valid_identifier?(_other) do false end end end hex-2.0.6/lib/hex/solver/solver.ex000066400000000000000000000340101437023760000170170ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Solver do @moduledoc false alias Hex.Solver.{ Incompatibility, PackageLister, PackageRange, PartialSolution, Term } alias Hex.Solver.Constraints.Util require Logger def run(registry, dependencies, locked, overrides) do solve("$root", new_state(registry, dependencies, locked, overrides)) end defp solve(next, state) do case unit_propagation([next], state) do {:ok, state} -> case choose_package_version(state) do :done -> {:ok, state.solution.decisions} {:choice, package, state} -> solve(package, state) end {:error, incompatibility, _state} -> {:error, incompatibility} end end defp unit_propagation([], state) do {:ok, state} end defp unit_propagation([package | changed], state) do incompatibilities = Map.fetch!(state.incompatibilities, package) result = Enum.reduce_while(incompatibilities, {changed, state}, fn incompatibility, {changed, state} -> case propagate_incompatibility(incompatibility.terms, nil, incompatibility, state) do {:ok, result, state} -> {:cont, {changed ++ [result], state}} {:error, :none} -> {:cont, {changed, state}} {:error, :conflict} -> unit_propagation_conflict(incompatibility, state) end end) case result do {:error, incompatibility, state} -> {:error, incompatibility, state} {changed, state} -> unit_propagation(changed, state) end end defp unit_propagation_conflict(incompatibility, state) do case conflict_resolution(state, incompatibility) do {:ok, root_cause, state} -> {:ok, result, state} = propagate_incompatibility(root_cause.terms, nil, root_cause, state, optionals: false) {:halt, {[result], state}} {:error, incompatibility} -> {:halt, {:error, incompatibility, state}} end end defp propagate_incompatibility(terms, unsatisified, incompatibility, state, opts \\ []) defp propagate_incompatibility([term | terms], unsatisified, incompatibility, state, opts) do case PartialSolution.relation(state.solution, term, opts) do :disjoint -> # If the term is contradicted by the partial solution then the # incompatibility is also contradicted so we can deduce nothing {:error, :none} :overlapping when unsatisified != nil -> # If more than one term is inconclusive we can deduce nothing {:error, :none} :overlapping -> propagate_incompatibility(terms, term, incompatibility, state, opts) :subset -> propagate_incompatibility(terms, unsatisified, incompatibility, state, opts) end end defp propagate_incompatibility([], nil, _incompatibility, _state, _opts) do # All terms in the incompatibility are satisified by the partial solution # so we have a conflict {:error, :conflict} end defp propagate_incompatibility([], unsatisfied, incompatibility, state, _opts) do # Only one term in the incompatibility was unsatisfied unsatisfied = %{unsatisfied | positive: not unsatisfied.positive} Logger.debug("RESOLVER: derived #{unsatisfied}") solution = PartialSolution.derive(state.solution, unsatisfied, incompatibility) {:ok, unsatisfied.package_range.name, %{state | solution: solution}} end defp choose_package_version(state) do unsatisfied = PartialSolution.unsatisfied(state.solution) if unsatisfied == [] do :done else case PackageLister.pick_package(state.lister, unsatisfied) do {:ok, package_range, nil} -> # If no version satisfies the constraint then add an incompatibility that indicates that term = %Term{positive: true, package_range: package_range} incompatibility = Incompatibility.new([term], :no_versions) state = add_incompatibility(state, incompatibility) {:choice, package_range.name, state} {:ok, package_range, version} -> {lister, incompatibilities} = PackageLister.dependencies_as_incompatibilities( state.lister, package_range.repo, package_range.name, version ) state = %{state | lister: lister} {state, conflict} = Enum.reduce(incompatibilities, {state, false}, fn incompatibility, {state, conflict} -> # If an incompatibility is already satisfied then selecting this version would cause # a conflict. We'll continue adding its dependencies then go back to unit propagation # that will eventually choose a better version. conflict = conflict or incompatibility_conflict?(state, incompatibility, package_range.name) state = add_incompatibility(state, incompatibility) {state, conflict} end) solution = if conflict do state.solution else package_range = %PackageRange{package_range | constraint: version} Logger.debug("RESOLVER: selecting #{package_range}") PartialSolution.decide(state.solution, package_range) end state = %{state | solution: solution} {:choice, package_range.name, state} {:error, package_range} -> package_range = %PackageRange{package_range | constraint: Util.any()} term = %Term{positive: true, package_range: package_range} incompatibility = Incompatibility.new([term], :package_not_found) state = add_incompatibility(state, incompatibility) {:choice, package_range.name, state} end end end defp add_incompatibility(state, incompatibility) do Logger.debug("RESOLVER: fact #{incompatibility}") incompatibilities = Enum.reduce(incompatibility.terms, state.incompatibilities, fn term, incompatibilities -> Map.update( incompatibilities, term.package_range.name, [incompatibility], &[incompatibility | &1] ) end) %{state | incompatibilities: incompatibilities} end defp incompatibility_conflict?(state, incompatibility, name) do Enum.all?(incompatibility.terms, fn term -> term.package_range.name == name or PartialSolution.satisfies?(state.solution, term) end) end # Given an incompatibility that's satisified by the solution, construct a new # incompatibility that encapsulates the root cause of the conflict and backtracks # until the new incompatibility will allow propagation to deduce new assignments. defp conflict_resolution(state, incompatibility) do Logger.debug("RESOLVER: conflict #{incompatibility}") do_conflict_resolution(state, incompatibility, false) catch :throw, {__MODULE__, :conflict_resolution, incompatibility, state} -> {:ok, incompatibility, state} end defp do_conflict_resolution(state, incompatibility, new_incompatibility?) do if Incompatibility.failure?(incompatibility) do {:error, incompatibility} else resolution = Enum.reduce(incompatibility.terms, new_resolution_state(), fn term, resolution -> satisfier = PartialSolution.satisfier(state.solution, term, optionals: false) resolution = cond do resolution.most_recent_satisfier == nil -> %{resolution | most_recent_term: term, most_recent_satisfier: satisfier} resolution.most_recent_satisfier.index < satisfier.index -> %{ resolution | most_recent_term: term, most_recent_satisfier: satisfier, difference: nil, previous_satisfier_level: max( resolution.previous_satisfier_level, resolution.most_recent_satisfier.decision_level ) } true -> %{ resolution | previous_satisfier_level: max(resolution.previous_satisfier_level, satisfier.decision_level) } end if resolution.most_recent_term == term do # If most_recent_satisfier doesn't satisfy most_recent_term on its own, # then the next most recent satisfier may not be the one that satisfies # remainder difference = Term.difference(resolution.most_recent_satisfier.term, resolution.most_recent_term) if difference do satisfier = PartialSolution.satisfier( state.solution, Term.inverse(difference), optionals: false ) previous_satisfier_level = max(resolution.previous_satisfier_level, satisfier.decision_level) %{ resolution | difference: difference, previous_satisfier_level: previous_satisfier_level } else %{resolution | difference: difference} end else resolution end end) # If most_recent_satisfier is the only satisfier left at its decision level, # or if it has no cause (indicating that it's a decision rather than a # derivation), then the incompatibility is the root cause. We then backjump # to previous_satisfier_level, where the incompatibility is guaranteed to # allow propagation to produce more assignments if resolution.previous_satisfier_level < resolution.most_recent_satisfier.decision_level or resolution.most_recent_satisfier.cause == nil do solution = PartialSolution.backtrack(state.solution, resolution.previous_satisfier_level) state = %{state | solution: solution} state = if new_incompatibility?, do: add_incompatibility(state, incompatibility), else: state throw({__MODULE__, :conflict_resolution, incompatibility, state}) end # Create a new incompatibility by combining the given incompatibility with # the incompatibility that caused most_recent_satisfier to be assigned. # Doing this iteratively constructs a new new incompatibility that's guaranteed # to be true (we know for sure no solution will satisfy the incompatibility) # while also approximating the intuitive notion of the "root cause" of the conflict. new_terms = Enum.filter(incompatibility.terms, &(&1 != resolution.most_recent_term)) ++ Enum.filter( resolution.most_recent_satisfier.cause.terms, &(&1.package_range != resolution.most_recent_satisfier.term.package_range) ) # The most_recent_satisfier may not satisfy most_recent_term on its own if # there are a collection of constraints on most_recent_term that only satisfy # it together. For example, if most_recent_term is `foo ~> 1.0` and solution # contains `[foo >= 1.0.0, foo < 2.0.0]`, the most_recent_satisfier will be # `foo < 2.0.0` even though it doesn't totally satisfy `foo ~> 1.0`. # In this case we add `most_recent_satisfier \ most_recent_term` to the # incompatibility as well. See https://github.com/dart-lang/pub/tree/master/doc/solver.md#conflict-resolution # for more details. new_terms = if resolution.difference, do: new_terms ++ [Term.inverse(resolution.difference)], else: new_terms incompatibility = Incompatibility.new( new_terms, {:conflict, incompatibility, resolution.most_recent_satisfier.cause} ) partially = if resolution.difference, do: " partially" Logger.debug(""" RESOLVER: conflict resolution #{resolution.most_recent_term} is#{partially} satisfied by #{resolution.most_recent_satisfier} which is caused by #{resolution.most_recent_satisfier.cause} thus #{incompatibility}\ """) do_conflict_resolution(state, incompatibility, true) end end defp new_resolution_state() do %{ # The term in incompatibility.terms that was most recently satisfied by the solution. most_recent_term: nil, # The earliest assignment in the solution such that incompatibility is satisfied # by the solution up to and including this assignment. most_recent_satisfier: nil, # The difference between most_recent_satisfier and most_recent_term, that is, # the versions that are allowed by most_recent_satisfier but not by most_recent_term. # nil if most_recent_satisfier totally satisfies most_recent_term. difference: nil, # The decision level of the earliest assignment before most_recent_satisfier # such that incompatibility is satisfied by the solution up to and including # this assignment and most_recent_satisfier. # Decision level 1 is the level where the root package was selected. We can # go back to level 0 but level 1 tends to give better error messages, because # references to the root package end up closer to the final conclusion that # no solution exists. previous_satisfier_level: 1 } end defp new_state(registry, root_dependencies, locked, overrides) do version = Version.parse!("1.0.0") package_range = %PackageRange{name: "$root", constraint: version} root = Incompatibility.new([%Term{positive: false, package_range: package_range}], :root) locked = Enum.map(locked, fn %{repo: repo, name: package, version: version, label: label} -> %{repo: repo, name: package, constraint: version, label: label} end) lister = %PackageLister{ registry: registry, root_dependencies: root_dependencies, locked: locked, overrides: overrides } %{ solution: %PartialSolution{}, incompatibilities: %{}, lister: lister } |> add_incompatibility(root) end end hex-2.0.6/lib/hex/solver/term.ex000066400000000000000000000110451437023760000164570ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Term do @moduledoc false alias Hex.Solver.{Constraint, PackageRange, Term} alias Hex.Solver.Constraints.Empty require Logger defstruct positive: true, package_range: nil, optional: false def relation(left, right, opts \\ []) do if Keyword.get(opts, :optionals, true) do case do_relation(left, right) do :disjoint -> if left.optional and not right.optional, do: :overlapping, else: :disjoint other -> if left.optional and right.optional, do: :disjoint, else: other end else do_relation(left, right) end end def do_relation(%Term{} = left, %Term{} = right) do left_constraint = constraint(left) right_constraint = constraint(right) cond do right.positive and left.positive -> cond do not compatible_package?(left, right) -> :disjoint Constraint.allows_all?(right_constraint, left_constraint) -> :subset not Constraint.allows_any?(left_constraint, right_constraint) -> :disjoint true -> :overlapping end right.positive and not left.positive -> cond do not compatible_package?(left, right) -> :overlapping Constraint.allows_all?(left_constraint, right_constraint) -> :disjoint true -> :overlapping end not right.positive and left.positive -> cond do not compatible_package?(left, right) -> :subset not Constraint.allows_any?(right_constraint, left_constraint) -> :subset Constraint.allows_all?(right_constraint, left_constraint) -> :disjoint true -> :overlapping end not right.positive and not left.positive -> cond do not compatible_package?(left, right) -> :overlapping Constraint.allows_all?(left_constraint, right_constraint) -> :subset true -> :overlapping end end end def intersect(%Term{} = left, %Term{} = right) do if compatible_package?(left, right) do optional = left.optional and right.optional cond do left.positive != right.positive -> positive = if left.positive, do: left, else: right negative = if left.positive, do: right, else: left constraint = Constraint.difference(constraint(positive), constraint(negative)) non_empty_term(left, constraint, optional, true) left.positive and right.positive -> constraint = Constraint.intersect(constraint(left), constraint(right)) non_empty_term(left, constraint, optional, true) not left.positive and not right.positive -> constraint = Constraint.union(constraint(left), constraint(right)) non_empty_term(left, constraint, optional, false) end else nil end end def difference(%Term{} = left, %Term{} = right) do intersect(left, inverse(right)) end def satisfies?(%Term{} = left, %Term{} = right, opts \\ []) do compatible_package?(left, right) and relation(left, right, opts) == :subset end def inverse(%Term{} = term) do %{term | positive: not term.positive} end def compatible_package?(%Term{package_range: %PackageRange{name: "$root"}}, %Term{}) do true end def compatible_package?(%Term{}, %Term{package_range: %PackageRange{name: "$root"}}) do true end def compatible_package?(%Term{package_range: left}, %Term{package_range: right}) do {left.repo, left.name} == {right.repo, right.name} end defp constraint(%Term{package_range: %PackageRange{constraint: constraint}}) do constraint end defp non_empty_term(_term, %Empty{}, _optional, _positive) do nil end defp non_empty_term(term, constraint, optional, positive) do %Term{ package_range: %{term.package_range | constraint: constraint}, positive: positive, optional: optional } end def to_string(%Term{package_range: package_range, positive: positive}) do "#{positive(positive)}#{package_range}" end defp positive(true), do: "" defp positive(false), do: "not " defimpl String.Chars do defdelegate to_string(term), to: Hex.Solver.Term end defimpl Inspect do def inspect( %Term{package_range: package_range, positive: positive, optional: optional}, _opts ) do "#Term<#{positive(positive)}#{package_range}#{optional(optional)}>" end defp positive(true), do: "" defp positive(false), do: "not " defp optional(true), do: " (optional)" defp optional(false), do: "" end end hex-2.0.6/lib/hex/solver/util.ex000066400000000000000000000003301437023760000164600ustar00rootroot00000000000000# Vendored from hex_solver v0.2.2 (2634e31), do not edit manually defmodule Hex.Solver.Util do @moduledoc false def compare(module) when is_atom(module) do &(module.compare(&1, &2) in [:lt, :eq]) end end hex-2.0.6/lib/hex/sponsor.ex000066400000000000000000000014641437023760000157050ustar00rootroot00000000000000defmodule Hex.Sponsor do @moduledoc false @metadata_file "hex_metadata.config" @sponsor_link_name "sponsor" def get_link(package_path) do case read_metadata(package_path) do {:ok, metadata} -> sponsorship(metadata) _ -> nil end end def get_link(package_name, deps_path) do deps_path |> Path.join(package_name) |> get_link() end defp read_metadata(package_path) do package_path |> Path.join(@metadata_file) |> :file.consult() end defp sponsorship(metadata) do case Enum.find(metadata, fn {name, _} -> name == "links" end) do {_links, links} -> Enum.find_value(links, fn {link, value} -> if String.downcase(link) == @sponsor_link_name do value end end) _ -> nil end end end hex-2.0.6/lib/hex/state.ex000066400000000000000000000212611437023760000153170ustar00rootroot00000000000000defmodule Hex.State do @moduledoc false @name __MODULE__ @api_url "https://hex.pm/api" @pbkdf2_iters 32_768 def default_api_url(), do: @api_url @config %{ api_key_read: %{ config: [:"$read_key"] }, api_key_write: %{ config: [:"$write_key", :"$encrypted_key"] }, api_key_write_unencrypted: %{ env: ["HEX_API_KEY"], config: [:api_key] }, api_url: %{ env: ["HEX_API_URL", "HEX_API"], config: [:api_url], default: @api_url, fun: {__MODULE__, :trim_slash} }, cache_home: %{ default: :user_cache, fun: {Hex.Config, :find_config_home} }, config_home: %{ default: :user_config, fun: {Hex.Config, :find_config_home} }, unsafe_https: %{ env: ["HEX_UNSAFE_HTTPS"], config: [:unsafe_https], default: false, fun: {__MODULE__, :to_boolean} }, unsafe_registry: %{ env: ["HEX_UNSAFE_REGISTRY"], config: [:unsafe_registry], default: false, fun: {__MODULE__, :to_boolean} }, no_verify_repo_origin: %{ env: ["HEX_NO_VERIFY_REPO_ORIGIN"], config: [:no_verify_repo_origin], default: false, fun: {__MODULE__, :to_boolean} }, http_concurrency: %{ env: ["HEX_HTTP_CONCURRENCY"], config: [:http_concurrency], default: 8, fun: {__MODULE__, :to_integer} }, http_proxy: %{ env: ["http_proxy", "HTTP_PROXY"], config: [:http_proxy] }, https_proxy: %{ env: ["https_proxy", "HTTPS_PROXY"], config: [:https_proxy] }, no_proxy: %{ env: ["no_proxy", "NO_PROXY"], config: [:no_proxy] }, http_timeout: %{ env: ["HEX_HTTP_TIMEOUT"], config: [:http_timeout], fun: {__MODULE__, :to_integer} }, data_home: %{ default: :user_data, fun: {Hex.Config, :find_config_home} }, mirror_url: %{ env: ["HEX_MIRROR_URL", "HEX_MIRROR"], config: [:mirror_url], fun: {__MODULE__, :trim_slash} }, trusted_mirror_url: %{ env: ["HEX_TRUSTED_MIRROR_URL", "HEX_TRUSTED_MIRROR"], config: [:trusted_mirror_url], fun: {__MODULE__, :trim_slash} }, offline: %{ env: ["HEX_OFFLINE"], config: [:offline], default: false, fun: {__MODULE__, :to_boolean} }, resolve_verbose: %{ env: ["HEX_RESOLVE_VERBOSE"], default: false, fun: {__MODULE__, :to_boolean} }, repos_key: %{ env: ["HEX_REPOS_KEY"], config: [:repos_key] }, diff_command: %{ env: ["HEX_DIFF_COMMAND"], config: [:diff_command], default: Mix.Tasks.Hex.Package.default_diff_command() }, cacerts_path: %{ env: ["HEX_CACERTS_PATH"], default: nil, config: [:cacerts_path] }, no_short_urls: %{ env: ["HEX_NO_SHORT_URLS"], config: [:no_short_urls], default: false, fun: {__MODULE__, :to_boolean} }, debug_solver: %{ env: ["HEX_DEBUG_SOLVER"], config: [:debug_solver], default: false, fun: {__MODULE__, :to_boolean} } } def start_link([]) do global_config = Hex.Config.read() Agent.start_link(__MODULE__, :init, [global_config], name: @name) end def child_spec(arg) do %{ id: __MODULE__, start: {__MODULE__, :start_link, [arg]} } end def stop() do Agent.stop(@name) end def init(global_config) do project_config = Keyword.get(Mix.Project.config(), :hex, []) state = Map.new(@config, fn {key, spec} -> {key, load_config_value(global_config, project_config, spec)} end) Map.merge(state, %{ clean_pass: {:computed, true}, httpc_profile: {:computed, :hex}, pbkdf2_iters: {:computed, @pbkdf2_iters}, repos: {:computed, Hex.Config.read_repos(global_config)}, ssl_version: {:computed, ssl_version()}, shell_process: {:computed, nil} }) end def refresh() do Agent.update(@name, fn _ -> init(Hex.Config.read()) end) end def get(key) do Agent.get(@name, fn state -> case Map.fetch(state, key) do {:ok, {_source, value}} -> value :error -> nil end end) end def fetch!(key) do Agent.get(@name, fn state -> case Map.fetch(state, key) do {:ok, {_source, value}} -> value :error -> raise KeyError, key: key, term: Hex.State end end) end def fetch!(key, transform) do key |> fetch!() |> transform.() end def fetch_source!(key) do Agent.get(@name, fn state -> case Map.fetch(state, key) do {:ok, {source, _value}} -> source :error -> raise KeyError, key: key, term: Hex.State end end) end def put(key, value) do Agent.update(@name, Map, :put, [key, {:computed, value}]) end def update!(key, fun) do Agent.update(@name, fn state -> Map.update!(state, key, fn {source, value} -> {source, fun.(value)} end) end) end def get_all() do Agent.get(@name, & &1) end def put_all(map) do Agent.update(@name, fn _ -> map end) end defp load_config_value(global_config, project_config, spec) do env = System.get_env() result = load_env(spec[:env], env) || load_project_config(project_config, spec[:config]) || load_global_config(global_config, spec[:config]) {module, func} = spec[:fun] || {__MODULE__, :ok_wrap} case result do nil -> case apply(module, func, [spec[:default]]) do {:ok, value} -> {:default, value} {source, value} -> {source, value} end {source, value} -> case apply(module, func, [value]) do {:ok, value} -> {source, value} :error -> print_invalid_config_error(value, source) {:ok, value} = apply(module, func, [spec[:default]]) {:default, value} end end end defp print_invalid_config_error(value, source) do value = inspect(value, pretty: true) message = "Invalid Hex config, falling back to default. Source: #{source(source)} #{value}" Hex.Shell.error(message) end defp source({:env, env_var}), do: "environment variable #{env_var}=" defp source({:project_config, key}), do: "mix.exs config #{key}: " defp source({:global_config, key}), do: "Hex config (location: #{config_path()}) #{key}: " defp config_path() do :config_home |> Hex.State.fetch!() |> Path.join("hex.config") end defp load_env(keys, env) do Enum.find_value(keys || [], fn key -> case Map.fetch(env, key) do {:ok, value} -> {{:env, key}, value} :error -> nil end end) end defp load_global_config(config, keys) do Enum.find_value(keys || [], fn key -> if value = Keyword.get(config, key) do {{:global_config, key}, value} end end) end defp load_project_config(config, keys) do Enum.find_value(keys || [], fn key -> if value = Keyword.get(config, key) do {{:project_config, key}, value} end end) end def to_boolean(nil), do: {:ok, nil} def to_boolean(false), do: {:ok, false} def to_boolean(true), do: {:ok, true} def to_boolean("0"), do: {:ok, false} def to_boolean("1"), do: {:ok, true} def to_boolean("false"), do: {:ok, false} def to_boolean("true"), do: {:ok, true} def to_boolean("FALSE"), do: {:ok, false} def to_boolean("TRUE"), do: {:ok, true} def to_boolean(_), do: :error def to_integer(nil), do: {:ok, nil} def to_integer(""), do: {:ok, nil} def to_integer(integer) when is_integer(integer), do: {:ok, integer} def to_integer(string) when is_binary(string) do {int, _} = Integer.parse(string) {:ok, int} end def to_integer(_), do: :error def default(nil, value), do: value def default(value, _), do: value def trim_slash(nil), do: {:ok, nil} def trim_slash(string) when is_binary(string), do: {:ok, String.trim_leading(string, "/")} def trim_slash(_), do: :error def ssl_version() do {:ok, version} = :application.get_key(:ssl, :vsn) parse_ssl_version(version) end defp parse_ssl_version(version) do version |> List.to_string() |> String.split(".") |> Enum.take(3) |> Enum.map(&to_integer/1) |> version_pad() |> List.to_tuple() end defp version_pad([major]), do: [major, 0, 0] defp version_pad([major, minor]), do: [major, minor, 0] defp version_pad([major, minor, patch]), do: [major, minor, patch] defp version_pad([major, minor, patch | _]), do: [major, minor, patch] def path_expand(path) when is_binary(path) do {:ok, Path.expand(path)} end def path_expand(_), do: :error def ok_wrap(arg), do: {:ok, arg} def config, do: @config end hex-2.0.6/lib/hex/stdlib.ex000066400000000000000000000056471437023760000154720ustar00rootroot00000000000000defmodule Hex.Stdlib do @moduledoc false defmacro stacktrace() do if Version.compare(System.version(), "1.7.0") == :lt do quote do: System.stacktrace() else quote do: __STACKTRACE__ end end # TODO: Remove this once we require OTP 24.0 def ssh_hostkey_fingerprint(digset_type, key) do cond do # Requires Elixir 1.15.0 function_exported?(Mix, :ensure_application!, 1) -> Mix.ensure_application!(:ssh) apply(:ssh, :hostkey_fingerprint, [digset_type, key]) Code.ensure_loaded?(:ssh) and function_exported?(:ssh, :hostkey_fingerprint, 2) -> apply(:ssh, :hostkey_fingerprint, [digset_type, key]) true -> apply(:public_key, :ssh_hostkey_fingerprint, [digset_type, key]) end end # TODO: Remove this once we require OTP 22.1 def crypto_hmac(type, key, data) do if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :mac, 4) do apply(:crypto, :mac, [:hmac, type, key, data]) else apply(:crypto, :hmac, [type, key, data]) end end # TODO: Remove this once we require OTP 22.0 def crypto_one_time_encrypt(cipher, key, iv, data) do if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :crypto_one_time, 5) do apply(:crypto, :crypto_one_time, [cipher, key, iv, data, true]) else apply(:crypto, :block_encrypt, [cipher, key, iv, data]) end end # TODO: Remove this once we require OTP 22.0 def crypto_one_time_decrypt(cipher, key, iv, data) do if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :crypto_one_time, 5) do apply(:crypto, :crypto_one_time, [cipher, key, iv, data, false]) else apply(:crypto, :block_decrypt, [cipher, key, iv, data]) end end # TODO: Remove this once we require OTP 22.0 def crypto_one_time_aead_encrypt(cipher, key, iv, plain_text, aad) do if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :crypto_one_time_aead, 5) do apply(:crypto, :crypto_one_time_aead, [cipher, key, iv, plain_text, aad, true]) else apply(:crypto, :block_encrypt, [:aes_gcm, key, iv, {aad, plain_text}]) end end # TODO: Remove this once we require OTP 22.0 def crypto_one_time_aead_decrypt(cipher, key, iv, cipher_text, aad, cipher_tag) do if Code.ensure_loaded?(:crypto) and function_exported?(:crypto, :crypto_one_time_aead, 5) do apply(:crypto, :crypto_one_time_aead, [cipher, key, iv, cipher_text, aad, cipher_tag, false]) else apply(:crypto, :block_decrypt, [:aes_gcm, key, iv, {aad, cipher_text, cipher_tag}]) end end # TODO: Remove this once we require OTP 22.0 def ssl_cipher_suites(string_type) do if Code.ensure_loaded?(:ssl) and function_exported?(:ssl, :cipher_suites, 3) do [ssl_version | _] = :ssl.versions()[:supported] apply(:ssl, :cipher_suites, [:all, ssl_version, string_type]) else apply(:ssl, :cipher_suites, [string_type]) end end end hex-2.0.6/lib/hex/tar.ex000066400000000000000000000025341437023760000147670ustar00rootroot00000000000000defmodule Hex.Tar do @moduledoc false def create!(_metadata, [], _output), do: Mix.raise( "Stopping package build due to errors.\nCreating tarball failed: File list was empty." ) def create!(metadata, files, output) do files = Enum.map(files, fn {filename, contents} -> {String.to_charlist(filename), contents} filename -> String.to_charlist(filename) end) case :mix_hex_tarball.create(metadata, files) do {:ok, %{tarball: tarball} = result} -> if output != :memory, do: File.write!(output, tarball) result {:error, reason} -> Mix.raise("Creating tarball failed: #{:mix_hex_tarball.format_error(reason)}") end end def unpack!(path, dest) do tarball = case path do {:binary, tarball} -> tarball _ -> File.read!(path) end dest = if dest == :memory, do: dest, else: String.to_charlist(dest) case :mix_hex_tarball.unpack(tarball, dest) do {:ok, result} -> result {:error, reason} -> Mix.raise("Unpacking tarball failed: #{:mix_hex_tarball.format_error(reason)}") end end # TODO: Add this function to def outer_checksum(path) do case File.read(path) do {:ok, tarball} -> {:ok, :crypto.hash(:sha256, tarball)} {:error, reason} -> {:error, reason} end end end hex-2.0.6/lib/hex/update_checker.ex000066400000000000000000000067231437023760000171530ustar00rootroot00000000000000defmodule Hex.UpdateChecker do @moduledoc false use GenServer @name __MODULE__ @timeout 60_000 @update_interval 24 * 60 * 60 def start_link(opts \\ []) do {init_state, opts} = Keyword.pop(opts, :init_state, %{}) opts = Keyword.put_new(opts, :name, @name) GenServer.start_link(__MODULE__, init_state, opts) end def init(init_state) do {:ok, state(init_state)} end def start_check() do GenServer.cast(@name, :start_check) end def check() do GenServer.call(@name, :check, @timeout * 2) |> print_update_message() end def handle_cast(:start_check, state) do if not state.started and not Hex.State.fetch!(:offline) and check_update?() do Task.async(fn -> {:installs, Hex.Repo.get_installs()} end) {:noreply, %{state | started: true}} else {:noreply, %{state | started: true, done: true}} end end def handle_call(:check, _from, %{started: true, done: true} = state) do {:reply, :already_checked, state} end def handle_call(:check, from, %{started: true, reply: nil, check_timeout: timeout} = state) do {:noreply, %{state | from: from}, timeout} end def handle_call(:check, from, %{started: true} = state) do {:reply, state.reply, %{state | from: from, done: true}} end def handle_call(:check, _from, %{started: false} = state) do {:reply, :latest, state} end def handle_info(:timeout, state) do state = reply(:timeout, state) {:noreply, state} end def handle_info({_ref, {:installs, result}}, state) do result = case result do {:ok, {code, body, _headers}} when code in 200..299 -> Hex.Repo.find_new_version_from_csv(body) other -> Hex.Shell.error("Failed to check for new Hex version") Hex.Utils.print_error_result(other) # Treat failure as latest :latest end Hex.Registry.Server.last_update(:calendar.universal_time()) state = reply(result, state) {:noreply, state} end def handle_info({:DOWN, _ref, :process, _pid, :normal}, state) do {:noreply, state} end defp print_update_message(:already_checked), do: :ok defp print_update_message(:latest), do: :ok defp print_update_message({:http_error, reason}) do Hex.Shell.error("Hex update check failed, HTTP ERROR: #{inspect(reason)}") :ok end defp print_update_message(:timeout) do Hex.Shell.error("Hex update check failed due to a timeout") :ok end defp print_update_message({:status, status}) do Hex.Shell.error("Hex update check failed, status code: #{status}") :ok end defp print_update_message({:version, version}) do Hex.Shell.warn( "A new Hex version is available (#{Hex.version()} < #{version}), " <> "please update with `mix local.hex`" ) :ok end defp reply(reply, %{from: nil} = state) do %{state | reply: reply} end defp reply(reply, %{from: from} = state) do GenServer.reply(from, reply) %{state | from: nil, done: true} end defp check_update?() do if last = Hex.Registry.Server.last_update() do now = :calendar.universal_time() |> :calendar.datetime_to_gregorian_seconds() last = :calendar.datetime_to_gregorian_seconds(last) now - last > @update_interval else true end end defp state(init_state) do state = %{ from: nil, reply: nil, done: false, started: false, check_timeout: @timeout } Map.merge(state, init_state) end end hex-2.0.6/lib/hex/utils.ex000066400000000000000000000202441437023760000153370ustar00rootroot00000000000000defmodule Hex.Utils do @moduledoc false def package_name("hexpm", package), do: package def package_name(nil, package), do: package def package_name(repo, package), do: "#{repo}/#{package}" def safe_deserialize_erlang("") do nil end def safe_deserialize_erlang(binary) do case safe_binary_to_term(binary) do {:ok, term} -> term :error -> Mix.raise("Received malformed erlang from Hex API") end rescue ArgumentError -> Mix.raise("Received malformed erlang from Hex API") end def safe_serialize_erlang(term) do binarify(term) |> :erlang.term_to_binary() end def safe_binary_to_term!(binary, opts \\ []) do case safe_binary_to_term(binary, opts) do {:ok, term} -> term :error -> raise ArgumentError, "unsafe terms" end end def safe_binary_to_term(binary, opts \\ []) def safe_binary_to_term(binary, opts) when is_binary(binary) do term = :erlang.binary_to_term(binary, opts) safe_terms(term) {:ok, term} catch :throw, :safe_terms -> :error end defp safe_terms(list) when is_list(list) do safe_list(list) end defp safe_terms(tuple) when is_tuple(tuple) do safe_tuple(tuple, tuple_size(tuple)) end defp safe_terms(map) when is_map(map) do fun = fn key, value, acc -> safe_terms(key) safe_terms(value) acc end :maps.fold(fun, map, map) end defp safe_terms(other) when is_atom(other) or is_number(other) or is_bitstring(other) or is_pid(other) or is_reference(other) do other end defp safe_terms(_other) do throw(:safe_terms) end defp safe_list([]), do: :ok defp safe_list([h | t]) when is_list(t) do safe_terms(h) safe_list(t) end defp safe_list([h | t]) do safe_terms(h) safe_terms(t) end defp safe_tuple(_tuple, 0), do: :ok defp safe_tuple(tuple, n) do safe_terms(:erlang.element(n, tuple)) safe_tuple(tuple, n - 1) end def truncate(string, options \\ []) do length = options[:length] || 50 omission = options[:omission] || "..." cond do not String.valid?(string) -> string String.length(string) < length -> string true -> String.slice(string, 0, length) <> omission end end def binarify(term, opts \\ []) def binarify(binary, _opts) when is_binary(binary) do binary end def binarify(number, _opts) when is_number(number) do number end def binarify(atom, _opts) when is_nil(atom) or is_boolean(atom) do atom end def binarify(atom, _opts) when is_atom(atom) do Atom.to_string(atom) end def binarify(list, opts) when is_list(list) do for(elem <- list, do: binarify(elem, opts)) end def binarify(tuple, opts) when is_tuple(tuple) do for(elem <- Tuple.to_list(tuple), do: binarify(elem, opts)) |> List.to_tuple() end def binarify(map, opts) when is_map(map) do if Keyword.get(opts, :maps, true) do for(elem <- map, into: %{}, do: binarify(elem, opts)) else for(elem <- map, do: binarify(elem, opts)) end end def print_error_result({:error, reason}) do Hex.Shell.info(inspect(reason)) end def print_error_result({:ok, {status, nil, _headers}}) do print_http_code(status) end def print_error_result({:ok, {status, "", _headers}}) do print_http_code(status) end def print_error_result({:ok, {_status, body, _headers}}) when is_binary(body) do Hex.Shell.info(body) end def print_error_result({:ok, {status, body, _headers}}) when is_map(body) do message = body["message"] errors = body["errors"] if message do Hex.Shell.info(message) end if errors do pretty_errors(errors) end unless message || errors do print_http_code(status) Hex.Shell.info(body) end end defp pretty_errors(errors, depth \\ 0) do Enum.each(errors, fn {key, map} when is_map(map) -> Hex.Shell.info(indent(depth) <> key <> ":") pretty_errors(map, depth + 1) {key, value} -> message = pretty_error_message(value, depth) Hex.Shell.info(indent(depth) <> key <> ": " <> message) end) end defp pretty_error_message(message, depth) do if message =~ "\n" do message = message |> String.trim() |> String.replace("\n", "\n" <> indent(depth + 1)) "\n" <> indent(depth + 1) <> message else message end end defp print_http_code(code), do: Hex.Shell.info(pretty_http_code(code)) defp pretty_http_code(401), do: "Authentication failed (401)" defp pretty_http_code(403), do: "Forbidden (403)" defp pretty_http_code(404), do: "Entity not found (404)" defp pretty_http_code(422), do: "Validation failed (422)" defp pretty_http_code(code), do: "HTTP status code: #{code}" defp indent(0), do: " " defp indent(depth), do: " " <> indent(depth - 1) def hexdocs_url(organization, package) when organization in ["hexpm", nil], do: "https://hexdocs.pm/#{package}" def hexdocs_url(organization, package), do: "https://#{organization}.hexdocs.pm/#{package}" def hexdocs_url(organization, package, version) when organization in ["hexpm", nil], do: "https://hexdocs.pm/#{package}/#{version}" def hexdocs_url(organization, package, version), do: "https://#{organization}.hexdocs.pm/#{package}/#{version}" def hexdocs_module_url(organization, package, module) when organization in ["hexpm", nil], do: "https://hexdocs.pm/#{package}/#{module}.html" def hexdocs_module_url(organization, package, module), do: "https://#{organization}.hexdocs.pm/#{package}/#{module}.html" def hexdocs_module_url(organization, package, version, module) when organization in ["hexpm", nil], do: "https://hexdocs.pm/#{package}/#{version}/#{module}.html" def hexdocs_module_url(organization, package, version, module), do: "https://#{organization}.hexdocs.pm/#{package}/#{version}/#{module}.html" def package_retirement_reason(:RETIRED_OTHER), do: "other" def package_retirement_reason(:RETIRED_INVALID), do: "invalid" def package_retirement_reason(:RETIRED_SECURITY), do: "security" def package_retirement_reason(:RETIRED_DEPRECATED), do: "deprecated" def package_retirement_reason(:RETIRED_RENAMED), do: "renamed" def package_retirement_reason(other), do: other def package_retirement_message(%{reason: reason_code, message: message}) do "(#{package_retirement_reason(reason_code)}) #{message}" end def package_retirement_message(%{reason: reason_code}) do "(#{package_retirement_reason(reason_code)})" end # From https://github.com/fishcakez/dialyze/blob/6698ae582c77940ee10b4babe4adeff22f1b7779/lib/mix/tasks/dialyze.ex#L168 def otp_version do major = :erlang.system_info(:otp_release) |> List.to_string() vsn_file = Path.join([:code.root_dir(), "releases", major, "OTP_VERSION"]) try do {:ok, contents} = File.read(vsn_file) String.split(contents, "\n", trim: true) else [full] -> full _ -> major catch :error, _ -> major end end def windows_repo_path_fix(path) do case :os.type() do {:win32, _name} -> String.replace(path, ":", "-") {_family, _name} -> path end end def lock(tuple) when elem(tuple, 0) == :hex do if tuple_size(tuple) > 8 and Hex.Server.should_warn_lock_version?() do Hex.Shell.warn( "The mix.lock file was generated with a newer version of Hex. Update " <> "your client by running `mix local.hex` to avoid losing data." ) end destructure( [:hex, name, version, inner_checksum, managers, deps, repo, outer_checksum], Tuple.to_list(tuple) ) %{ name: to_string(name), version: version, inner_checksum: inner_checksum, outer_checksum: outer_checksum, managers: managers, deps: lock_deps(deps), repo: repo || "hexpm" } end def lock(_) do nil end defp lock_deps(nil) do nil end defp lock_deps(deps) do Enum.map(deps, fn {app, req, opts} -> opts = opts |> Keyword.put_new(:repo, "hexpm") |> Keyword.update!(:hex, &to_string/1) {app, req, opts} end) end end hex-2.0.6/lib/mix/000077500000000000000000000000001437023760000136505ustar00rootroot00000000000000hex-2.0.6/lib/mix/task_description.ex000066400000000000000000000002701437023760000175520ustar00rootroot00000000000000defmodule Hex.Mix.TaskDescription do @moduledoc false @type args :: String.t() @type docs :: String.t() @type task_spec :: {args, docs} @callback tasks() :: [task_spec] end hex-2.0.6/lib/mix/tasks/000077500000000000000000000000001437023760000147755ustar00rootroot00000000000000hex-2.0.6/lib/mix/tasks/hex.audit.ex000066400000000000000000000031151437023760000172240ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Audit do use Mix.Task alias Hex.Registry.Server, as: Registry @shortdoc "Shows retired Hex deps for the current project" @moduledoc """ Shows all Hex dependencies that have been marked as retired. Retired packages are no longer recommended to be used by their maintainers. The task will display a message describing the reason for retirement and exit with a non-zero code if any retired dependencies are found. """ @behaviour Hex.Mix.TaskDescription @impl true def run(_) do Mix.Tasks.Deps.Loadpaths.run(["--no-compile"]) Hex.start() Registry.open() lock = Mix.Dep.Lock.read() lock |> Hex.Mix.packages_from_lock() |> Registry.prefetch() case retired_packages(lock) do [] -> Hex.Shell.info("No retired packages found") packages -> header = ["Dependency", "Version", "Retirement reason"] Mix.Tasks.Hex.print_table(header, packages) Hex.Shell.error("Found retired packages") Mix.Tasks.Hex.set_exit_code(1) end end @impl true def tasks() do [ {"", "Shows retired Hex deps for the current project"} ] end defp retired_packages(lock) do Enum.flat_map(lock, fn {_app, lock} -> retirement_status(Hex.Utils.lock(lock)) end) end defp retirement_status(%{repo: repo, name: package, version: version}) do retired = Registry.retired(repo, package, version) case retired do %{} -> [[package, version, Hex.Utils.package_retirement_message(retired)]] nil -> [] end end defp retirement_status(nil) do [] end end hex-2.0.6/lib/mix/tasks/hex.build.ex000066400000000000000000000315351437023760000172240ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Build do use Mix.Task @shortdoc "Builds a new package version locally" @moduledoc """ Builds a new local version of your package. The package .tar file is created in the current directory, but is not pushed to the repository. An app named `foo` at version `1.2.3` will be built as `foo-1.2.3.tar`. $ mix hex.build #{Hex.Package.configuration_doc()} ### Command line options * `--unpack` - Builds the tarball and unpacks contents into a directory. Useful for making sure the tarball contains all needed files before publishing. See `--output` below for setting the output path. * `-o`, `--output` - Sets output path. When used with `--unpack` it means the directory (Default: `-`). Otherwise, it specifies tarball path (Default: `-.tar`) """ @behaviour Hex.Mix.TaskDescription @error_fields ~w(app name files version build_tools)a @warn_fields ~w(description licenses links)a @meta_fields @error_fields ++ @warn_fields ++ ~w(elixir extra)a @root_fields ~w(app version elixir description)a @max_description_length 300 @default_repo "hexpm" @metadata_config "hex_metadata.config" @switches [unpack: :boolean, output: :string] @aliases [o: :output] @impl true def run(args) do Hex.start() {opts, _args} = OptionParser.parse!(args, strict: @switches, aliases: @aliases) build = prepare_package() organization = build.organization meta = build.meta package = build.package exclude_deps = build.exclude_deps Hex.Shell.info("Building #{meta.name} #{meta.version}") print_info(meta, organization, exclude_deps, package[:files]) if opts[:unpack] do output = Keyword.get(opts, :output, "#{meta.name}-#{meta.version}") build_and_unpack_package(meta, output) else output = Keyword.get(opts, :output, "#{meta.name}-#{meta.version}.tar") build_package(meta, output) end end @impl true def tasks() do [ {"", "Builds a new package version locally"} ] end defp build_package(meta, output) do %{outer_checksum: outer_checksum} = Hex.Tar.create!(meta, meta.files, output) Hex.Shell.info("Package checksum: #{Base.encode16(outer_checksum, case: :lower)}") Hex.Shell.info("Saved to #{output}") end defp build_and_unpack_package(meta, output) do %{tarball: tarball, inner_checksum: inner_checksum, outer_checksum: outer_checksum} = Hex.Tar.create!(meta, meta.files, :memory) %{inner_checksum: ^inner_checksum, outer_checksum: ^outer_checksum} = Hex.Tar.unpack!({:binary, tarball}, output) Hex.Shell.info("Saved to #{output}") end @doc false def prepare_package() do Mix.Project.get!() config = Mix.Project.config() check_umbrella_project!(config) check_root_fields!(config) package = Map.new(config[:package] || []) check_misspellings!(package) {organization, package} = Map.pop(package, :organization) {deps, exclude_deps} = dependencies() meta = meta_for(config, package, deps) check_unstable_dependencies!(organization, meta) %{ config: config, package: package, deps: deps, exclude_deps: exclude_deps, meta: meta, organization: organization } end @doc false def print_info(meta, organization, exclude_deps, package_files) do if meta[:requirements] != [] do Hex.Shell.info(" Dependencies:") Enum.each(meta[:requirements], fn requirement -> %{name: name, app: app, requirement: req, optional: opt, repository: repo} = requirement app = if name != app, do: " (app: #{app})" opt = if opt, do: " (optional)" repo = if repo != @default_repo, do: " (repo: #{repo})" message = " #{name} #{req}#{app}#{repo}#{opt}" Hex.Shell.info(message) end) end if organization do Hex.Shell.info(" Organization: #{organization}") end Enum.each(@meta_fields, &print_metadata(meta, &1)) errors = Enum.concat([ check_missing_fields(meta, organization), check_description_length(meta), check_missing_files(package_files || []), check_reserved_files(package_files || []), check_excluded_deps(exclude_deps) ]) if errors != [] do ["Stopping package build due to errors." | errors] |> Enum.join("\n") |> Mix.raise() end if organization in [nil, "hexpm"] do licenses_valid_or_warn(meta.licenses) end end defp licenses_valid_or_warn([]), do: Hex.Shell.warn("\nYou have not included any licenses\n") defp licenses_valid_or_warn(licenses) do invalid_licenses = Enum.reject(licenses, fn lic -> :mix_hex_licenses.valid(lic) end) if invalid_licenses != [] do message = [ "The following licenses are not recognized by SPDX:\n", Enum.map(invalid_licenses, &" * #{&1}\n"), "\nConsider using licenses from https://spdx.org/licenses" ] Hex.Shell.warn(message) end end defp check_excluded_deps([]), do: [] defp check_excluded_deps(deps) do [ "Dependencies excluded from the package (only Hex packages can be dependencies): #{Enum.join(deps, ", ")}" ] end defp meta_for(config, package, deps) do config |> Keyword.take(@root_fields) |> Map.new() |> Map.merge(package) |> package(config) |> Map.put(:requirements, deps) end defp dependencies() do {include, exclude} = Mix.Project.config()[:deps] |> Enum.map(&Hex.Mix.normalize_dep/1) |> Enum.filter(&prod_dep?/1) |> Enum.split_with(&package_dep?/1) Enum.each(include, fn {app, _req, opts} -> if Keyword.has_key?(opts, :override) do Mix.raise( "Can't build package with overridden dependency #{app}, remove `override: true`" ) end if Keyword.has_key?(opts, :compile) do Mix.raise( "Can't build package when :compile is set for dependency #{app}, remove `compile: ...`" ) end if Keyword.has_key?(opts, :manager) do Mix.raise( "Can't build package when :manager is set for dependency #{app}, remove `manager: ...`" ) end if Keyword.has_key?(opts, :app) do Mix.raise("Can't build package when :app is set for dependency #{app}, remove `app: ...`") end if Keyword.get(opts, :system_env, []) != [] do Mix.raise( "Can't build package when :system_env is set for dependency #{app}, remove `system_env: ...`" ) end end) include = Enum.map(include, fn {app, req, opts} -> name = opts[:hex] || app repo = deorg_repo(opts[:repo] || opts[:organization] || @default_repo) %{ name: to_string(name), app: app, requirement: req, optional: opts[:optional] || false, repository: repo } end) exclude = for {app, _req, _opts} <- exclude, do: app {include, exclude} end defp deorg_repo(repo) do case String.split(to_string(repo), ":", parts: 2) do [_source, repo] -> repo [repo] -> repo end end @doc false def package(package, config) do files = package[:files] || Hex.Package.default_files() exclude_patterns = (package[:exclude_patterns] || []) ++ [~r/\W\.DS_Store$/] files = files |> expand_paths(File.cwd!()) |> Enum.reject(fn path -> Enum.any?(exclude_patterns, &(path =~ &1)) end) package |> Map.put(:files, files) |> maybe_put(:description, package[:description], &String.trim/1) |> maybe_put(:name, package[:name] || config[:app], &to_string(&1)) |> maybe_put(:build_tools, !package[:build_tools] && guess_build_tools(files), & &1) |> Map.take(@meta_fields) end defp maybe_put(map, key, value, transform) do if value do Map.put(map, key, transform.(value)) else map end end @doc false def check_umbrella_project!(config) do if Mix.Project.umbrella?(config) do Mix.raise("Hex does not support umbrella projects") end end defp check_unstable_dependencies!(organization, meta) do if organization in [nil, "hexpm"] and not pre_requirement?(meta.version) and has_pre_requirements?(meta) do Mix.raise("A stable package release cannot have a pre-release dependency") end end defp check_misspellings!(opts) do if opts[:organisation] do Mix.raise("Invalid Hex package config :organisation, use spelling :organization") end end defp check_root_fields!(config) do package_only_fields = ([:organisation, :organization] ++ @meta_fields) -- (@root_fields ++ [:name]) config_keys = Keyword.keys(config) invalid_field = Enum.find(config_keys, &(&1 in package_only_fields)) if invalid_field do Hex.Shell.warn( "Mix project configuration #{inspect(invalid_field)} belongs under the :package key, did you misplace it?" ) end end defp pre_requirement?(version_req) do String.contains?(version_req, "-") end defp has_pre_requirements?(meta) do meta.requirements |> Enum.map(& &1.requirement) |> Enum.any?(&pre_requirement?/1) end @scm_keys [:git, :github, :path] defp package_dep?({_app, _req, opts}) do keys = Keyword.keys(opts) :hex in keys or not Enum.any?(@scm_keys, &(&1 in keys)) end defp prod_dep?({_app, _req, opts}) do if only = opts[:only], do: :prod in List.wrap(only), else: true end defp expand_paths(paths, dir) do expand_dir = Path.expand(dir) paths |> Enum.map(&Path.join(dir, &1)) |> Enum.flat_map(&Path.wildcard/1) |> Enum.flat_map(&dir_files/1) |> Enum.map(&Path.expand/1) |> Enum.uniq() |> Enum.map(&Path.relative_to(&1, expand_dir)) end defp dir_files(path) do case File.lstat(path) do {:ok, %File.Stat{type: :directory}} -> new_paths = path |> File.ls!() |> Enum.map(&Path.join(path, &1)) |> Enum.flat_map(&dir_files/1) [path | new_paths] _ -> [path] end end defp print_metadata(metadata, :files) do case metadata[:files] do [] -> Hex.Shell.error("No files") files -> Hex.Shell.info(" Files:") Enum.each(files, &Hex.Shell.info(" #{&1}")) end end defp print_metadata(metadata, key) do if value = metadata[key] do key = key |> Atom.to_string() |> String.replace("_", " ") |> String.capitalize() value = format_metadata_value(value) Hex.Shell.info(" #{key}: #{value}") end end defp format_metadata_value(list) when is_list(list) do Enum.join(list, ", ") end defp format_metadata_value(map) when is_map(map) do "\n " <> Enum.map_join(map, "\n ", fn {key, val} -> "#{key}: #{val}" end) end defp format_metadata_value(value) do value end defp check_missing_fields(metadata, organization) do if organization in [nil, "hexpm"] do check_error_fields(metadata, @error_fields ++ @warn_fields) else check_warn_fields(metadata, @warn_fields) check_error_fields(metadata, @error_fields) end end defp check_warn_fields(metadata, warn_fields) do case check_error_fields(metadata, warn_fields) do [message] -> Hex.Shell.warn(message) [] -> :ok end end defp check_error_fields(metadata, error_fields) do taken_fields = Map.take(metadata, error_fields) |> Map.keys() missing = error_fields -- taken_fields if missing == [] do [] else ["Missing metadata fields: #{Enum.join(missing, ", ")}"] end end defp check_description_length(metadata) do descr = metadata[:description] || "" if String.length(descr) > @max_description_length do ["Package description is too long (exceeds #{@max_description_length} characters)"] else [] end end defp check_missing_files(package_files) do case Enum.filter(package_files, &(Path.wildcard(&1) == [])) do [] -> [] missing -> ["Missing files: #{Enum.join(missing, ", ")}"] end end defp check_reserved_files(package_files) do reserved_file = @metadata_config invalid_file = Enum.find(package_files, &(reserved_file in Path.wildcard(&1))) if invalid_file do ["Do not include this file: #{reserved_file}"] else [] end end @build_tools [ {"mix.exs", "mix"}, {"rebar", "rebar3"}, {"rebar.lock", "rebar3"}, {"rebar.config", "rebar3"}, {"rebar.config.script", "rebar3"}, {"erlang.mk", "make"}, {"Makefile", "make"}, {"Makefile.win", "make"} ] defp guess_build_tools(paths) do base_files = paths |> Enum.filter(&(Path.dirname(&1) == ".")) |> MapSet.new() for {file, tool} <- @build_tools, file in base_files do tool end |> default_build_tool() |> Enum.uniq() end defp default_build_tool([]), do: ["mix"] defp default_build_tool(other), do: other end hex-2.0.6/lib/mix/tasks/hex.config.ex000066400000000000000000000205211437023760000173630ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Config do use Mix.Task @shortdoc "Reads, updates or deletes local Hex config" @moduledoc """ Reads, updates or deletes local Hex config. ## List config keys and values $ mix hex.config ## Get or delete config value for KEY $ mix hex.config KEY [--delete] ## Set config KEY to VALUE $ mix hex.config KEY VALUE ## Config keys * `api_key` - Your API key. If you are authenticated this config will override the API key used for your authenticated user. Can be also be overridden by setting the environment variable `HEX_API_KEY` * `api_url` - Hex API URL. Can be overridden by setting the environment variable `HEX_API_URL` (Default: `#{inspect(Hex.State.default_api_url())}`) * `offline` - If set to true Hex will not fetch the registry or packages and will instead use locally cached files if they are available. Can be overridden by setting the environment variable `HEX_OFFLINE` (Default: `false`) * `unsafe_https` - If set to true Hex will not verify HTTPS certificates. Can be overridden by setting the environment variable `HEX_UNSAFE_HTTPS` (Default: `false`) * `unsafe_registry` - If set to true Hex will not verify the registry signature against the repository's public key. Can be overridden by setting the environment variable `HEX_UNSAFE_REGISTRY` (Default: `false`) * `no_verify_repo_origin` - If set to true Hex will not verify the registry origin. Can be overridden by setting the environment variable `HEX_NO_VERIFY_REPO_ORIGIN` (Default: `false`) * `http_proxy` - HTTP proxy server. Can be overridden by setting the environment variable `HTTP_PROXY` * `https_proxy` - HTTPS proxy server. Can be overridden by setting the environment variable `HTTPS_PROXY` * `no_proxy` - A comma separated list of hostnames that will not be proxied, asterisks can be used as wildcards. Can be overridden by setting the environment variable `no_proxy` or `NO_PROXY` * `http_concurrency` - Limits the number of concurrent HTTP requests in flight. Can be overridden by setting the environment variable `HEX_HTTP_CONCURRENCY` (Default: `8`) * `http_timeout` - Sets the timeout for HTTP requests in seconds. Can be overridden by setting the environment variable `HEX_HTTP_TIMEOUT` * `mirror_url` - Hex mirror URL. Can be overridden by setting the environment variable `HEX_TRUSTED_MIRROR` * `trusted_mirror_url` - Hex mirror URL. Unlike `mirror_url`, this mirror is "trusted", secrets such as authentication information will be sent to the mirror. Can be overridden by setting the environment variable `HEX_TRUSTED_MIRROR` * `cacerts_path` - Path to the CA certificate store PEM file. If not set, a CA bundle that ships with Hex is used. Can be overridden by setting the environment variable `HEX_CACERTS_PATH` * `no_short_urls` - If set to true Hex will not shorten any links. Can be overridden by setting the environment variable `HEX_NO_SHORT_URLS` (Default: `false`) Hex responds to these additional environment variables: * `HEX_HOME` - directory where Hex stores the cache and configuration (Default: `~/.hex`) * `MIX_XDG` - asks Hex to follow the [XDG Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) for its home directory and configuration files. `HEX_HOME` has higher preference than `MIX_XDG`. If none of the variables are set, the default directory `~/.hex` will be used. ## Config overrides All keys from the "Config keys" section above can be overridden. Hex uses the following order of precedence when computing a value for a given key: 1. System environment Setting for example `HEX_API_URL` environment variable has always the highest precedence for the `api_url` config key. 2. Project configuration Hex allows an optional, per-project configuration in the `mix.exs` file. For example, to override `api_url` config key, add the following: # mix.exs defmodule MyApp.MixProject def project() do [ # ... deps: deps(), hex: hex() ] end defp hex() do [ api_url: "https://hex.myorg/api" ] end end 3. Global configuration using `mix hex.config KEY VALUE` 4. Default value ## Command line options * `--delete` - Remove a specific config key """ @behaviour Hex.Mix.TaskDescription @switches [delete: :boolean] @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) case args do [] -> list() ["$" <> _key | _] -> Mix.raise("Invalid key name") [key] -> if opts[:delete] do delete(key) else read(key) end [key, value] -> set(key, value) _ -> Mix.raise(""" Invalid arguments, expected: mix hex.config KEY [VALUE] """) end end @impl true def tasks() do [ {"", "Reads, updates or deletes local Hex config"}, {"KEY", "Get config value for KEY"}, {"KEY --delete", "Delete config value for KEY"}, {"KEY VALUE", "Set config KEY to VALUE"} ] end defp list() do Enum.each(valid_read_keys(), fn {config, _internal} -> read(config, true) end) end defp read(key, verbose \\ false) defp read(key, verbose) when is_binary(key) do key = String.to_atom(key) case Keyword.fetch(valid_read_keys(), key) do {:ok, internal} -> fetch_current_value_and_print(internal, key, verbose) _error -> Mix.raise("The key #{key} is not valid") end end defp read(key, verbose) when is_atom(key), do: read(to_string(key), verbose) defp fetch_current_value_and_print(internal, key, verbose) do case Map.fetch(Hex.State.get_all(), internal) do {:ok, {{:env, env_var}, value}} -> print_value(key, value, verbose, "(using `#{env_var}`)") {:ok, {{:global_config, _key}, value}} -> print_value(key, value, verbose, "(using `#{config_path()}`)") {:ok, {{:project_config, _key}, value}} -> print_value(key, value, verbose, "(using `mix.exs`)") {:ok, {kind, value}} when kind in [:default, :computed] -> print_value(key, value, verbose, "(default)") :error -> Mix.raise("Config does not contain the key #{key}") end end defp print_value(key, value, true, source), do: Hex.Shell.info("#{key}: #{inspect(value, pretty: true)} #{source}") defp print_value(_key, value, false, _source), do: Hex.Shell.info(inspect(value, pretty: true)) defp delete(key) do key = String.to_atom(key) if Keyword.has_key?(valid_write_keys(), key) do Hex.Config.remove([key]) end end defp set(key, value) do key = String.to_atom(key) if Keyword.has_key?(valid_write_keys(), key) do Hex.Config.update([{key, value}]) else Mix.raise("Invalid key #{key}") end end defp config_path() do :config_home |> Hex.State.fetch!() |> Path.join("hex.config") end defp valid_keys() do Enum.map(Hex.State.config(), fn {internal, map} -> [config | _] = Map.get(map, :config, [nil]) [env | _] = Map.get(map, :env, [nil]) cond do String.starts_with?(to_string(config), "$") -> {internal, config, :not_accessible} is_nil(config) and not is_nil(env) -> {internal, config, :env_only} is_nil(config) and is_nil(env) -> {internal, config, :read_only} true -> {internal, config, :read_and_write} end end) end defp valid_read_keys() do valid_keys() |> Enum.map(fn {internal, config, access} -> if access != :not_accessible, do: key_representation(internal, config) end) |> Enum.filter(&(&1 != nil)) end defp valid_write_keys() do valid_keys() |> Enum.map(fn {internal, config, access} -> if access == :read_and_write, do: key_representation(internal, config) end) |> Enum.filter(&(&1 != nil)) end defp key_representation(internal, nil), do: {internal, internal} defp key_representation(internal, config), do: {config, internal} end hex-2.0.6/lib/mix/tasks/hex.docs.ex000066400000000000000000000270531437023760000170550ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Docs do use Mix.Task @shortdoc "Fetches or opens documentation of a package" @moduledoc """ Fetches or opens documentation of a package. If no version is specified, defaults to version used in the current mix project. If called outside of a mix project or the dependency is not used in the current mix project, defaults to the latest version. ## Fetch documentation for all dependencies in the current mix project $ mix hex.docs fetch ## Fetch documentation for offline use Fetches documentation for the specified package that you can later open with `mix hex.docs offline`. $ mix hex.docs fetch PACKAGE [VERSION] ## Open a browser window with offline documentation $ mix hex.docs offline PACKAGE [VERSION] ## Open a browser window with online documentation $ mix hex.docs online PACKAGE [VERSION] ## Command line options * `--module Some.Module` - Open a specified module documentation page inside desired package * `--organization ORGANIZATION` - Set this for private packages belonging to an organization * `--latest` - Looks for the latest release of a package * `--format epub` - When opening documentation offline, use this flag to open the epub formatted version """ @behaviour Hex.Mix.TaskDescription @elixir_apps ~w(eex elixir ex_unit iex logger mix) @switches [module: :string, organization: :string, latest: :boolean, format: :string] @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) opts = Keyword.put(opts, :mix_project, !!Mix.Project.get()) case args do ["fetch" | remaining] -> fetch_docs(remaining, opts) ["online" | remaining] -> open_docs(remaining, opts) ["offline" | remaining] -> open_docs_offline(remaining, opts) _ -> Mix.raise(""" Invalid arguments, expected one of: mix hex.docs fetch mix hex.docs fetch PACKAGE [VERSION] mix hex.docs offline PACKAGE [VERSION] mix hex.docs online PACKAGE [VERSION] """) end end @impl true def tasks() do [ {"fetch PACKAGE [VERSION]", "Fetch documentation for offline use"}, {"offline PACKAGE [VERSION]", "Open a browser window with offline documentation"}, {"online PACKAGE [VERSION]", "Open a browser window with online documentation"} ] end defp fetch_docs([] = _args, opts) do if !opts[:mix_project] do Mix.raise( "Specify a package name or run inside a Mix project " <> "to fetch docs for all dependencies" ) end Enum.each(deps_in_lock(), fn package -> fetch_docs([package.name, package.version], organization: package.repo) end) end defp fetch_docs([name], opts) when name in @elixir_apps do fetch_docs([name, System.version()], opts) end defp fetch_docs([name], opts) do locked_or_latest_version = find_package_locked_or_latest_version(name, opts) fetch_docs([name, locked_or_latest_version], opts) end defp fetch_docs([name, version], opts) do target_dir = Path.join([docs_dir(), org_to_path(opts[:organization]), name, version]) fallback_dir = Path.join([docs_dir(), name, version]) cond do File.exists?(target_dir) -> Hex.Shell.info("Docs already fetched: #{target_dir}") File.exists?(fallback_dir) -> Hex.Shell.info("Docs already fetched: #{fallback_dir}") true -> target = Path.join(target_dir, "#{name}-#{version}.tar.gz") success? = download_docs(opts[:organization], name, version, target) if success? do extract_docs(target, target_dir) end end end defp find_package_locked_or_latest_version(name, opts) do package_in_lock = package_in_lock(name) if opts[:mix_project] && !opts[:latest] && package_in_lock do package_in_lock.version else find_package_latest_version(opts[:organization], name) end end defp find_package_latest_version(organization, name) do %{"releases" => releases} = retrieve_package_info(organization, name) sorted_versions = Enum.sort(releases, &(Version.compare(&1["version"], &2["version"]) == :gt)) if Enum.all?(sorted_versions, &pre_release?/1) do sorted_versions |> List.first() |> Map.get("version") else sorted_versions |> Enum.reject(&pre_release?/1) |> List.first() |> Map.get("version") end end defp retrieve_package_info(organization, name) do auth = if organization, do: Mix.Tasks.Hex.auth_info(:read) case Hex.API.Package.get(organization, name, auth) do {:ok, {code, body, _}} when code in 200..299 -> body {:ok, {404, _, _}} -> Mix.raise("No package with name #{name}") other -> Hex.Shell.error("Failed to retrieve package information") Hex.Utils.print_error_result(other) end end defp open_docs([] = _args, _opts) do Mix.raise("You must specify the name of a package") end defp open_docs([name], opts) do package_in_lock = package_in_lock(name) if opts[:mix_project] && !opts[:latest] && package_in_lock do version = package_in_lock.version open_docs([name, version], opts) else open_latest_docs([name], opts) end end defp open_docs([name, version], opts) do get_docs_url([name, version], opts) |> browser_open() end defp open_latest_docs(args, opts) do args |> get_docs_url(opts) |> browser_open() end defp open_docs_offline([] = _args, _opts) do Mix.raise("You must specify the name of a package") end defp open_docs_offline([name], opts) do package_in_lock = package_in_lock(name) if opts[:mix_project] && !opts[:latest] && package_in_lock do latest_version = package_in_lock.version open_docs_offline([name, latest_version], opts) else open_latest_docs_offline(name, opts) end end defp open_docs_offline([name, version], opts) do docs_location = docs_location(opts[:organization], name, version, opts) if docs_location do open_file(docs_location) else fetch_docs([name, version], opts) docs_location = docs_location(opts[:organization], name, version, opts) if docs_location do open_file(docs_location) end end end defp open_latest_docs_offline(name, opts) do latest_version = find_package_version(opts[:organization], name) if latest_version do open_docs_offline([name, latest_version], opts) else fetch_docs([name], opts) latest_version = find_package_version(opts[:organization], name) if latest_version do open_docs_offline([name, latest_version], opts) end end end defp docs_location(organization, name, version, opts) do format = Keyword.get(opts, :format, "html") module = Keyword.get(opts, :module, "index") default_path = Path.join([docs_dir(), org_to_path(organization), name, version]) fallback_path = Path.join([docs_dir(), name, version]) case format do "epub" -> epub_file_location(default_path, fallback_path, organization) "html" -> html_file_location(default_path, fallback_path, module, organization) end end defp html_file_location(default_path, fallback_path, module, organization) do default_path = Path.join([default_path, module <> ".html"]) fallback_path = Path.join([fallback_path, module <> ".html"]) cond do File.exists?(default_path) -> default_path !organization && File.exists?(fallback_path) -> fallback_path true -> nil end end defp epub_file_location(default_path, fallback_path, organization) do default_path = Path.wildcard(Path.join([default_path, "*.epub"])) fallback_path = Path.wildcard(Path.join([fallback_path, "*.epub"])) cond do length(default_path) == 1 -> Enum.at(default_path, 0) !organization && length(fallback_path) == 1 -> Enum.at(fallback_path, 0) true -> Mix.raise("No documentation found in epub format.") end end defp find_package_version(organization, name) do default_path = Path.join([docs_dir(), org_to_path(organization), name]) fallback_path = Path.join([docs_dir(), name]) cond do File.exists?(default_path) -> find_latest_version(default_path) !organization && File.exists?(fallback_path) -> find_latest_version(fallback_path) true -> nil end end defp get_docs_url([name], opts) do if module = opts[:module] do Hex.Utils.hexdocs_module_url(opts[:organization], name, module) else Hex.Utils.hexdocs_url(opts[:organization], name) end end defp get_docs_url([name, version], opts) do if module = opts[:module] do Hex.Utils.hexdocs_module_url(opts[:organization], name, version, module) else Hex.Utils.hexdocs_url(opts[:organization], name, version) end end defp browser_open(path) do path |> open_cmd() |> system_cmd() end defp open_cmd(path) do case :os.type() do {:win32, _} -> dirname = Path.dirname(path) basename = Path.basename(path) {"cmd", ["/c", "start", basename], [cd: dirname]} {:unix, :darwin} -> {"open", [path], []} {:unix, _} -> {"xdg-open", [path], []} end end if Mix.env() == :test do defp system_cmd({cmd, args, options}) do send(self(), {:hex_system_cmd, cmd, args, options}) end else defp system_cmd({cmd, args, options}) do System.cmd(cmd, args, options) end end defp open_file(path) do unless path do Mix.raise("Documentation not found") end unless File.exists?(path) do Mix.raise("Documentation file not found: #{path}") end browser_open(path) end defp find_latest_version(path) do sorted_versions = path |> File.ls!() |> Enum.sort(&(Version.compare(&1, &2) == :gt)) if Enum.all?(sorted_versions, &pre_release?/1) do List.first(sorted_versions) else sorted_versions |> Enum.reject(&pre_release?/1) |> List.first() end end defp download_docs(organization, package, version, target) do repo = org_to_repo(organization) case Hex.Repo.get_docs(repo, package, version) do {:ok, {200, body, _}} -> File.mkdir_p!(Path.dirname(target)) File.write!(target, body) true _ -> message = "Couldn't find docs for package with name #{package} or version #{version}" Hex.Shell.error(message) false end end defp extract_docs(target, target_dir) do File.mkdir_p!(target_dir) fd = File.open!(target, [:read, :compressed]) :ok = :mix_hex_erl_tar.extract({:file, fd}, [:compressed, cwd: Path.dirname(target)]) Hex.Shell.info("Docs fetched: #{target_dir}") end defp docs_dir() do Path.join(Hex.State.fetch!(:data_home), "docs") end defp package_in_lock(name) do Enum.find(deps_in_lock(), &(&1.name == name)) end defp deps_in_lock() do Mix.Dep.Lock.read() |> Enum.map(fn {_app, info} -> Hex.Utils.lock(info) end) |> Enum.reject(&is_nil/1) end defp org_to_repo(organization) when organization in [nil, "hexpm"], do: "hexpm" defp org_to_repo(organization), do: "hexpm:#{organization}" defp org_to_path(organization) do organization |> org_to_repo() |> Hex.Utils.windows_repo_path_fix() end defp pre_release?(%{"version" => version}), do: do_pre_release?(version) defp pre_release?(version), do: do_pre_release?(version) defp do_pre_release?(version) do case Version.parse(version) do {:ok, %Version{pre: []}} -> false {:ok, %Version{}} -> true _ -> false end end end hex-2.0.6/lib/mix/tasks/hex.ex000066400000000000000000000257051437023760000161300ustar00rootroot00000000000000defmodule Mix.Tasks.Hex do use Mix.Task @apikey_tag "HEXAPIKEY" @shortdoc "Prints Hex help information" @moduledoc """ Prints Hex tasks and their information. $ mix hex See `mix help hex.config` to see all available configuration options. """ @impl true def run(_args) do Hex.start() Hex.Shell.info("Hex v" <> Hex.version()) Hex.Shell.info("Hex is a package manager for the Erlang ecosystem.") print_available_tasks() Hex.Shell.info("Further information can be found here: https://hex.pm/docs") end defp print_available_tasks() do line_break() Hex.Shell.info("Available tasks:") line_break() pattern = "hex." modules = Enum.filter(load_tasks(), &String.contains?(Mix.Task.task_name(&1), pattern)) {docs, max} = build_task_doc_list(modules) display_doc_list(docs, max) line_break() end defp load_tasks() do Enum.filter(Mix.Task.load_all(), &(Mix.Task.moduledoc(&1) != false)) end defp build_task_doc_list(modules) do Enum.reduce(modules, {[], 0}, fn module, {docs, max} -> task = "mix " <> Mix.Task.task_name(module) task_list = if Keyword.has_key?(module.__info__(:functions), :tasks) do Enum.map(module.tasks(), fn {subtask, docs} -> {"#{task} #{subtask}", docs} end) else [] end max = Enum.reduce(task_list, max, fn {task, _}, max_now -> max(byte_size(task), max_now) end) if Enum.empty?(task_list) do {docs, max} else {docs ++ [task_list], max} end end) end defp display_doc_list(docs, max) do Enum.each(Enum.sort_by(docs, &List.first/1), fn tasks -> Enum.each(tasks, fn {task, doc} -> Mix.shell().info(format_task(task, max, doc)) end) line_break() end) end defp format_task(task, max, doc) do String.pad_trailing(task, max) <> " # " <> doc end defp line_break(), do: Hex.Shell.info("") @doc false def print_table(header, values) do header = Enum.map(header, &[:underline, &1]) widths = widths([header | values]) print_row(header, widths) Enum.each(values, &print_row(&1, widths)) end defp ansi_length(binary) when is_binary(binary) do byte_size(binary) end defp ansi_length(list) when is_list(list) do Enum.reduce(list, 0, &(ansi_length(&1) + &2)) end defp ansi_length(atom) when is_atom(atom) do 0 end defp print_row(strings, widths) do Enum.zip(strings, widths) |> Enum.map(fn {string, width} -> pad_size = width - ansi_length(string) + 2 pad = :lists.duplicate(pad_size, ?\s) [string || "", :reset, pad] end) |> IO.ANSI.format() |> Hex.Shell.info() end defp widths([head | tail]) do widths = Enum.map(head, &ansi_length/1) Enum.reduce(tail, widths, fn list, acc -> Enum.zip(list, acc) |> Enum.map(fn {string, width} -> max(width, ansi_length(string)) end) end) end @doc false def auth(opts \\ []) do username = Hex.Shell.prompt("Username:") |> String.trim() account_password = Mix.Tasks.Hex.password_get("Account password:") |> String.trim() Mix.Tasks.Hex.generate_all_user_keys(username, account_password, opts) end @local_password_prompt "You have authenticated on Hex using your account password. However, " <> "Hex requires you to have a local password that applies only to this machine for security " <> "purposes. Please enter it." @doc false def generate_user_key(key_name, permissions, opts) do case Hex.API.Key.new(key_name, permissions, opts) do {:ok, {201, body, _}} -> {:ok, body["secret"]} other -> Mix.shell().error("Generation of key failed") Hex.Utils.print_error_result(other) :error end end @doc false def generate_all_user_keys(username, password, opts \\ []) do Hex.Shell.info("Generating keys...") auth = [user: username, pass: password] key_name = api_key_name(opts[:key_name]) permissions = [%{"domain" => "api"}] case generate_user_key(key_name, permissions, auth) do {:ok, write_key} -> key_name = api_key_name(opts[:key_name], "read") permissions = [%{"domain" => "api", "resource" => "read"}] case generate_user_key(key_name, permissions, key: write_key) do {:ok, read_key} -> key_name = repositories_key_name(opts[:key_name]) permissions = [%{"domain" => "repositories"}] case generate_user_key(key_name, permissions, key: write_key) do {:ok, organization_key} -> auth_organization("hexpm", organization_key) Hex.Shell.info(@local_password_prompt) prompt_encrypt_key(write_key, read_key) {:ok, write_key, read_key, organization_key} :error -> :ok end :error -> :error end :error -> :error end end @doc false def generate_organization_key(organization_name, key_name, permissions, auth \\ nil) do auth = auth || auth_info(:write) case Hex.API.Key.Organization.new(organization_name, key_name, permissions, auth) do {:ok, {201, body, _}} -> {:ok, body["secret"]} other -> Mix.shell().error("Generation of key failed") Hex.Utils.print_error_result(other) :error end end @doc false def general_key_name(nil) do {:ok, hostname} = :inet.gethostname() List.to_string(hostname) end def general_key_name(key) do key end @doc false def api_key_name(key, extra \\ nil) do {:ok, hostname} = :inet.gethostname() name = "#{key || hostname}-api" if extra, do: "#{name}-#{extra}", else: name end @doc false def repository_key_name(organization, key) do {:ok, hostname} = :inet.gethostname() "#{key || hostname}-repository-#{organization}" end @doc false def repositories_key_name(key) do {:ok, hostname} = :inet.gethostname() "#{key || hostname}-repositories" end @doc false def update_keys(write_key, read_key \\ nil) do Hex.Config.update( "$write_key": write_key, "$read_key": read_key, "$encrypted_key": nil, encrypted_key: nil ) Hex.State.put(:api_key_write, write_key) Hex.State.put(:api_key_read, read_key) end @doc false def auth_organization(name, key) do repo = Hex.Repo.get_repo(name) || Hex.Repo.default_hexpm_repo() repo = Map.put(repo, :auth_key, key) Hex.State.fetch!(:repos) |> Map.put(name, repo) |> Hex.Config.update_repos() end @doc false def auth_info(permission, opts \\ []) def auth_info(:write, opts) do api_key_write_unencrypted = Hex.State.fetch!(:api_key_write_unencrypted) api_key_write = Hex.State.fetch!(:api_key_write) cond do api_key_write_unencrypted -> [key: api_key_write_unencrypted] api_key_write -> [key: prompt_decrypt_key(api_key_write)] Keyword.get(opts, :auth_inline, true) -> authenticate_inline() true -> [] end end def auth_info(:read, opts) do api_key_write_unencrypted = Hex.State.fetch!(:api_key_write_unencrypted) api_key_read = Hex.State.fetch!(:api_key_read) cond do api_key_write_unencrypted -> [key: api_key_write_unencrypted] api_key_read -> [key: api_key_read] Keyword.get(opts, :auth_inline, true) -> authenticate_inline() true -> [] end end defp authenticate_inline() do authenticate? = Hex.Shell.yes?("No authenticated user found. Do you want to authenticate now?") if authenticate? do case auth() do {:ok, write_key, _read_key, _org_key} -> [key: write_key] :error -> no_auth_error() end else no_auth_error() end end defp no_auth_error() do Mix.raise("No authenticated user found. Run `mix hex.user auth`") end @doc false def prompt_encrypt_key(write_key, read_key, challenge \\ "Local password") do password = password_get("#{challenge}:") |> String.trim() confirm = password_get("#{challenge} (confirm):") |> String.trim() if password != confirm do Hex.Shell.error("Entered passwords do not match. Try again") prompt_encrypt_key(write_key, read_key, challenge) else encrypted_write_key = Hex.Crypto.encrypt(write_key, password, @apikey_tag) update_keys(encrypted_write_key, read_key) end end @doc false def prompt_decrypt_key(encrypted_key, challenge \\ "Local password") do password = password_get("#{challenge}:") |> String.trim() case Hex.Crypto.decrypt(encrypted_key, password, @apikey_tag) do {:ok, key} -> key :error -> Hex.Shell.error("Wrong password. Try again") prompt_decrypt_key(encrypted_key, challenge) end end @doc false def encrypt_key(password, key) do Hex.Crypto.encrypt(key, password, @apikey_tag) end @doc false def decrypt_key(password, key) do Hex.Crypto.decrypt(key, password, @apikey_tag) end @doc false def required_opts(opts, required) do Enum.map(required, fn req -> unless Keyword.has_key?(opts, req) do Mix.raise("Missing command line option: #{req}") end end) end @doc false def convert_permissions([]) do nil end @doc false def convert_permissions(permissions) do Enum.map(permissions, fn permission -> permission = String.downcase(permission) destructure [domain, resource], String.split(permission, ":", parts: 2) %{"domain" => domain, "resource" => resource} end) end # Password prompt that hides input by every 1ms # clearing the line with stderr @doc false def password_get(prompt) do if Hex.State.fetch!(:clean_pass) do password_clean(prompt) else Hex.Shell.prompt(prompt <> " ") end end defp password_clean(prompt) do pid = spawn_link(fn -> loop(prompt) end) ref = make_ref() value = IO.gets(prompt <> " ") send(pid, {:done, self(), ref}) receive do: ({:done, ^pid, ^ref} -> :ok) value end defp loop(prompt) do receive do {:done, parent, ref} -> send(parent, {:done, self(), ref}) IO.write(:standard_error, "\e[2K\r") after 1 -> IO.write(:standard_error, "\e[2K\r#{prompt} ") loop(prompt) end end @progress_steps 25 @doc false def progress(nil) do fn _ -> nil end end def progress(max) do put_progress(0, 0) fn size -> fraction = size / max completed = trunc(fraction * @progress_steps) put_progress(completed, trunc(fraction * 100)) size end end defp put_progress(completed, percent) do unfilled = @progress_steps - completed str = "\r[#{String.duplicate("#", completed)}#{String.duplicate(" ", unfilled)}]" IO.write(:stderr, str <> " #{percent}%") end if Mix.env() == :test do @doc false def set_exit_code(code), do: throw({:exit_code, code}) else @doc false def set_exit_code(code), do: System.at_exit(fn _ -> System.halt(code) end) end end hex-2.0.6/lib/mix/tasks/hex.info.ex000066400000000000000000000142011437023760000170470ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Info do use Mix.Task @shortdoc "Prints Hex information" @moduledoc """ Prints Hex package or system information. $ mix hex.info [PACKAGE [VERSION]] If `package` is not given, print system information. This includes when registry was last updated and current system version. If `package` is given, print information about the package. This includes all released versions and package metadata. If `package` and `version` is given, print release information. ## Command line options * `--organization ORGANIZATION` - Set this for private packages belonging to an organization """ @behaviour Hex.Mix.TaskDescription @switches [organization: :string] @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) case args do [] -> general() [package] -> package(opts[:organization], package) [package, version] -> release(opts[:organization], package, version) _ -> Mix.raise(""" Invalid arguments, expected: mix hex.info [PACKAGE [VERSION]] """) end end @impl true def tasks() do [ {"", "Prints Hex information"}, {"PACKAGE [VERSION]", "Prints package information"} ] end defp general() do Hex.Shell.info("Hex: #{Hex.version()}") Hex.Shell.info("Elixir: #{System.version()}") Hex.Shell.info("OTP: #{Hex.Utils.otp_version()}") Hex.Shell.info("") Hex.Shell.info("Built with: Elixir #{Hex.elixir_version()} and OTP #{Hex.otp_version()}") Hex.Registry.Server.open() Hex.UpdateChecker.check() Hex.Registry.Server.close() end defp package(organization, package) do auth = organization && Mix.Tasks.Hex.auth_info(:read) case Hex.API.Package.get(organization, package, auth) do {:ok, {code, body, _}} when code in 200..299 -> print_package(body, locked_dep(package)) {:ok, {404, _, _}} -> Hex.Shell.error("No package with name #{package}") Mix.Tasks.Hex.set_exit_code(1) other -> Hex.Shell.error("Failed to retrieve package information") Hex.Utils.print_error_result(other) Mix.Tasks.Hex.set_exit_code(1) end end defp release(organization, package, version) do auth = organization && Mix.Tasks.Hex.auth_info(:read) case Hex.API.Release.get(organization, package, version, auth) do {:ok, {code, body, _}} when code in 200..299 -> print_release(organization, package, body) {:ok, {404, _, _}} -> Hex.Shell.error("No release with name #{package} #{version}") Mix.Tasks.Hex.set_exit_code(1) other -> Hex.Shell.error("Failed to retrieve release information") Hex.Utils.print_error_result(other) Mix.Tasks.Hex.set_exit_code(1) end end defp print_package(package, locked_package) do meta = package["meta"] desc = meta["description"] || "No description provided" Hex.Shell.info(desc <> "\n") releases = package["releases"] || [] retirements = package["retirements"] || %{} Hex.Shell.info("Config: " <> package["configs"]["mix.exs"]) print_locked_package(locked_package) Hex.Shell.info(["Releases: "] ++ format_releases(releases, Map.keys(retirements)) ++ ["\n"]) print_meta(meta) end defp format_releases(releases, retirements) do {releases, rest} = Enum.split(releases, 8) Enum.map(releases, &format_version(&1, retirements)) |> Enum.intersperse([", "]) |> add_ellipsis(rest) end defp format_version(%{"version" => version}, retirements) do if version in retirements do [:yellow, version, " (retired)", :reset] else [version] end end defp add_ellipsis(output, []), do: output defp add_ellipsis(output, _rest), do: output ++ [", ..."] defp print_meta(meta) do print_list(meta, "licenses") print_dict(meta, "links") end defp print_release(organization, package, release) do version = release["version"] print_retirement(release) Hex.Shell.info("Config: " <> release["configs"]["mix.exs"]) if release["has_docs"] do Hex.Shell.info("Documentation at: #{Hex.Utils.hexdocs_url(organization, package, version)}") end if requirements = release["requirements"] do Hex.Shell.info("Dependencies:") Enum.each(requirements, fn {name, req} -> app = req["app"] app = if app && app != name, do: " (app: #{app})" optional = if req["optional"], do: " (optional)" Hex.Shell.info(" #{name} #{req["requirement"]}#{app}#{optional}") end) end print_publisher(release) end defp print_locked_package(nil), do: nil defp print_locked_package(locked_package) do Hex.Shell.info(["Locked version: #{locked_package.version}"]) end defp print_retirement(%{"retirement" => nil}), do: "" defp print_retirement(release) do retirement = %{ reason: release["retirement"]["reason"], message: release["retirement"]["message"] } Hex.Shell.warn([ [:bright, "This version has been retired"], [:normal, ": "], [:normal, Hex.Utils.package_retirement_message(retirement)] ]) end defp print_publisher(release) do publisher_username = release["publisher"]["username"] publisher_email = release["publisher"]["email"] email_or_empty = if publisher_email, do: " (#{publisher_email})", else: "" Hex.Shell.info("Published by: #{publisher_username}#{email_or_empty}") end defp print_list(meta, name) do list = Map.get(meta, name, []) if list != [] do Hex.Shell.info(String.capitalize(name) <> ": " <> Enum.join(list, ", ")) end end defp print_dict(meta, name) do title = String.capitalize(name) dict = Map.get(meta, name, []) if dict != [] do Hex.Shell.info(title <> ":") Enum.each(dict, fn {key, val} -> Hex.Shell.info(" #{key}: #{val}") end) end end # Pull out the locked dependency version, if it exists defp locked_dep(package_name) do Mix.Dep.Lock.read() |> Enum.map(fn {_app, info} -> Hex.Utils.lock(info) end) |> Enum.find(fn locked -> locked && locked.name == package_name end) end end hex-2.0.6/lib/mix/tasks/hex.organization.ex000066400000000000000000000207641437023760000206330ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Organization do use Mix.Task @shortdoc "Manages Hex.pm organizations" @moduledoc """ Manages the list of authorized Hex.pm organizations. Organizations is a feature of Hex.pm to host and manage private packages. See for more information. By default you will be authorized to all your applications when running `mix hex.user auth` and this is the recommended approach. This task is mainly provided for a CI and build systems where access to an organization is needed without authorizing a user. By authorizing a new organization a new key is created for fetching packages from the organizations repository and the repository key is stored on the local machine. To use a package from an organization add `organization: "my_organization"` to the dependency declaration in `mix.exs`: {:plug, "~> 1.0", organization: "my_organization"} ## Authorize an organization This command will generate an API key used to authenticate access to the organization. See the `hex.user` tasks to list and control all your active API keys. $ mix hex.organization auth ORGANIZATION [--key KEY] [--key-name KEY_NAME] ## Deauthorize and remove an organization $ mix hex.organization deauth NAME ## List all authorized organizations This command will only list organizations you have authorized with this task, it will not list organizations you have access to by having authorized with `mix hex.user auth`. $ mix hex.organization list ## Generate organization key This command is useful to pre-generate keys for use with `mix hex.organization auth ORGANIZATION --key KEY` on CI servers or similar systems. It returns the hash of the generated key that you can pass to `auth ORGANIZATION --key KEY`. Unlike the `hex.user key` commands, a key generated with this command is owned by the organization directly, and not the user that generated it. This makes it ideal for shared environments such as CI where you don't want to give access to user-specific resources and the user's organization membership status won't affect key. By default this command sets the `repository:organization_name` permission which allows read-only access to the organization's repository, it can be overridden with the `--permission` flag. $ mix hex.organization key ORGANIZATION generate [--key-name KEY_NAME] [--permission PERMISSION] ## Revoke key Removes given key from organization. The key can no longer be used to authenticate API requests. $ mix hex.organization key ORGANIZATION revoke KEY_NAME ## Revoke all keys Revoke all keys from the organization. $ mix hex.organization key ORGANIZATION revoke --all ## List keys Lists all keys associated with the organization. $ mix hex.organization key ORGANIZATION list ## Command line options * `--key KEY` - Hash of key used to authenticate HTTP requests to repository, if omitted will generate a new key with your account credentials. This flag is useful if you have a key pre-generated with `mix hex.organization key` and want to authenticate on a CI server or similar system * `--key-name KEY_NAME` - By default Hex will base the key name on your machine's hostname and the organization name, use this option to give your own name. * `--permission PERMISSION` - Sets the permissions on the key, this option can be given multiple times, possibly values are: * `api:read` - API read access. * `api:write` - API write access. * `repository:organization_name` - Access to the organization's repository (this is the default permission). """ @behaviour Hex.Mix.TaskDescription @switches [ all: :boolean, key_name: :string, key: :string, permission: [:string, :keep] ] @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, switches: @switches) case args do ["auth", name] -> auth(name, opts) ["deauth", name] -> deauth(name) ["key", name, "generate"] -> key_generate(name, opts) ["key", name, "revoke", key_name] -> key_revoke(name, key_name) ["key", name, "revoke"] -> if opts[:all], do: key_revoke_all(name), else: invalid_args() ["key", name, "list"] -> key_list(name) ["list"] -> list() _ -> invalid_args() end end @impl true def tasks() do [ {"auth ORGANIZATION", "Authorize an organization"}, {"deauth ORGANIZATION", "Deauthorize and remove organization"}, {"list", "List all authorized organizations"}, {"key ORGANIZATION generate", "Generate organization key"}, {"key ORGANIZATION revoke KEY_NAME", "Revoke key"}, {"key ORGANIZATION revoke --all", "Revoke all keys"}, {"key ORGANIZATION list", "List keys"} ] end defp invalid_args() do Mix.raise(""" Invalid arguments, expected one of: mix hex.organization auth ORGANIZATION mix hex.organization deauth ORGANIZATION mix hex.organization list mix hex.organization key ORGANIZATION generate mix hex.organization key ORGANIZATION revoke KEY_NAME mix hex.organization key ORGANIZATION revoke --all mix hex.organization key ORGANIZATION list """) end defp auth(organization, opts) do key = opts[:key] key = if key do test_key(key, organization) key else key_name = Mix.Tasks.Hex.repository_key_name(organization, opts[:key_name]) permissions = [%{"domain" => "repository", "resource" => organization}] auth = Mix.Tasks.Hex.auth_info(:write) case Mix.Tasks.Hex.generate_user_key(key_name, permissions, auth) do {:ok, key} -> key :error -> nil end end if key do Mix.Tasks.Hex.auth_organization("hexpm:#{organization}", key) end end defp deauth(name) do Hex.State.fetch!(:repos) |> Map.delete("hexpm:#{name}") |> Hex.Config.update_repos() end defp key_revoke_all(organization) do auth = Mix.Tasks.Hex.auth_info(:write) Hex.Shell.info("Revoking all keys...") case Hex.API.Key.Organization.delete_all(organization, auth) do {:ok, {code, _body, _headers}} when code in 200..299 -> :ok other -> Hex.Shell.error("Key revocation failed") Hex.Utils.print_error_result(other) end end defp key_revoke(organization, key) do auth = Mix.Tasks.Hex.auth_info(:write) Hex.Shell.info("Revoking key #{key}...") case Hex.API.Key.Organization.delete(organization, key, auth) do {:ok, {code, _body, _headers}} when code in 200..299 -> :ok other -> Hex.Shell.error("Key revocation failed") Hex.Utils.print_error_result(other) end end # TODO: print permissions defp key_list(organization) do auth = Mix.Tasks.Hex.auth_info(:read) case Hex.API.Key.Organization.get(organization, auth) do {:ok, {code, body, _headers}} when code in 200..299 -> values = Enum.map(body, fn %{"name" => name, "inserted_at" => time} -> [name, time] end) Mix.Tasks.Hex.print_table(["Name", "Created at"], values) other -> Hex.Shell.error("Key fetching failed") Hex.Utils.print_error_result(other) end end defp key_generate(organization, opts) do key_name = Mix.Tasks.Hex.general_key_name(opts[:key_name]) default_permission = [%{"domain" => "repository", "resource" => organization}] permissions = Keyword.get_values(opts, :permission) permissions = Mix.Tasks.Hex.convert_permissions(permissions) || default_permission result = Mix.Tasks.Hex.generate_organization_key( organization, key_name, permissions ) case result do {:ok, secret} -> Hex.Shell.info(secret) :error -> :ok end end defp list() do Enum.each(Hex.State.fetch!(:repos), fn {name, _repo} -> case String.split(name, ":", parts: 2) do ["hexpm", name] -> Hex.Shell.info(name) _ -> :ok end end) end defp test_key(key, name) do case Hex.API.Auth.get("repository", name, key: key) do {:ok, {code, _body, _}} when code in 200..299 -> :ok {:ok, {code, _body, _}} when code in [401, 403] -> Hex.Shell.error("Failed to authenticate against organization repository with given key") other -> Hex.Utils.print_error_result(other) Hex.Shell.error("Failed to verify authentication key") end end end hex-2.0.6/lib/mix/tasks/hex.outdated.ex000066400000000000000000000226431437023760000177360ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Outdated do use Mix.Task alias Hex.Registry.Server, as: Registry @shortdoc "Shows outdated Hex deps for the current project" @moduledoc """ Shows all Hex dependencies that have newer versions in the registry. $ mix hex.outdated [APP] By default, it only shows top-level packages explicitly listed in the `mix.exs` file. All outdated packages can be displayed by using the `--all` command line option. By default, `hex.outdated` will exit with a non-zero exit code (1) if there are any outdated dependencies. You can override this to respect the requirements as specified in your `mix.exs` file, with the `--within-requirements` command line option, so it only exits with non-zero exit code if the update is possible. For example, if your version requirement is "~> 2.0" but the latest version is `3.0`, with `--within-requirements` it will exit successfully, but if the latest version is `2.8`, then `--within-requirements` will exit with non-zero exit code (1). One scenario this could be useful is to ensure you always have the latest version of your dependencies, except for major version bumps. If a dependency name is given all requirements on that dependency, from the entire dependency tree, are listed. This is useful if you are trying to figure why a package isn't updating when you run `mix deps.update`. Note that when this task determines if a package is updatable it only looks at the project's current set of dependency requirements and what version they are locked to. When `mix deps.update` is called multiple packages may be updated that in turn update their own dependencies, which may cause the package you want to update to not be able to update. ## Command line options * `--all` - shows all outdated packages, including children of packages defined in `mix.exs` * `--pre` - include pre-releases when checking for newer versions * `--within-requirements` - exit with non-zero code only if requirements specified in `mix.exs` is met. """ @behaviour Hex.Mix.TaskDescription @switches [all: :boolean, pre: :boolean, within_requirements: :boolean] @impl true def run(args) do Mix.Tasks.Deps.Loadpaths.run(["--no-compile"]) Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) Registry.open() lock = Mix.Dep.Lock.read() lock |> Hex.Mix.packages_from_lock() |> Hex.Registry.Server.prefetch() case args do [app] -> single(lock, app, opts) [] -> all(lock, opts) _ -> Mix.raise(""" Invalid arguments, expected: mix hex.outdated [APP] """) end end @impl true def tasks() do [ {"", "Shows outdated Hex deps for the current project"}, {"[APP]", "Shows outdated Hex deps for the given dependency"} ] end defp single(lock, app, opts) do app = String.to_atom(app) deps = Hex.Mix.top_level_deps() {repo, package, current} = case Hex.Utils.lock(lock[app]) do %{repo: repo, name: package, version: version} -> {repo, package, version} nil -> Mix.raise("Dependency #{app} not locked as a Hex package") end latest = latest_version(repo, package, current, opts[:pre]) outdated? = Version.compare(current, latest) == :lt lock_requirements = get_requirements_from_lock(app, lock) deps_requirements = get_requirements_from_deps(app, deps) requirements = deps_requirements ++ lock_requirements if outdated? do [ "There is newer version of the dependency available ", [:bright, latest, " > ", current, :reset, "!"] ] |> IO.ANSI.format_fragment() |> Hex.Shell.info() else ["Current version ", :bright, current, :reset, " of dependency is up to date!"] |> IO.ANSI.format_fragment() |> Hex.Shell.info() end header = ["Source", "Requirement", "Up-to-date"] values = Enum.map(requirements, &format_single_row(&1, latest)) Hex.Shell.info("") Mix.Tasks.Hex.print_table(header, values) message = "Up-to-date indicates if the requirement matches the latest version." Hex.Shell.info(["\n", message]) if outdated?, do: Mix.Tasks.Hex.set_exit_code(1) end defp get_requirements_from_lock(app, lock) do Enum.flat_map(lock, fn {source, lock} -> case Hex.Utils.lock(lock) do %{deps: nil} -> [] %{deps: deps} -> Enum.flat_map(deps, fn {dep_app, req, _opts} -> if app == dep_app, do: [[Atom.to_string(source), req]], else: [] end) nil -> [] end end) end defp get_requirements_from_deps(app, deps) do # TODO: Path to umbrella child's mix.exs case Map.fetch(deps, app) do {:ok, deps} -> Enum.map(deps, fn {src, req, _opts} -> [Path.join([src, "mix.exs"]), req] end) :error -> [] end end defp format_single_row([source, req], latest) do req_matches? = version_match?(latest, req) req_color = if req_matches?, do: :green, else: :red up_to_date? = if req_matches?, do: "Yes", else: "No" [[:bright, source], [req_color, req || ""], [req_color, up_to_date?]] end defp all(lock, opts) do deps = Hex.Mix.top_level_deps() dep_names = if opts[:all], do: Map.keys(lock), else: Map.keys(deps) versions = dep_names |> Enum.sort() |> get_versions(deps, lock, opts[:pre]) values = Enum.map(versions, &format_all_row/1) diff_links = Enum.map(versions, &build_diff_link/1) |> Enum.reject(&is_nil/1) if Enum.empty?(values) do Hex.Shell.info("No hex dependencies") else header = ["Dependency", "Current", "Latest", "Status"] Mix.Tasks.Hex.print_table(header, values) base_message = "Run `mix hex.outdated APP` to see requirements for a specific dependency." diff_message = maybe_diff_message(diff_links) Hex.Shell.info(["\n", base_message, diff_message]) any_outdated? = any_outdated?(versions) req_met? = any_req_matches?(versions) cond do any_outdated? && opts[:within_requirements] && req_met? -> Mix.Tasks.Hex.set_exit_code(1) any_outdated? && opts[:within_requirements] && not req_met? -> nil any_outdated? -> Mix.Tasks.Hex.set_exit_code(1) true -> nil end end end defp get_versions(dep_names, deps, lock, pre?) do Enum.flat_map(dep_names, fn name -> case Hex.Utils.lock(lock[name]) do %{repo: repo, name: package, version: lock_version} -> latest_version = latest_version(repo, package, lock_version, pre?) lock_requirements = get_requirements_from_lock(name, lock) deps_requirements = get_requirements_from_deps(name, deps) requirements = (deps_requirements ++ lock_requirements) |> Enum.map(fn [_, req_version] -> req_version end) [[Atom.to_string(name), lock_version, latest_version, requirements]] _ -> [] end end) end defp latest_version(repo, package, default, pre?) do {:ok, default} = Version.parse(default) pre? = pre? || default.pre != [] {:ok, versions} = Registry.versions(repo, package) latest = highest_version(versions, pre?) to_string(latest || default) end defp highest_version(versions, pre?) do versions = if pre? do versions else Enum.filter(versions, fn version -> version.pre == [] end) end List.last(versions) end defp format_all_row([package, lock, latest, requirements]) do outdated? = Version.compare(lock, latest) == :lt latest_color = if outdated?, do: :red, else: :green req_matches? = req_matches?(requirements, latest) status = case {outdated?, req_matches?} do {true, true} -> [:yellow, "Update possible"] {true, false} -> [:red, "Update not possible"] {false, _} -> [:green, "Up-to-date"] end [ [:bright, package], lock, [latest_color, latest], status ] end defp build_diff_link([package, lock, latest, requirements]) do outdated? = Version.compare(lock, latest) == :lt req_matches? = Enum.all?(requirements, &version_match?(latest, &1)) case {outdated?, req_matches?} do {true, true} -> "diffs[]=#{package}:#{lock}:#{latest}" {_, _} -> nil end end defp version_match?(_version, nil), do: true defp version_match?(version, req), do: Version.match?(version, req) defp any_outdated?(versions) do Enum.any?(versions, fn [_package, lock, latest, _requirements] -> Version.compare(lock, latest) == :lt end) end defp maybe_diff_message([]), do: "" defp maybe_diff_message(diff_links) do "\n\nTo view the diffs in each available update, visit:\n" <> diff_link(diff_links) end defp diff_link(diff_links) do long_url = "https://diff.hex.pm/diffs?" <> Enum.join(diff_links, "&") if Hex.State.fetch!(:no_short_urls) do long_url else maybe_get_short_link(long_url) end end defp maybe_get_short_link(long_url) do case Hex.API.ShortURL.create(long_url) do :error -> long_url {:ok, short_url} -> short_url end end defp any_req_matches?(versions) do Enum.any?(versions, fn [_package, _lock, latest, requirements] -> req_matches?(requirements, latest) end) end defp req_matches?(requirements, latest) do Enum.all?(requirements, &version_match?(latest, &1)) end end hex-2.0.6/lib/mix/tasks/hex.owner.ex000066400000000000000000000131611437023760000172520ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Owner do use Mix.Task @shortdoc "Manages Hex package ownership" @moduledoc """ Adds, removes or lists package owners. Package owners have full permissions to the package. They can publish and revert releases and even remove other package owners. ## Add owner Adds an owner to package by specifying the package name and email or username of the new owner. This command also takes a `--level` option, see below for more details. $ mix hex.owner add PACKAGE EMAIL_OR_USERNAME ## Transfer ownership Like `mix hex.owner add` but also removes all existing owners of the package. This task is required to use when transferring ownership of the package to an organization. $ mix hex.owner transfer PACKAGE EMAIL_OR_USERNAME ## Remove owner Removes an owner to package by specifying the package name and email or username of the new owner. $ mix hex.owner remove PACKAGE EMAIL_OR_USERNAME ## List owners Lists all owners of given package. $ mix hex.owner list PACKAGE ## List owned packages Lists all packages owned by the current user. $ mix hex.owner packages ## Command line options * `--level maintainer` - Maintainer level owners have all the powers of package ownership, except they cannot add or remove other package owners * `--level full` - Over the maintainer level, full owners can also add and remove other package owners (default) * `--organization ORGANIZATION` - Set this for private packages belonging to an organization """ @behaviour Hex.Mix.TaskDescription @switches [organization: :string, level: :string] @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) organization = opts[:organization] level = opts[:level] || "full" case args do ["add", package, owner] -> add_owner(organization, package, owner, level) ["transfer", package, owner] -> transfer_owner(organization, package, owner) ["remove", package, owner] -> remove_owner(organization, package, owner) ["list", package] -> list_owners(organization, package) ["packages"] -> list_owned_packages() _ -> Mix.raise(""" Invalid arguments, expected one of: mix hex.owner add PACKAGE EMAIL_OR_USERNAME mix hex.owner transfer PACKAGE EMAIL_OR_USERNAME mix hex.owner remove PACKAGE EMAIL_OR_USERNAME mix hex.owner list PACKAGE mix hex.owner packages """) end end @impl true def tasks() do [ {"add PACKAGE EMAIL_OR_USERNAME", "Adds an owner to package"}, {"transfer PACKAGE EMAIL_OR_USERNAME", "Transfers ownership of a package to another user or organization"}, {"remove PACKAGE EMAIL_OR_USERNAME", "Removes an owner from package"}, {"list PACKAGE", "List all owners of a given package"}, {"packages", "List all packages owned by the current user"} ] end defp add_owner(organization, package, owner, level) when level in ~w[full maintainer] do auth = Mix.Tasks.Hex.auth_info(:write) Hex.Shell.info("Adding owner #{owner} with ownership level #{level} to #{package}") case Hex.API.Package.Owner.add(organization, package, owner, level, false, auth) do {:ok, {code, _body, _headers}} when code in 200..299 -> :ok other -> Hex.Shell.error("Adding owner failed") Hex.Utils.print_error_result(other) end end defp add_owner(_organization, _package, _owner, _level) do Mix.raise("Invalid ownership level, expected one of: full, maintainer") end defp transfer_owner(organization, package, owner) do auth = Mix.Tasks.Hex.auth_info(:write) Hex.Shell.info("Transferring ownership to #{owner} for #{package}") case Hex.API.Package.Owner.add(organization, package, owner, "full", true, auth) do {:ok, {code, _body, _headers}} when code in 200..299 -> :ok other -> Hex.Shell.error("Transferring ownership failed") Hex.Utils.print_error_result(other) end end defp remove_owner(organization, package, owner) do auth = Mix.Tasks.Hex.auth_info(:write) Hex.Shell.info("Removing owner #{owner} from #{package}") case Hex.API.Package.Owner.delete(organization, package, owner, auth) do {:ok, {code, _body, _headers}} when code in 200..299 -> :ok other -> Hex.Shell.error("Removing owner failed") Hex.Utils.print_error_result(other) end end defp list_owners(organization, package) do auth = Mix.Tasks.Hex.auth_info(:read) case Hex.API.Package.Owner.get(organization, package, auth) do {:ok, {code, body, _headers}} when code in 200..299 -> header = ["Email", "Level"] owners = Enum.map(body, &[&1["email"], &1["level"]]) Mix.Tasks.Hex.print_table(header, owners) other -> Hex.Shell.error("Package owner fetching failed") Hex.Utils.print_error_result(other) end end defp list_owned_packages() do auth = Mix.Tasks.Hex.auth_info(:read) case Hex.API.User.me(auth) do {:ok, {code, body, _headers}} when code in 200..299 -> Enum.each(body["packages"], fn package -> name = package_name(package["repository"], package["name"]) Hex.Shell.info("#{name} - #{package["html_url"]}") end) other -> Hex.Shell.error("Listing owned packages failed") Hex.Utils.print_error_result(other) end end defp package_name("hexpm", package_name), do: package_name defp package_name(repository_name, package_name), do: repository_name <> "/" <> package_name end hex-2.0.6/lib/mix/tasks/hex.package.ex000066400000000000000000000253071437023760000175200ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Package do use Mix.Task alias Hex.Registry.Server, as: Registry @shortdoc "Fetches or diffs packages" @default_diff_command "git diff --no-index __PATH1__ __PATH2__" @doc false def default_diff_command(), do: @default_diff_command @moduledoc """ Fetches or diffs packages. ## Fetch package Fetch a package tarball to the current directory. $ mix hex.package fetch PACKAGE [VERSION] [--unpack] [--output PATH] If `version` is not given, use the latest version. You can pipe the fetched tarball to stdout by setting `--output -`. ## Diff package versions $ mix hex.package diff APP VERSION This command compares the project's dependency `APP` against the target package version, unpacking the target version into temporary directory and running a diff command. ## Fetch and diff package contents between versions $ mix hex.package diff PACKAGE VERSION1 VERSION2 $ mix hex.package diff PACKAGE VERSION1..VERSION2 This command fetches package tarballs for both versions, unpacks them into temporary directories and runs a diff command. Afterwards, the temporary directories are automatically deleted. Note, similarly to when tarballs are fetched with `mix deps.get`, a `hex_metadata.config` is placed in each unpacked directory. This file contains package's metadata as Erlang terms and so we can additionally see the diff of that. The exit code of the task is that of the underlying diff command. ### Diff command The diff command can be customized by setting `diff_command` configuration option, see `mix help hex.config` for more information. The default diff command is: $ #{@default_diff_command} The `__PATH1__` and `__PATH2__` placeholders will be interpolated with paths to directories of unpacked tarballs for each version. Many diff commands supports coloured output but because we execute the command in non-interactive mode, they'd usually be disabled. On Unix systems you can pipe the output to more commands, for example: $ mix hex.package diff decimal 1.0.0..1.1.0 | colordiff | less -R Here, the output of `mix hex.package diff` is piped to the `colordiff` utility to adds colours, which in turn is piped to `less -R` which "pages" it. (`-R` preserves escape codes which allows colours to work.) Another option is to configure the diff command itself. For example, to force Git to always colour the output we can set the `--color=always` option: $ mix hex.config diff_command "git diff --color=always --no-index __PATH1__ __PATH2__" $ mix hex.package diff decimal 1.0.0..1.1.0 ## Command line options * `--unpack` - Unpacks the tarball after fetching it * `-o`, `--output` - Sets output path. When used with `--unpack` it means the directory (Default: `-`). Otherwise, it specifies tarball path (Default: `-.tar`) * `--organization ORGANIZATION` - Set this for private packages belonging to an organization * `--repo REPO` - Set this for self-hosted Hex instances, default: `hexpm` """ @behaviour Hex.Mix.TaskDescription @switches [unpack: :boolean, organization: :string, output: :string, repo: :string] @aliases [o: :output] @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches, aliases: @aliases) unpack = Keyword.get(opts, :unpack, false) output = Keyword.get(opts, :output, nil) case args do ["fetch", package] -> fetch(repo(opts), package, nil, unpack, output) ["fetch", package, version] -> fetch(repo(opts), package, version, unpack, output) ["diff", package, version1, version2] -> diff(repo(opts), package, parse_version!(version1, version2)) ["diff", package, version] -> diff(repo(opts), package, parse_version!(version)) _ -> Mix.raise(""" Invalid arguments, expected one of: mix hex.package fetch PACKAGE [VERSION] [--unpack] mix hex.package diff APP VERSION mix hex.package diff PACKAGE VERSION1 VERSION2 mix hex.package diff PACKAGE VERSION1..VERSION2 """) end end @impl true def tasks() do [ {"fetch PACKAGE [VERSION] [--unpack]", "Fetch the package"}, {"diff APP VERSION", "Diff dependency against version"}, {"diff PACKAGE VERSION1 VERSION2", "Diff package versions"}, {"diff PACKAGE VERSION1..VERSION2", "Diff package versions"} ] end defp fetch(repo, package, nil, unpack?, output) do version = find_package_latest_version(repo, package) fetch(repo, package, version, unpack?, output) end defp fetch(repo, package, version, false, "-") do Hex.Registry.Server.open() Hex.Registry.Server.prefetch([{repo, package}]) tarball = fetch_tarball!(repo, package, version) IO.binwrite(tarball) Hex.Registry.Server.close() end defp fetch(_repo, _package, _version, true, "-") do Mix.raise("Cannot unpack the package while output destination is stdout") end defp fetch(repo, package, version, unpack?, output) do Hex.Registry.Server.open() Hex.Registry.Server.prefetch([{repo, package}]) tarball = fetch_tarball!(repo, package, version) if output, do: File.mkdir_p!(output) abs_name = Path.absname("#{package}-#{version}") {abs_path, tar_path} = if output do {output, Path.join(output, "#{package}-#{version}.tar")} else {abs_name, "#{abs_name}.tar"} end File.write!(tar_path, tarball) if unpack? do %{inner_checksum: inner_checksum, outer_checksum: outer_checksum} = Hex.Tar.unpack!(tar_path, abs_path) verify_inner_checksum!(repo, package, version, inner_checksum) verify_outer_checksum!(repo, package, version, outer_checksum) else {:ok, outer_checksum} = Hex.Tar.outer_checksum(tar_path) verify_outer_checksum!(repo, package, version, outer_checksum) end message = if unpack? do File.rm!(tar_path) "#{package} v#{version} extracted to #{abs_path}" else "#{package} v#{version} downloaded to #{tar_path}" end Hex.Shell.info(message) Hex.Registry.Server.close() end defp fetch_tarball!(repo, package, version) do path = Hex.SCM.cache_path(repo, package, version) case Hex.SCM.fetch(repo, package, version) do {:ok, _} -> File.read!(path) {:error, reason} -> if File.exists?(path) do File.read!(path) else Mix.raise( "Downloading " <> Hex.Repo.tarball_url(repo, package, version) <> " failed:\n\n" <> reason ) end end end defp verify_inner_checksum!(repo, package, version, checksum) do registry_checksum = Registry.inner_checksum(repo, package, version) if checksum != registry_checksum do Mix.raise("Checksum mismatch against registry (inner)") end end defp verify_outer_checksum!(repo, package, version, checksum) do registry_checksum = Registry.outer_checksum(repo, package, version) if checksum != registry_checksum do Mix.raise("Checksum mismatch against registry (outer)") end end defp diff(repo, app, version) when is_binary(version) do Mix.Tasks.Deps.Loadpaths.run(["--no-compile"]) {path_lock, package} = case Map.get(Mix.Dep.Lock.read(), String.to_atom(app)) do nil -> Mix.raise( "Cannot find the app \"#{app}\" in \"mix.lock\" file, " <> "please ensure it has been specified in \"mix.exs\" and run \"mix deps.get\"" ) lock -> path = Path.join(Mix.Project.deps_path(), app) package = Hex.Utils.lock(lock).name {path, package} end path = tmp_path("#{package}-#{version}-") try do fetch_and_unpack!(repo, package, [{path, version}]) code = run_diff_path!(path_lock, path) Mix.Tasks.Hex.set_exit_code(code) after File.rm_rf!(path) end end defp diff(repo, package, {version1, version2}) do path1 = tmp_path("#{package}-#{version1}-") path2 = tmp_path("#{package}-#{version2}-") try do fetch_and_unpack!(repo, package, [{path1, version1}, {path2, version2}]) code = run_diff_path!(path1, path2) Mix.Tasks.Hex.set_exit_code(code) after File.rm_rf!(path1) File.rm_rf!(path2) end end defp fetch_and_unpack!(repo, package, versions) do Hex.Registry.Server.open() Hex.Registry.Server.prefetch([{repo, package}]) try do Enum.each(versions, fn {path, version} -> tarball = fetch_tarball!(repo, package, version) %{inner_checksum: inner_checksum, outer_checksum: outer_checksum} = Hex.Tar.unpack!({:binary, tarball}, path) verify_inner_checksum!(repo, package, version, inner_checksum) verify_outer_checksum!(repo, package, version, outer_checksum) end) after Hex.Registry.Server.close() end end defp run_diff_path!(path1, path2) do cmd = Hex.State.fetch!(:diff_command) |> String.replace("__PATH1__", escape_and_quote_path(path1)) |> String.replace("__PATH2__", escape_and_quote_path(path2)) Mix.shell().cmd(cmd) end defp escape_and_quote_path(path) do escaped = String.replace(path, "\"", "\\\"") ~s("#{escaped}") end defp tmp_path(prefix) do random_string = Base.encode16(:crypto.strong_rand_bytes(4)) Path.join(System.tmp_dir!(), prefix <> random_string) end defp parse_version!(string) do case String.split(string, "..", trim: true) do [version1, version2] -> parse_two_versions!(version1, version2) [version] -> version |> Version.parse!() |> to_string() end end defp parse_version!(version1, version2) do parse_two_versions!(version1, version2) end defp parse_two_versions!(version1, version2) do version1 = Version.parse!(version1) version2 = Version.parse!(version2) {to_string(version1), to_string(version2)} end defp repo(opts) do repo = Keyword.get(opts, :repo, "hexpm") if organization = opts[:organization] do Enum.join([repo, organization], ":") else repo end end defp find_package_latest_version(organization, name) do %{"latest_stable_version" => latest_stable_version} = retrieve_package_info(organization, name) latest_stable_version end defp retrieve_package_info(organization, name) do case Hex.API.Package.get(organization, name) do {:ok, {code, body, _}} when code in 200..299 -> body {:ok, {404, _, _}} -> Mix.raise("No package with name #{name}") other -> Hex.Shell.error("Failed to retrieve package information") Hex.Utils.print_error_result(other) end end end hex-2.0.6/lib/mix/tasks/hex.publish.ex000066400000000000000000000360471437023760000175760ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Publish do use Mix.Task alias Mix.Tasks.Hex.Build @shortdoc "Publishes a new package version" @moduledoc """ Publishes a new version of the package. $ mix hex.publish The current authenticated user will be the package owner. Only package owners can publish the package, new owners can be added with the `mix hex.owner` task. Packages and documentation sizes are limited to 8mb compressed, and 64mb uncompressed. ## Publishing documentation Documentation will be generated by running the `mix docs` task. `ex_doc` provides this task by default, but any library can be used. Or an alias can be used to extend the documentation generation. The expected result of the task is the generated documentation located in the `doc/` directory with an `index.html` file. The documentation will be accessible at `https://hexdocs.pm/my_package/1.0.0`, `https://hexdocs.pm/my_package` will always redirect to the latest published version. Documentation will be built and published automatically. To publish a package without documentation run `mix hex.publish package` or to only publish documentation run `mix hex.publish docs`. ## Reverting a package A new package can be reverted or updated within 24 hours of it's initial publish, a new version of an existing package can be reverted or updated within one hour. Documentation have no limitations on when it can be updated. To update the package simply run the `mix hex.publish` task again. To revert run `mix hex.publish --revert VERSION` or to only revert the documentation run `mix hex.publish docs --revert VERSION`. If the last version is reverted, the package is removed. ## Command line options * `--organization ORGANIZATION` - Set this for private packages belonging to an organization * `--yes` - Publishes the package without any confirmation prompts * `--dry-run` - Builds package and performs local checks without publishing, use `mix hex.build --unpack` to inspect package contents before publishing * `--replace` - Allows overwriting an existing package version if it exists. Private packages can always be overwritten, public packages can only be overwritten within one hour after they were initially published. * `--revert VERSION` - Revert given version. If the last version is reverted, the package is removed. #{Hex.Package.configuration_doc()} """ @behaviour Hex.Mix.TaskDescription @switches [ revert: :string, progress: :boolean, organization: :string, organisation: :string, yes: :boolean, dry_run: :boolean, replace: :boolean ] @impl true def run(args) do Mix.Tasks.Deps.Loadpaths.run(["--no-compile"]) Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) build = Build.prepare_package() revert_version = opts[:revert] revert = !!revert_version organization = opts[:organization] || build.organization case args do ["package"] when revert -> auth = Mix.Tasks.Hex.auth_info(:write) revert_package(build, organization, revert_version, auth) ["docs"] when revert -> auth = Mix.Tasks.Hex.auth_info(:write) revert_docs(build, organization, revert_version, auth) [] when revert -> auth = Mix.Tasks.Hex.auth_info(:write) revert_package(build, organization, revert_version, auth) ["package"] -> case proceed_with_owner(build, organization, opts) do {:ok, owner} -> auth = Mix.Tasks.Hex.auth_info(:write) Hex.Shell.info("Publishing package...") case create_release(build, organization, auth, opts) do :ok -> transfer_owner(build, owner, auth, opts) _ -> Mix.Tasks.Hex.set_exit_code(1) end :error -> :ok end ["docs"] -> docs_task() auth = Mix.Tasks.Hex.auth_info(:write) create_docs(build, organization, auth, opts) [] -> create(build, organization, opts) _ -> Mix.raise(""" Invalid arguments, expected one of: mix hex.publish mix hex.publish package mix hex.publish docs """) end end @impl true def tasks() do [ {"", "Publishes a new package version"}, {"package", "Publish current package"}, {"docs", "Publish current docs"}, {"package --revert VERSION", "Reverts package on given version"}, {"docs --revert VERSION", "Reverts docs on given version"}, {"--revert VERSION", "Reverts given version"} ] end defp create(build, organization, opts) do case proceed_with_owner(build, organization, opts) do {:ok, owner} -> Hex.Shell.info("Building docs...") docs_task() auth = Mix.Tasks.Hex.auth_info(:write) Hex.Shell.info("Publishing package...") case create_release(build, organization, auth, opts) do :ok -> Hex.Shell.info("Publishing docs...") create_docs(build, organization, auth, opts) transfer_owner(build, owner, auth, opts) _ -> Mix.Tasks.Hex.set_exit_code(1) end :error -> :ok end end defp create_docs(build, organization, auth, opts) do directory = docs_dir() name = build.meta.name version = build.meta.version unless File.exists?("#{directory}/index.html") do Mix.raise("File not found: #{directory}/index.html") end progress? = Keyword.get(opts, :progress, true) dry_run? = Keyword.get(opts, :dry_run, false) tarball = build_docs_tarball(directory) if dry_run? do :ok else send_tarball(organization, name, version, tarball, auth, progress?) end end defp docs_task() do # Elixir v1.15 prunes the loadpaths on compilation and # docs will compile code. So we add all original code paths back. path = :code.get_path() try do Mix.Task.run("docs", []) rescue ex in [Mix.NoTaskError] -> require Hex.Stdlib stacktrace = Hex.Stdlib.stacktrace() Mix.shell().error(""" Publication failed because the "docs" task is unavailable. You may resolve this by: 1. Adding {:ex_doc, ">= 0.0.0", only: :dev, runtime: false} to your dependencies in your mix.exs and trying again 2. If ex_doc was already added, make sure you run "mix hex.publish" in the same environment as the ex_doc package 3. Publishing the package without docs by running "mix hex.publish package" (not recommended) """) reraise ex, stacktrace after :code.add_pathsz(path) end end defp proceed_with_owner(build, organization, opts) do meta = build.meta exclude_deps = build.exclude_deps package = build.package Hex.Shell.info("Building #{meta.name} #{meta.version}") Build.print_info(meta, organization, exclude_deps, package[:files]) print_link_to_coc() print_public_private(organization) print_owner_prompt(build, organization, opts) end defp print_public_private(organization) do api_url = Hex.State.fetch!(:api_url) default_api_url? = api_url == Hex.State.default_api_url() using_api = if default_api_url? do "" else " using #{api_url}" end to_repository = cond do !organization and !default_api_url? -> "" public_organization?(organization) -> [" to ", :bright, "public", :reset, " repository hexpm"] true -> [" to ", :bright, "private", :reset, " repository #{organization}"] end Hex.Shell.info( Hex.Shell.format([ "Publishing package", to_repository, using_api, "." ]) ) end defp print_owner_prompt(build, organization, opts) do auth = Mix.Tasks.Hex.auth_info(:read) organizations = user_organizations(auth) owner_prompt? = public_organization?(organization) and not Keyword.get(opts, :yes, false) and organizations != [] and not package_exists?(build) Hex.Shell.info("") if owner_prompt? do do_print_owner_prompt(organizations) else if Keyword.get(opts, :yes, false) or Hex.Shell.yes?("Proceed?") do {:ok, nil} else :error end end end defp do_print_owner_prompt(organizations) do Hex.Shell.info( "You are a member of one or multiple organizations. Would you like to publish " <> "the package with yourself as owner or an organization as owner? " <> "If you publish with an organization as owner your package will " <> "be public but managed by the selected organization." ) Hex.Shell.info("") Hex.Shell.info(" [1] Yourself") numbers = Stream.map(Stream.iterate(2, &(&1 + 1)), &Integer.to_string/1) organizations = Stream.zip(numbers, organizations) Enum.each(organizations, fn {ix, organization} -> Hex.Shell.info(" [#{ix}] #{organization}") end) Hex.Shell.info("") owner_prompt_selection(Map.new(organizations)) end defp owner_prompt_selection(organizations) do selection = String.trim(Hex.Shell.prompt("Your selection:")) if selection == "1" do {:ok, nil} else case Map.fetch(organizations, selection) do {:ok, organization} -> {:ok, organization} :error -> owner_prompt_selection(organizations) end end end defp package_exists?(build) do case Hex.API.Package.get("hexpm", build.meta.name) do {:ok, {200, _body, _headers}} -> true {:ok, {404, _body, _headers}} -> false other -> Hex.Utils.print_error_result(other) true end end defp user_organizations(auth) do case Hex.API.User.me(auth) do {:ok, {200, body, _header}} -> Enum.map(body["organizations"], & &1["name"]) other -> Hex.Utils.print_error_result(other) [] end end defp public_organization?(organization), do: organization in [nil, "hexpm"] defp transfer_owner(_build, nil, _auth, _opts) do :ok end defp transfer_owner(build, owner, auth, opts) do Hex.Shell.info("Transferring ownership to #{owner}...") dry_run? = Keyword.get(opts, :dry_run, false) if dry_run? do :ok else case Hex.API.Package.Owner.add("hexpm", build.meta.name, owner, "full", true, auth) do {:ok, {status, _body, _header}} when status in 200..299 -> :ok other -> Hex.Shell.error("Failed to transfer ownership") Hex.Utils.print_error_result(other) end end end defp print_link_to_coc() do Hex.Shell.info( "Before publishing, please read the Code of Conduct: " <> "https://hex.pm/policies/codeofconduct\n" ) end defp revert_package(build, organization, version, auth) do name = build.meta.name case Hex.API.Release.delete(organization, name, version, auth) do {:ok, {code, _, _}} when code in 200..299 -> Hex.Shell.info("Reverted #{name} #{version}") other -> Hex.Shell.error("Reverting #{name} #{version} failed") Hex.Utils.print_error_result(other) end end defp revert_docs(build, organization, version, auth) do name = build.meta.name case Hex.API.ReleaseDocs.delete(organization, name, version, auth) do {:ok, {code, _, _}} when code in 200..299 -> Hex.Shell.info("Reverted docs for #{name} #{version}") {:ok, {404, _, _}} -> Hex.Shell.info("Docs do not exist") other -> Hex.Shell.error("Reverting docs for #{name} #{version} failed") Hex.Utils.print_error_result(other) end end defp build_docs_tarball(directory) do files = files(directory) raise_if_file_matches_semver(files) {:ok, data} = :mix_hex_tarball.create_docs(files) data end defp raise_if_file_matches_semver(files) do Enum.map(files, fn {filename, _contents} -> filename_matches_semver!(filename) filename -> filename_matches_semver!(filename) end) end defp filename_matches_semver!(filename) do top_level = filename |> Path.split() |> List.first() case Version.parse(to_string(top_level)) do {:ok, _struct} -> Mix.raise("Invalid filename: top-level filenames cannot match a semantic version pattern") _ -> :ok end end defp send_tarball(organization, name, version, tarball, auth, progress?) do progress = progress_fun(progress?, byte_size(tarball)) case Hex.API.ReleaseDocs.publish(organization, name, version, tarball, auth, progress) do {:ok, {code, _body, headers}} when code in 200..299 -> api_url = Hex.State.fetch!(:api_url) default_api_url? = api_url == Hex.State.default_api_url() location = if !default_api_url? && headers[~c"location"] do headers[~c"location"] else Hex.Utils.hexdocs_url(organization, name, version) end Hex.Shell.info("") Hex.Shell.info(["Docs published to ", location]) :ok {:ok, {404, _, _}} -> Hex.Shell.info("") Hex.Shell.error("Publishing docs failed due to the package not being published yet") :error other -> Hex.Shell.info("") Hex.Shell.error("Publishing docs failed") Hex.Utils.print_error_result(other) :error end end defp files(directory) do "#{directory}/**" |> Path.wildcard() |> Enum.filter(&File.regular?/1) |> Enum.map(&{relative_path(&1, directory), File.read!(&1)}) end defp relative_path(file, dir) do Path.relative_to(file, dir) |> String.to_charlist() end defp docs_dir do cond do File.exists?("doc") -> "doc" File.exists?("docs") -> "docs" true -> Mix.raise( "Documentation could not be found. " <> "Please ensure documentation is in the doc/ or docs/ directory" ) end end defp create_release(build, organization, auth, opts) do meta = build.meta %{tarball: tarball, outer_checksum: checksum} = Hex.Tar.create!(meta, meta.files, :memory) dry_run? = Keyword.get(opts, :dry_run, false) if dry_run? do :ok else send_release(tarball, checksum, organization, auth, opts) end end defp send_release(tarball, checksum, organization, auth, opts) do progress? = Keyword.get(opts, :progress, true) progress = progress_fun(progress?, byte_size(tarball)) replace? = Keyword.get(opts, :replace, false) case Hex.API.Release.publish(organization, tarball, auth, progress, replace?) do {:ok, {code, body, _}} when code in 200..299 -> location = body["html_url"] || body["url"] checksum = String.downcase(Base.encode16(checksum, case: :lower)) Hex.Shell.info("") Hex.Shell.info("Package published to #{location} (#{checksum})") :ok other -> Hex.Shell.info("") Hex.Shell.error("Publishing failed") Hex.Utils.print_error_result(other) :error end end defp progress_fun(true, size), do: Mix.Tasks.Hex.progress(size) defp progress_fun(false, _size), do: Mix.Tasks.Hex.progress(nil) end hex-2.0.6/lib/mix/tasks/hex.registry.ex000066400000000000000000000164061437023760000177750ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Registry do use Mix.Task @behaviour Hex.Mix.TaskDescription @switches [ name: :string, private_key: :string ] @shortdoc "Manages local Hex registries" @moduledoc """ Manages local Hex registries. ## Build a local registry $ mix hex.registry build PUBLIC_DIR To build a registry you need a name, a directory that will be used to store public registry files, and a private key to sign the registry: $ mix hex.registry build public --name=acme --private-key=private_key.pem * creating public/public_key * creating public/tarballs * creating public/names * creating public/versions You can generate a random private key using the following command: $ openssl genrsa -out private_key.pem Let's say you have a package `foo-1.0.0.tar`. To publish it, simply copy it to the appropriate directory and re-build the registry: $ cp foo-1.0.0.tar public/tarballs/ $ mix hex.registry build public --name=acme --private-key=private_key.pem * creating public/packages/foo * updating public/names * updating public/versions You can test the repository by starting the built-in Erlang/OTP HTTP server, adding the repository, and retrieving the package that you just published. $ erl -s inets -eval 'inets:start(httpd,[{port,8000},{server_name,"localhost"},{server_root,"."},{document_root,"public"}]).' # replace "acme" with the name of your repository $ mix hex.repo add acme http://localhost:8000 --public-key=public/public_key $ mix hex.package fetch foo 1.0.0 --repo=acme To use the package in your Mix project, add it as a dependency and set the `:repo` option to your repository name: defp deps() do {:decimal, "~> 2.0", repo: "acme"} end ### Command line options * `--name` - The name of the registry * `--private-key` - Path to the private key """ @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) case args do ["build", public_dir] -> build(public_dir, opts) _ -> Mix.raise(""" Invalid arguments, expected one of: mix hex.registry build PUBLIC_DIR """) end end @impl true def tasks() do [ {"build PUBLIC_DIR", "Build a local registry"} ] end defp build(public_dir, opts) do repo_name = opts[:name] || raise "missing --name" private_key_path = opts[:private_key] || raise "missing --private-key" private_key = private_key_path |> File.read!() |> decode_private_key() build(repo_name, public_dir, private_key) end defp build(repo_name, public_dir, private_key) do ensure_public_key(private_key, public_dir) create_directory(Path.join(public_dir, "tarballs")) paths_per_name = Enum.group_by(Path.wildcard("#{public_dir}/tarballs/*.tar"), fn path -> [name | _rest] = String.split(Path.basename(path), ["-", ".tar"], trim: true) name end) versions = Enum.map(paths_per_name, fn {name, paths} -> releases = paths |> Enum.map(&build_release(repo_name, &1)) |> Enum.sort(&(Version.compare(&1.version, &2.version) == :lt)) updated_at = paths |> Enum.map(&File.stat!(&1).mtime) |> Enum.sort() |> Enum.at(-1) updated_at = updated_at && %{seconds: to_unix(updated_at), nanos: 0} package = :mix_hex_registry.build_package( %{repository: repo_name, name: name, releases: releases}, private_key ) write_file("#{public_dir}/packages/#{name}", package) versions = Enum.map(releases, & &1.version) {name, %{updated_at: updated_at, versions: versions}} end) for path <- Path.wildcard("#{public_dir}/packages/*"), not Enum.member?(Map.keys(paths_per_name), Path.basename(path)) do remove_file(path) end names = for {name, %{updated_at: updated_at}} <- versions do %{name: name, updated_at: updated_at} end payload = %{repository: repo_name, packages: names} names = :mix_hex_registry.build_names(payload, private_key) write_file("#{public_dir}/names", names) versions = for {name, %{versions: versions}} <- versions do %{name: name, versions: versions} end payload = %{repository: repo_name, packages: versions} versions = :mix_hex_registry.build_versions(payload, private_key) write_file("#{public_dir}/versions", versions) end @unix_epoch :calendar.datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}) @doc false def to_unix(erl_datetime) do :calendar.datetime_to_gregorian_seconds(erl_datetime) - @unix_epoch end defp build_release(repo_name, tarball_path) do tarball = File.read!(tarball_path) {:ok, result} = :mix_hex_tarball.unpack(tarball, :memory) dependencies = for {package, map} <- Map.get(result.metadata, "requirements", []) do app = Map.fetch!(map, "app") requirement = Map.fetch!(map, "requirement") optional = map["optional"] == true repository = map["repository"] release = %{ package: package, app: app, optional: optional, requirement: requirement } if !repository or repository == repo_name do release else Map.put(release, :repository, repository) end end %{ version: result.metadata["version"], inner_checksum: result.inner_checksum, outer_checksum: result.outer_checksum, dependencies: dependencies } end defp ensure_public_key(private_key, public_dir) do path = "#{public_dir}/public_key" encoded_public_key = private_key |> extract_public_key() |> encode_public_key() case File.read(path) do {:ok, ^encoded_public_key} -> :ok {:ok, _} -> Hex.Shell.info("* public key at #{path} does not match private key, overwriting") write_file(path, encoded_public_key) {:error, :enoent} -> write_file(path, encoded_public_key) end end defp create_directory(path) do unless File.dir?(path) do Hex.Shell.info(["* creating ", path]) File.mkdir_p!(path) end end defp write_file(path, data) do if File.exists?(path) do Hex.Shell.info(["* updating ", path]) else File.mkdir_p!(Path.dirname(path)) Hex.Shell.info(["* creating ", path]) end File.write!(path, data) end defp remove_file(path) do Hex.Shell.info(["* removing ", path]) File.rm!(path) end ## Key utilities require Record Record.defrecordp( :rsa_private_key, :RSAPrivateKey, Record.extract(:RSAPrivateKey, from_lib: "public_key/include/OTP-PUB-KEY.hrl") ) Record.defrecordp( :rsa_public_key, :RSAPublicKey, Record.extract(:RSAPublicKey, from_lib: "public_key/include/OTP-PUB-KEY.hrl") ) defp extract_public_key(rsa_private_key(modulus: m, publicExponent: e)) do rsa_public_key(modulus: m, publicExponent: e) end defp encode_public_key(key) do :public_key.pem_encode([:public_key.pem_entry_encode(:RSAPublicKey, key)]) end defp decode_private_key(data) do [entry] = :public_key.pem_decode(data) :public_key.pem_entry_decode(entry) end end hex-2.0.6/lib/mix/tasks/hex.repo.ex000066400000000000000000000152571437023760000170750ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Repo do use Mix.Task @shortdoc "Manages Hex repositories" @moduledoc """ Manages the list of available Hex repositories. The repository is where packages and the registry of packages is stored. You can fetch packages from multiple different repositories and packages can depend on packages from other repositories. To use a package from another repository than the global default `hexpm` add `repo: "my_repo"` to the dependency declaration in `mix.exs`: {:plug, "~> 1.0", repo: "my_repo"} By default all dependencies of plug will also be fetched from `my_repo` unless plug has declared otherwise in its dependency definition. To use packages from `my_repo` you need to add it to your configuration first. You do that by calling `mix hex.repo add my_repo https://myrepo.example.com`. The default repo is called `hexpm` and points to https://repo.hex.pm. This can be overridden by using `mix hex.repo set ...`. A repository configured from an organization will have `hexpm:` prefixed to its name. To depend on packages from an organization add `repo: "hexpm:my_organization"` to the dependency declaration or simply `organization: "my_organization"`. To configure organizations, see the `hex.organization` task. ## Add a repo $ mix hex.repo add NAME URL ### Command line options * `--public-key PATH` - Path to public key used to verify the registry (optional). * `--auth-key KEY` - Key used to authenticate HTTP requests to repository (optional). * `--fetch-public-key FINGERPRINT` - Download public key from the repository and verify against the fingerprint (optional). ## Set config for repo $ mix hex.repo set NAME --url URL $ mix hex.repo set NAME --public-key PATH $ mix hex.repo set NAME --auth-key KEY ## Remove repo $ mix hex.repo remove NAME ## Show repo config $ mix hex.repo show NAME $ mix hex.repo show NAME --url ## List all repos $ mix hex.repo list """ @behaviour Hex.Mix.TaskDescription @add_switches [public_key: :string, auth_key: :string, fetch_public_key: :string] @set_switches [url: :string, public_key: :string, auth_key: :string] @show_switches [url: :boolean, public_key: :boolean, auth_key: :boolean] @impl true def run(all_args) do Hex.start() {_opts, args} = OptionParser.parse!(all_args, switches: []) case args do ["add", name, url] -> {opts, _args} = OptionParser.parse!(all_args, strict: @add_switches) add(name, url, opts) ["set", name] -> {opts, _args} = OptionParser.parse!(all_args, strict: @set_switches) set(name, opts) ["remove", name] -> remove(name) ["show", name] -> {opts, _args} = OptionParser.parse!(all_args, strict: @show_switches) show(name, opts) ["list"] -> list() _ -> invalid_args() end end defp invalid_args() do Mix.raise(""" Invalid arguments, expected one of: mix hex.repo add NAME URL mix hex.repo set NAME mix hex.repo remove NAME mix hex.repo show NAME mix hex.repo list """) end @impl true def tasks() do [ {"add NAME URL", "Add a repo"}, {"set NAME", "Set config for repo"}, {"remove NAME", "Remove repo"}, {"show NAME", "Show repo config"}, {"list", "List all repos"} ] end defp add(name, url, opts) do public_key = read_public_key(opts[:public_key]) || fetch_public_key(opts[:fetch_public_key], url, opts[:auth_key]) repo = %{ url: url, public_key: nil, fetch_public_key: nil, auth_key: nil, trusted: true } |> Map.merge(Map.new(opts)) |> Map.put(:public_key, public_key) Hex.State.fetch!(:repos) |> Map.put(name, repo) |> Hex.Config.update_repos() end defp set(name, opts) do opts = if public_key = opts[:public_key] do Keyword.put(opts, :public_key, read_public_key(public_key)) else opts end Hex.State.fetch!(:repos) |> Map.update!(name, &Map.merge(&1, Map.new(opts))) |> Hex.Config.update_repos() end defp remove(name) do Hex.State.fetch!(:repos) |> Map.delete(name) |> Hex.Config.update_repos() end defp list() do header = ["Name", "URL", "Public key", "Auth key"] values = Enum.map(Hex.State.fetch!(:repos), fn {name, config} -> [ name, config[:url], show_public_key(config[:public_key]), config[:auth_key] ] end) Mix.Tasks.Hex.print_table(header, values) end defp read_public_key(nil) do nil end defp read_public_key(path) do key = path |> Path.expand() |> File.read!() decode_public_key(key) key end defp decode_public_key(key) do [pem_entry] = :public_key.pem_decode(key) :public_key.pem_entry_decode(pem_entry) rescue _ -> Mix.raise(""" Could not decode public key. The public key contents are shown below. #{key} Public keys must be valid and be in the PEM format. """) end defp show_public_key(nil), do: nil defp show_public_key(public_key) do [pem_entry] = :public_key.pem_decode(public_key) public_key = :public_key.pem_entry_decode(pem_entry) Hex.Stdlib.ssh_hostkey_fingerprint(:sha256, public_key) |> List.to_string() end defp fetch_public_key(nil, _, _), do: nil defp fetch_public_key(fingerprint, repo_url, auth_key) do repo_config = %{url: repo_url, auth_key: auth_key, trusted: true} case Hex.Repo.get_public_key(repo_config) do {:ok, {200, key, _}} -> if show_public_key(key) == fingerprint do key else Mix.raise("Public key fingerprint mismatch") end {:ok, {code, _, _}} -> Hex.Shell.error("Downloading public key failed with code \"#{inspect(code)}\"") Mix.Tasks.Hex.set_exit_code(1) other -> Hex.Shell.error("Downloading public key failed") Hex.Utils.print_error_result(other) Mix.Tasks.Hex.set_exit_code(1) end end defp show(name, [{key, _} | _]) do case Map.fetch(Hex.State.fetch!(:repos), name) do {:ok, config} -> Hex.Shell.info(Map.get(config, key, "")) :error -> Mix.raise("Config does not contain repo #{name}") end end defp show(name, []) do case Map.fetch(Hex.State.fetch!(:repos), name) do {:ok, repo} -> header = ["URL", "Public key", "Auth key"] rows = [[repo.url, show_public_key(repo.public_key), repo.auth_key]] Mix.Tasks.Hex.print_table(header, rows) :error -> Mix.raise("Config does not contain repo #{name}") end end end hex-2.0.6/lib/mix/tasks/hex.retire.ex000066400000000000000000000063401437023760000174130ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Retire do use Mix.Task @shortdoc "Retires a package version" @moduledoc """ Retires a package version. $ mix hex.retire PACKAGE VERSION REASON $ mix hex.retire PACKAGE VERSION --unretire Mark a package as retired when you no longer recommend its usage. A retired package is still resolvable and usable but it will be flagged as retired in the repository and a message will be displayed to users when they use the package. ## Retirement reasons * **renamed** - The package has been renamed, including the new package name in the message * **deprecated** - The package has been deprecated, if there's a replacing package include it in the message * **security** - There are security issues with this package * **invalid** - The package is invalid, for example it does not compile correctly * **other** - Any other reason not included above, clarify the reason in the message ## Command line options * `--message "MESSAGE"` - Required message (up to 140 characters) clarifying the retirement reason * `--organization ORGANIZATION` - Set this for private packages belonging to an organization ## Example $ mix hex.retire your_app 0.1.1 invalid --message "Package has a breaking bug" """ @behaviour Hex.Mix.TaskDescription @switches [message: :string, unretire: :boolean, organization: :string] @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) retire? = !opts[:unretire] organization = opts[:organization] case args do [package, version, reason] when retire? -> retire(organization, package, version, reason, opts) [package, version] when not retire? -> unretire(organization, package, version) _ -> Mix.raise(""" Invalid arguments, expected one of: mix hex.retire PACKAGE VERSION REASON mix hex.retire PACKAGE VERSION --unretire """) end end @impl true def tasks() do [ {"PACKAGE VERSION REASON", "Retires a package version"}, {"PACKAGE VERSION --unretire", "Unretires a package"} ] end defp retire(organization, package, version, reason, opts) do auth = Mix.Tasks.Hex.auth_info(:write) body = %{reason: reason, message: message_option(opts[:message])} case Hex.API.Release.retire(organization, package, version, body, auth) do {:ok, {code, _body, _headers}} when code in 200..299 -> Hex.Shell.info("#{package} #{version} has been retired\n") other -> Hex.Shell.error("Retiring package failed") Hex.Utils.print_error_result(other) end end defp unretire(organization, package, version) do auth = Mix.Tasks.Hex.auth_info(:write) case Hex.API.Release.unretire(organization, package, version, auth) do {:ok, {code, _body, _headers}} when code in 200..299 -> Hex.Shell.info("#{package} #{version} has been unretired") :ok other -> Hex.Shell.error("Unretiring package failed") Hex.Utils.print_error_result(other) end end defp message_option(nil) do Mix.raise("Missing required flag --message") end defp message_option(message) do message end end hex-2.0.6/lib/mix/tasks/hex.search.ex000066400000000000000000000055121437023760000173660ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Search do use Mix.Task @shortdoc "Searches for package names" @moduledoc """ Displays packages matching the given search query. If you are authenticated it will additionally search all organizations you are member of. $ mix hex.search PACKAGE ## Command line options * `--organization ORGANIZATION` - Set this for private packages belonging to an organization """ @behaviour Hex.Mix.TaskDescription @switches [organization: :string, all_organizations: :boolean] @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) case args do [package] -> search_package(package, opts[:organization]) _ -> Mix.raise(""" Invalid arguments, expected: mix hex.search PACKAGE """) end end @impl true def tasks() do [ {"PACKAGE", "Searches for package names"} ] end defp search_package(package, organization) do auth = Mix.Tasks.Hex.auth_info(:read, auth_inline: false) Hex.API.Package.search(organization, package, auth) |> lookup_packages() end defp lookup_packages({:ok, {200, [], _headers}}) do Hex.Shell.info("No packages found") end defp lookup_packages({:ok, {200, packages, _headers}}) do include_organizations? = Enum.any?(packages, &(&1["repository"] != "hexpm")) if include_organizations? do print_with_organizations(packages) else print_without_organizations(packages) end end defp print_with_organizations(packages) do values = Enum.map(packages, fn package -> [ if(package["repository"] != "hexpm", do: package["repository"]), package["name"], package["meta"]["description"] |> trim_heredoc() |> Hex.Utils.truncate(), latest_stable(package["releases"]), package["html_url"] || package["url"] ] end) Mix.Tasks.Hex.print_table( ["Organization", "Package", "Description", "Version", "URL"], values ) end defp print_without_organizations(packages) do values = Enum.map(packages, fn package -> [ package["name"], package["meta"]["description"] |> trim_heredoc() |> Hex.Utils.truncate(), latest_stable(package["releases"]), package["html_url"] || package["url"] ] end) Mix.Tasks.Hex.print_table( ["Package", "Description", "Version", "URL"], values ) end defp latest_stable(releases) do %{"version" => version} = Enum.find( releases, %{"version" => nil}, &(Version.parse!(&1["version"]).pre == []) ) version end defp trim_heredoc(nil), do: "" defp trim_heredoc(string) do string |> String.split("\n", trim: true) |> Enum.map_join(" ", &String.trim/1) end end hex-2.0.6/lib/mix/tasks/hex.sponsor.ex000066400000000000000000000031551437023760000176250ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.Sponsor do use Mix.Task @shortdoc "Show Hex packages accepting sponsorships" @moduledoc """ Show Hex packages in your dependencies that accept sponsorships. $ mix hex.sponsor Sponsorship plays an important role to maintain some open source projects. This task will display all packages that are accepting sponsorship from the current project. You can add sponsorship links to your projects by adding the following to your mix.exs: links: %{ "GitHub" => "[your-repo-link]", "Sponsor" => "[your-sponsorship-link]" } """ @behaviour Hex.Mix.TaskDescription @impl true def run(_) do unless Mix.Project.get() do raise Mix.raise( "The sponsor task only works inside a Mix project. " <> "Please ensure you are in a directory with a mix.exs file." ) end Mix.Tasks.Deps.Loadpaths.run(["--no-compile"]) sponsor_links = Mix.Dep.Lock.read() |> Hex.Mix.packages_from_lock() |> sponsor_links(Mix.Project.deps_path()) case sponsor_links do [] -> Hex.Shell.info("No dependencies with sponsorship link found.") deps_links -> header = ["Dependency", "Sponsorship"] Mix.Tasks.Hex.print_table(header, deps_links) end end defp sponsor_links(packages, deps_path) do Enum.flat_map(packages, fn {_repo, package_name} -> case Hex.Sponsor.get_link(package_name, deps_path) do nil -> [] value -> [[package_name, value]] end end) end @impl true def tasks() do [ {"", @shortdoc} ] end end hex-2.0.6/lib/mix/tasks/hex.user.ex000066400000000000000000000226001437023760000170740ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.User do use Mix.Task @shortdoc "Manages your Hex user account" @moduledoc """ Hex user tasks. ## Register a new user $ mix hex.user register ## Print the current user $ mix hex.user whoami ## Authorize a new user Authorizes a new user on the local machine by generating a new API key and storing it in the Hex config. $ mix hex.user auth [--key-name KEY_NAME] ### Command line options * `--key-name KEY_NAME` - By default Hex will base the key name on your machine's hostname, use this option to give your own name. ## Deauthorize the user Deauthorizes the user from the local machine by removing the API key from the Hex config. $ mix hex.user deauth ## Generate user key Generates an unencrypted API key for your account. Keys generated by this command will be owned by you and will give access to your private resources, do not share this key with anyone. For keys that will be shared by organization members use `mix hex.organization key` instead. By default this command sets the `api:write` permission which allows write access to the API, it can be overridden with the `--permission` flag. $ mix hex.user key generate ### Command line options * `--key-name KEY_NAME` - By default Hex will base the key name on your machine's hostname, use this option to give your own name. * `--permission PERMISSION` - Sets the permissions on the key, this option can be given multiple times, possible values are: * `api:read` - API read access. * `api:write` - API write access. * `repository:ORGANIZATION_NAME` - Access to given organization repository. * `repositories` - Access to repositories for all organizations you are member of. ## Revoke key Removes given key from account. The key can no longer be used to authenticate API requests. $ mix hex.user key revoke KEY_NAME ## Revoke all keys Revoke all keys from your account. $ mix hex.user key revoke --all ## List keys Lists all keys associated with your account. $ mix hex.user key list ## Reset user account password Starts the process for resetting account password. $ mix hex.user reset_password account ## Reset local password Updates the local password for your local authentication credentials. $ mix hex.user reset_password local """ @behaviour Hex.Mix.TaskDescription @switches [ all: :boolean, key_name: :string, permission: [:string, :keep] ] @impl true def run(args) do Hex.start() {opts, args} = OptionParser.parse!(args, strict: @switches) case args do ["register"] -> register() ["whoami"] -> whoami() ["auth"] -> auth(opts) ["deauth"] -> deauth() ["key", "generate"] -> key_generate(opts) ["key", "revoke", key_name] -> key_revoke(key_name) ["key", "revoke"] -> if opts[:all], do: key_revoke_all(), else: invalid_args() ["key", "list"] -> key_list() ["reset_password", "account"] -> reset_account_password() ["reset_password", "local"] -> reset_local_password() _ -> invalid_args() end end @impl true def tasks() do [ {"register", "Register a new user"}, {"whoami", "Prints the current user"}, {"auth", "Authorize a new user"}, {"deauth", "Deauthorize the user"}, {"key generate", "Generate user key"}, {"key revoke KEY_NAME", "Removes given key from account"}, {"key revoke --all", "Revoke all keys"}, {"key list", "Lists all keys associated with your account"}, {"reset_password account", "Reset user account password"}, {"reset_password local", "Reset local password"} ] end defp invalid_args() do Mix.raise(""" Invalid arguments, expected one of: mix hex.user register mix hex.user whoami mix hex.user auth mix hex.user deauth mix hex.user key generate mix hex.user key revoke KEY_NAME mix hex.user key revoke --all mix hex.user key list mix hex.user reset_password account mix hex.user reset_password local """) end defp whoami() do auth = Mix.Tasks.Hex.auth_info(:read) case Hex.API.User.me(auth) do {:ok, {code, body, _}} when code in 200..299 -> Hex.Shell.info(body["username"]) other -> Hex.Shell.error("Failed to auth") Hex.Utils.print_error_result(other) end end defp reset_account_password() do name = Hex.Shell.prompt("Username or Email:") |> String.trim() case Hex.API.User.password_reset(name) do {:ok, {code, _, _}} when code in 200..299 -> Hex.Shell.info( "We’ve sent you an email containing a link that will allow you to reset " <> "your account password for the next 24 hours. Please check your spam folder if the " <> "email doesn’t appear within a few minutes." ) other -> Hex.Shell.error("Initiating password reset for #{name} failed") Hex.Utils.print_error_result(other) end end defp reset_local_password() do encrypted_key = Hex.State.fetch!(:api_key_write) read_key = Hex.State.fetch!(:api_key_read) unless encrypted_key do Mix.raise("No authorized user found. Run `mix hex.user auth`") end decrypted_key = Mix.Tasks.Hex.prompt_decrypt_key(encrypted_key, "Current local password") Mix.Tasks.Hex.prompt_encrypt_key(decrypted_key, read_key, "New local password") Hex.Shell.info("Password changed") end defp deauth() do Mix.Tasks.Hex.update_keys(nil, nil) deauth_organizations() Hex.Shell.info( "Authentication credentials removed from the local machine. " <> "To authenticate again, run `mix hex.user auth` " <> "or create a new user with `mix hex.user register`" ) end defp deauth_organizations() do Hex.State.fetch!(:repos) |> Enum.reject(fn {name, _config} -> String.starts_with?(name, "hexpm:") end) |> Map.new() |> Hex.Config.update_repos() end defp register() do Hex.Shell.info(""" By registering an account on Hex.pm you accept all our \ policies and terms of service found at: https://hex.pm/policies/codeofconduct https://hex.pm/policies/termsofservice https://hex.pm/policies/privacy """) username = Hex.Shell.prompt("Username:") |> String.trim() email = Hex.Shell.prompt("Email:") |> String.trim() password = Mix.Tasks.Hex.password_get("Account password:") |> String.trim() confirm = Mix.Tasks.Hex.password_get("Account password (confirm):") |> String.trim() if password != confirm do Mix.raise("Entered passwords do not match") end Hex.Shell.info("Registering...") create_user(username, email, password) end defp create_user(username, email, password) do case Hex.API.User.new(username, email, password) do {:ok, {code, _, _}} when code in 200..299 -> Mix.Tasks.Hex.generate_all_user_keys(username, password) Hex.Shell.info( "You are required to confirm your email to access your account, " <> "a confirmation email has been sent to #{email}" ) other -> Hex.Shell.error("Registration of user #{username} failed") Hex.Utils.print_error_result(other) end end defp auth(opts) do Mix.Tasks.Hex.auth(opts) end defp key_revoke_all() do auth = Mix.Tasks.Hex.auth_info(:write) Hex.Shell.info("Revoking all keys...") case Hex.API.Key.delete_all(auth) do {:ok, {code, %{"name" => _, "authing_key" => true}, _headers}} when code in 200..299 -> Mix.Tasks.Hex.User.run(["deauth"]) other -> Hex.Shell.error("Key revocation failed") Hex.Utils.print_error_result(other) end end defp key_revoke(key) do auth = Mix.Tasks.Hex.auth_info(:write) Hex.Shell.info("Revoking key #{key}...") case Hex.API.Key.delete(key, auth) do {:ok, {200, %{"name" => ^key, "authing_key" => true}, _headers}} -> Mix.Tasks.Hex.User.run(["deauth"]) :ok {:ok, {code, _body, _headers}} when code in 200..299 -> :ok other -> Hex.Shell.error("Key revocation failed") Hex.Utils.print_error_result(other) end end # TODO: print permissions defp key_list() do auth = Mix.Tasks.Hex.auth_info(:read) case Hex.API.Key.get(auth) do {:ok, {code, body, _headers}} when code in 200..299 -> values = Enum.map(body, fn %{"name" => name, "inserted_at" => time} -> [name, time] end) Mix.Tasks.Hex.print_table(["Name", "Created at"], values) other -> Hex.Shell.error("Key fetching failed") Hex.Utils.print_error_result(other) end end defp key_generate(opts) do username = Hex.Shell.prompt("Username:") |> String.trim() password = Mix.Tasks.Hex.password_get("Account password:") |> String.trim() key_name = Mix.Tasks.Hex.general_key_name(opts[:key_name]) permissions = Keyword.get_values(opts, :permission) permissions = Mix.Tasks.Hex.convert_permissions(permissions) || [%{"domain" => "api"}] Hex.Shell.info("Generating key...") result = Mix.Tasks.Hex.generate_user_key( key_name, permissions, user: username, pass: password ) case result do {:ok, secret} -> Hex.Shell.info(secret) :error -> :ok end end end hex-2.0.6/mix.exs000066400000000000000000000107571437023760000136350ustar00rootroot00000000000000defmodule Hex.MixProject do use Mix.Project @version "2.0.6" def project do [ app: :hex, version: @version, elixir: "~> 1.5", aliases: aliases(), preferred_cli_env: ["deps.get": :test], config_path: config_path(), deps: deps(Mix.env()), elixirc_options: elixirc_options(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()) ] end def application do [ extra_applications: [:ssl, :inets, :logger], mod: {Hex.Application, []} ] end defp deps(:test) do [ {:bypass, "~> 1.0.0"}, {:cowboy, "~> 2.7.0"}, {:mime, "~> 1.0"}, {:plug, "~> 1.9.0"}, {:plug_cowboy, "~> 2.1.0"}, {:plug_crypto, "~> 1.1.2"} ] end defp deps(_) do [] end defp elixirc_options(:prod), do: [debug_info: false] defp elixirc_options(_), do: [] defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"] defp config_path() do if Version.compare(System.version(), "1.11.0") in [:eq, :gt] do "config/config.exs" else "config/mix_config.exs" end end defp aliases do [ "compile.elixir": [&unload_hex/1, "compile.elixir"], run: [&unload_hex/1, "run"], install: ["archive.build -o hex.ez", "archive.install hex.ez --force"], certdata: [&certdata/1] ] end defp unload_hex(_) do update_cached_deps(__MODULE__) Application.stop(:hex) Application.unload(:hex) paths = Path.wildcard(Path.join(archives_path(), "hex*")) Enum.each(paths, fn archive -> ebin = archive_ebin(archive) Code.delete_path(ebin) {:ok, files} = ebin |> :unicode.characters_to_list() |> :erl_prim_loader.list_dir() Enum.each(files, fn file -> file = List.to_string(file) size = byte_size(file) - byte_size(".beam") case file do <> -> module = String.to_atom(name) :code.delete(module) :code.purge(module) _ -> :ok end end) end) end defp update_cached_deps(module) do cond do Version.compare(System.version(), "1.7.0") == :lt -> if cached_deps = Mix.ProjectStack.read_cache({:cached_deps, Mix.env(), module}) do cached_deps = Enum.map(cached_deps, &change_scm/1) Mix.ProjectStack.write_cache({:cached_deps, Mix.env(), module}, cached_deps) end Version.compare(System.version(), "1.10.0") == :lt -> case Mix.ProjectStack.read_cache({:cached_deps, module}) do nil -> :ok {env_target, cached_deps} -> cached_deps = Enum.map(cached_deps, &change_scm/1) Mix.ProjectStack.write_cache({:cached_deps, module}, {env_target, cached_deps}) end true -> case Mix.State.read_cache({:cached_deps, module}) do nil -> :ok {env_target, cached_deps} -> cached_deps = Enum.map(cached_deps, &change_scm/1) Mix.State.write_cache({:cached_deps, module}, {env_target, cached_deps}) end end end defp change_scm(%Mix.Dep{deps: deps} = dep) do %Mix.Dep{dep | scm: Hex.FakeSCM, deps: Enum.map(deps, &change_scm/1)} end @mk_ca_bundle_url "https://raw.githubusercontent.com/bagder/curl/master/lib/mk-ca-bundle.pl" @mk_ca_bundle_cmd "mk-ca-bundle.pl" @ca_bundle "ca-bundle.crt" @ca_bundle_target Path.join("lib/hex/http", @ca_bundle) defp certdata(_) do cmd("wget", [@mk_ca_bundle_url]) File.chmod!(@mk_ca_bundle_cmd, 0o755) cmd(Path.expand(@mk_ca_bundle_cmd), ["-u"]) File.cp!(@ca_bundle, @ca_bundle_target) File.rm!(@ca_bundle) File.rm!(@mk_ca_bundle_cmd) end defp cmd(cmd, args) do {_, result} = System.cmd(cmd, args, into: IO.stream(:stdio, :line), stderr_to_stdout: true) if result != 0 do raise "Non-zero result (#{result}) from: #{cmd} #{Enum.map_join(args, " ", &inspect/1)}" end end cond do function_exported?(Mix, :path_for, 1) -> defp archives_path(), do: Mix.path_for(:archives) function_exported?(Mix.Local, :path_for, 1) -> defp archives_path(), do: Mix.Local.path_for(:archive) true -> defp archives_path(), do: Mix.Local.archives_path() end if function_exported?(Mix.Local, :archive_ebin, 1) do defp archive_ebin(archive), do: Mix.Local.archive_ebin(archive) else defp archive_ebin(archive), do: Mix.Archive.ebin(archive) end end defmodule Hex.FakeSCM do def fetchable?, do: true end hex-2.0.6/mix.lock000066400000000000000000000042561437023760000137630ustar00rootroot00000000000000%{ "bypass": {:hex, :bypass, "1.0.0", "b78b3dcb832a71aca5259c1a704b2e14b55fd4e1327ff942598b4e7d1a7ad83d", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}], "hexpm", "5a1dc855dfcc86160458c7a70d25f65d498bd8012bd4c06a8d3baa368dda3c45"}, "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "04fd8c6a39edc6aaa9c26123009200fc61f92a3a94f3178c527b70b767c6e605"}, "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm", "79f954a7021b302186a950a32869dbc185523d99d3e44ce430cd1f3289f41ed4"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, "plug": {:hex, :plug, "1.9.0", "8d7c4e26962283ff9f8f3347bd73838e2413fbc38b7bb5467d5924f68f3a5a4a", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "9902eda2c52ada2a096434682e99a2493f5d06a94d6ac6bcfff9805f952350f1"}, "plug_cowboy": {:hex, :plug_cowboy, "2.1.3", "38999a3e85e39f0e6bdfdf820761abac61edde1632cfebbacc445cdcb6ae1333", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "056f41f814dbb38ea44613e0f613b3b2b2f2c6afce64126e252837669eba84db"}, "plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"}, } hex-2.0.6/scripts/000077500000000000000000000000001437023760000137745ustar00rootroot00000000000000hex-2.0.6/scripts/release.sh000077500000000000000000000047051437023760000157610ustar00rootroot00000000000000#!/usr/bin/env bash set -e -u function join { local IFS="$1"; shift; echo "$*"; } # $1 = hex version # $2 = erlang version # $3 = elixir version # $4 = saved elixir version # $5 = ubuntu version function build { rm -rf _build src/mix_safe_erl_term.erl docker run -v $PWD:/hex hexpm/elixir:${3}-erlang-${2}-ubuntu-${5} sh -c "mix local.hex --force" docker run -v $PWD:/hex hexpm/elixir:${3}-erlang-${2}-ubuntu-${5} sh -c "cd /hex && mix local.hex --force && MIX_ENV=prod mix archive.build -o hex.ez" docker run -v $PWD:/hex hexpm/elixir:${3}-erlang-${2}-ubuntu-${5} sh -c "cd /hex && mix local.hex --force && MIX_ENV=prod mix archive.build -o hex-${1}.ez" cp hex.ez hex-elixir-${4}.ez cp hex-${1}.ez hex-${1}-elixir-${4}.ez } # $1 = hex version # $... = elixir version function hex_csv { rm hex-1.x*.csv || true s3down hex-1.x.csv hex-1.x.csv for elixir in "${@:2}" do sha=$(shasum -a 512 hex-${1}-elixir-${elixir}.ez) sha=($sha) echo "${1},${sha},${elixir}" >> hex-1.x.csv done openssl dgst -sha512 -sign "${ELIXIR_PEM}" hex-1.x.csv | openssl base64 > hex-1.x.csv.signed } # $1 = source # $2 = target function s3up { aws s3 cp "${1}" "s3://s3.hex.pm/installs/${2}" --acl public-read --cache-control "public, max-age=604800" --metadata "surrogate-key=installs" } # $1 = source # $2 = target function s3down { aws s3 cp "s3://s3.hex.pm/installs/${1}" "${2}" } # $1 = hex version # $... = elixir versions function upload { for elixir in "${@:2}" do s3up "hex-elixir-${elixir}.ez" "${elixir}/hex.ez" s3up "hex-${1}-elixir-${elixir}.ez" "${elixir}/hex-${1}.ez" done s3up hex-1.x.csv hex-1.x.csv s3up hex-1.x.csv.signed hex-1.x.csv.signed } hex_version=$1 # UPDATE THIS FOR EVERY RELEASE build ${hex_version} 23.3 1.14.2 1.14.0 xenial-20210114 build ${hex_version} 22.3 1.13.4 1.13.0 xenial-20200212 build ${hex_version} 22.3 1.12.3 1.12.0 xenial-20200212 build ${hex_version} 21.3 1.11.4 1.11.0 xenial-20200212 build ${hex_version} 21.3 1.10.4 1.10.0 xenial-20200212 build ${hex_version} 20.3 1.9.4 1.9.0 xenial-20200212 build ${hex_version} 20.3 1.8.2 1.8.0 xenial-20200212 build ${hex_version} 19.3 1.7.4 1.7.0 xenial-20200212 build ${hex_version} 19.3 1.6.6 1.6.0 xenial-20200212 build ${hex_version} 18.3 1.5.3 1.5.0 xenial-20200212 rm -rf _build hex_csv "${hex_version}" 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 1.10.0 1.11.0 1.12.0 1.13.0 1.14.0 upload "${hex_version}" 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 1.10.0 1.11.0 1.12.0 1.13.0 1.14.0 hex-2.0.6/scripts/release_rebar.sh000077500000000000000000000063261437023760000171350ustar00rootroot00000000000000#!/usr/bin/env bash set -e -u # $1 = rebar name # $2 = rebar version # $3 = elixir version function rebar_csv { if [ -f "rebar3-1.x.csv" ]; then mv rebar3-1.x.csv rebar3-1.x-old.csv else s3down "${1}-1.x.csv" "${1}-1.x-old.csv" fi # Remove existing build for this elixir version cat ${1}-1.x-old.csv | grep -v ",${3}\$" > ${1}-1.x.csv rm ${1}-1.x-old.csv # Add new build sha=$(shasum -a 512 "${1}") sha=($sha) echo "${2},${sha},${3}" >> ${1}-1.x.csv } # $1 = rebar name function sign_csv { openssl dgst -sha512 -sign "${ELIXIR_PEM}" "${1}-1.x.csv" | openssl base64 > ${1}-1.x.csv.signed } # $1 = source # $2 = target function s3up { aws s3 cp "${1}" "s3://s3.hex.pm/installs/${2}" --acl public-read --cache-control "public, max-age=604800" --metadata "surrogate-key=installs" } # $1 = source # $2 = target function s3down { aws s3 cp "s3://s3.hex.pm/installs/${1}" "${2}" } # $1 = rebar name # $2 = rebar version # $3 = elixir version function upload { s3up "${1}" "${3}/${1}" s3up "${1}" "${3}/${1}-${2}" # Special case 1.0.0 upload s3up "${1}-1.x.csv" "${1}-1.x.csv" s3up "${1}-1.x.csv.signed" "${1}-1.x.csv.signed" } # $1 = rebar version # $2 = otp version # $3 = ubuntu version function build_rebar2 { docker rm rebar2 || true docker run --name rebar2 hexpm/erlang:$2-ubuntu-$3 sh -c "\ apt update && apt -y install git && \ git clone https://github.com/rebar/rebar.git -b $1 && \ cd rebar && \ ./bootstrap" docker cp rebar2:/rebar/rebar rebar docker rm rebar2 } # $1 = rebar version # $2 = otp version # $3 = ubuntu version function build_rebar3 { docker rm rebar3 || true docker run --name rebar3 hexpm/erlang:$2-ubuntu-$3 sh -c "\ apt update && apt -y install git && \ git clone https://github.com/erlang/rebar3.git -b $1 && \ cd rebar3 && \ ./bootstrap" docker cp rebar3:/rebar3/rebar3 rebar3 docker rm rebar3 } rm rebar rebar3 rebar-1.x.csv rebar-1.x.csv.signed # Update these values for every release # Call as ELIXIR_PEM=elixir.pem ./release_rebar.sh # Note that the order of versions in the CSV file matters so all versions # of rebar needs to be updated. # For Elixir 1.0.0 / rebar 3.13.3 rebar_name="rebar3" rebar_version="3.13.3" elixir_version="1.0.0" otp_version="17.5.6.10" ubuntu_version="xenial-20200326" build_rebar3 "${rebar_version}" "${otp_version}" "${ubuntu_version}" rebar_csv rebar3 "${rebar_version}" "${elixir_version}" # For Elixir 1.11.4 / rebar 3.15.2 rebar_name="rebar3" rebar_version="3.15.2" elixir_version="1.11.4" otp_version="21.3.8.21" ubuntu_version="xenial-20201014" build_rebar3 "${rebar_version}" "${otp_version}" "${ubuntu_version}" rebar_csv rebar3 "${rebar_version}" "${elixir_version}" # For Elixir 1.13.0 / rebar 3.15.2 rebar_name="rebar3" rebar_version="3.15.2" elixir_version="1.13.0" otp_version="22.3.4.22" ubuntu_version="xenial-20210114" build_rebar3 "${rebar_version}" "${otp_version}" "${ubuntu_version}" rebar_csv rebar3 "${rebar_version}" "${elixir_version}" sign_csv rebar3 upload rebar3 "${rebar_version}" "${elixir_version}" # build_rebar2 "${rebar_version}" "${otp_version}" "${ubuntu_version}" # rebar_csv rebar2 "${rebar_version}" "${elixir_version}" # upload rebar2 "${rebar_version}" "${elixir_version}" hex-2.0.6/scripts/vendor_hex_core.sh000077500000000000000000000031511437023760000175040ustar00rootroot00000000000000#!/bin/bash set -e if [[ -z "$1" ]]; then echo "Usage: vendor_hex_core.sh PATH_TO_HEX_CORE" exit 1 fi source_dir=$1/src target_dir=src prefix=mix_ version=`cat $source_dir/hex_core.hrl | grep HEX_CORE_VERSION | cut -d'"' -f2` shortref=`cd $source_dir && git rev-parse --short HEAD` filenames="hex_core.hrl \ hex_core.erl \ hex_erl_tar.erl \ hex_erl_tar.hrl \ hex_filename.erl \ hex_pb_names.erl \ hex_pb_package.erl \ hex_pb_signed.erl \ hex_pb_versions.erl \ hex_tarball.erl \ hex_registry.erl \ hex_repo.erl \ hex_http.erl \ hex_http_httpc.erl \ safe_erl_term.xrl" search_to_replace="hex_core: \ hex_core) \ hex_core.hrl \ hex_erl_tar \ hex_filename \ hex_pb_names \ hex_pb_package \ hex_pb_signed \ hex_pb_versions \ hex_registry \ hex_tarball \ hex_http \ hex_repo \ hex_api \ safe_erl_term" rm -f $target_dir/$prefix* for filename in $filenames; do source_path=$source_dir/$filename target_path=$target_dir/$prefix$filename echo "%% Vendored from hex_core v$version ($shortref), do not edit manually" > $target_path echo >> $target_path cat $source_path >> $target_path for word in $search_to_replace; do sed -i.bak s/$word/$prefix$word/g $target_path rm $target_path.bak done done hex-2.0.6/scripts/vendor_hex_solver.sh000077500000000000000000000015761437023760000200770ustar00rootroot00000000000000#!/bin/bash set -e if [[ -z "$1" ]]; then echo "Usage: vendor_hex_solver.sh PATH_TO_HEX_SOLVER" exit 1 fi dir=$1 pushd $dir mix compile version=$(mix run -e 'IO.puts(Mix.Project.config[:version])') shortref=$(git rev-parse --short HEAD) popd rm -f lib/hex/solver.ex rm -rf lib/hex/solver skip_filenames="hex_solver/dev.ex" for filename in $(find $dir/lib -type f); do target_filename=${filename#$dir/lib/} target_path=lib/hex/${target_filename/hex_solver/solver} if [[ $skip_filenames == *$target_filename* ]]; then continue fi mkdir -p $(dirname $target_path) echo "# Vendored from hex_solver v$version ($shortref), do not edit manually" > $target_path echo >> $target_path cat $filename >> $target_path sed -i.bak 's/@moduledoc """/_ = """/g' $target_path rm $target_path.bak sed -i.bak s/HexSolver/Hex.Solver/g $target_path rm $target_path.bak done hex-2.0.6/src/000077500000000000000000000000001437023760000130745ustar00rootroot00000000000000hex-2.0.6/src/mix_hex_core.erl000066400000000000000000000102121437023760000162450ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% @doc %% `hex_core' entrypoint module. %% %% === Config === %% %% Most functions in the `hex_core' API takes a configuration. The configuration sets things %% like HTTP client to use, and API and repository URL. Some of these configuration options %% will likely be static for your application and some may change depending on the function %% you call. %% %% === Options === %% %% * `api_key' - Authentication key used when accessing the HTTP API. %% %% * `api_organization' - Name of the organization endpoint in the API, this should %% for example be set when accessing key for a specific organization. %% %% * `api_repository' - Name of the repository endpoint in the API, this should %% for example be set when accessing packages from a specific repository. %% %% * `api_url' - URL to the HTTP API (default: `https://hex.pm/api'). %% %% * `http_adapter' - A tuple of a callback module and its configuration used %% for HTTP requests (default: `{mix_hex_http_httpc, #{profile => default}}'). See %% {@link mix_hex_http} and {@link mix_hex_http_httpc} for more information. %% %% * `http_etag' - Sets the `if-none-match' HTTP header with the given value to do a %% conditional HTTP request. %% %% * `http_user_agent_fragment' - Will be appended to the `user-agent' HTTP header (default: `<<"(httpc)">>'). %% %% * `repo_key' - Authentication key used when accessing the repository. %% %% * `repo_name' - Name of the repository, used for verifying the repository signature %% authenticity (default: `hexpm'). %% %% * `repo_public_key' - Public key used to verify the repository signature %% (defaults to hexpm public key `https://hex.pm/docs/public_keys'). %% %% * `repo_url' - URL to the repository (default: `https://repo.hex.pm'). %% %% * `repo_organization' - Name of the organization repository, appends `/repos/:name' %% to the repository URL and overrides the `repo_name' option. %% %% * `repo_verify' - If `true' will verify the repository signature (default: `true'). %% %% * `repo_verify_origin' - If `true' will verify the repository signature origin, %% requires protobuf messages as of hex_core v0.4.0 (default: `true'). -module(mix_hex_core). -export([default_config/0]). -export_type([config/0]). %% https://hex.pm/docs/public_keys -define(HEXPM_PUBLIC_KEY, <<"-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApqREcFDt5vV21JVe2QNB Edvzk6w36aNFhVGWN5toNJRjRJ6m4hIuG4KaXtDWVLjnvct6MYMfqhC79HAGwyF+ IqR6Q6a5bbFSsImgBJwz1oadoVKD6ZNetAuCIK84cjMrEFRkELtEIPNHblCzUkkM 3rS9+DPlnfG8hBvGi6tvQIuZmXGCxF/73hU0/MyGhbmEjIKRtG6b0sJYKelRLTPW XgK7s5pESgiwf2YC/2MGDXjAJfpfCd0RpLdvd4eRiXtVlE9qO9bND94E7PgQ/xqZ J1i2xWFndWa6nfFnRxZmCStCOZWYYPlaxr+FZceFbpMwzTNs4g3d4tLNUcbKAIH4 0wIDAQAB -----END PUBLIC KEY-----">>). -type config() :: #{ api_key => binary() | undefined, api_organization => binary() | undefined, api_repository => binary() | undefined, api_url => binary(), http_adapter => {module(), map()}, http_etag => binary() | undefined, http_headers => map(), http_user_agent_fragment => binary(), repo_key => binary() | undefined, repo_name => binary(), repo_public_key => binary(), repo_url => binary(), repo_organization => binary() | undefined, repo_verify => boolean(), repo_verify_origin => boolean(), tarball_max_size => pos_integer(), tarball_max_uncompressed_size => pos_integer() }. -spec default_config() -> config(). default_config() -> #{ api_key => undefined, api_organization => undefined, api_repository => undefined, api_url => <<"https://hex.pm/api">>, http_adapter => {mix_hex_http_httpc, #{profile => default}}, http_etag => undefined, http_headers => #{}, http_user_agent_fragment => <<"(httpc)">>, repo_key => undefined, repo_name => <<"hexpm">>, repo_public_key => ?HEXPM_PUBLIC_KEY, repo_url => <<"https://repo.hex.pm">>, repo_organization => undefined, repo_verify => true, repo_verify_origin => true, tarball_max_size => 8 * 1024 * 1024, tarball_max_uncompressed_size => 64 * 1024 * 1024 }. hex-2.0.6/src/mix_hex_core.hrl000066400000000000000000000001341437023760000162520ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually -define(HEX_CORE_VERSION, "0.8.2"). hex-2.0.6/src/mix_hex_erl_tar.erl000066400000000000000000002266561437023760000167720ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% @private %% Copied from https://github.com/erlang/otp/blob/OTP-20.0.1/lib/stdlib/src/erl_tar.erl %% with modifications: %% - Change module name to `mix_hex_erl_tar` %% - Set tar mtimes to 0 and remove dependency on :os.system_time/1 %% - Preserve modes when building tarball %% - Do not crash if failing to write tar %% - Allow setting file_info opts on :mix_hex_erl_tar.add %% - Add safe_relative_path_links/2 to check directory traversal vulnerability when extracting files, %% it differs from OTP's current fix (2020-02-04) in that it checks regular files instead of %% symlink targets. This allows creating symlinks with relative path targets such as `../tmp/log` %% - Remove ram_file usage (backported from OTP master) %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1997-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% %% This module implements extraction/creation of tar archives. %% It supports reading most common tar formats, namely V7, STAR, %% USTAR, GNU, BSD/libarchive, and PAX. It produces archives in USTAR %% format, unless it must use PAX headers, in which case it produces PAX %% format. %% %% The following references where used: %% http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5 %% http://www.gnu.org/software/tar/manual/html_node/Standard.html %% http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html -module(mix_hex_erl_tar). -export([init/3, create/2, create/3, extract/1, extract/2, table/1, table/2, t/1, tt/1, open/2, close/1, add/3, add/4, add/5, format_error/1]). -include_lib("kernel/include/file.hrl"). -include_lib("mix_hex_erl_tar.hrl"). %% Converts the short error reason to a descriptive string. -spec format_error(term()) -> string(). format_error(invalid_tar_checksum) -> "Checksum failed"; format_error(bad_header) -> "Unrecognized tar header format"; format_error({bad_header, Reason}) -> lists:flatten(io_lib:format("Unrecognized tar header format: ~p", [Reason])); format_error({invalid_header, negative_size}) -> "Invalid header: negative size"; format_error(invalid_sparse_header_size) -> "Invalid sparse header: negative size"; format_error(invalid_sparse_map_entry) -> "Invalid sparse map entry"; format_error({invalid_sparse_map_entry, Reason}) -> lists:flatten(io_lib:format("Invalid sparse map entry: ~p", [Reason])); format_error(invalid_end_of_archive) -> "Invalid end of archive"; format_error(eof) -> "Unexpected end of file"; format_error(integer_overflow) -> "Failed to parse numeric: integer overflow"; format_error({misaligned_read, Pos}) -> lists:flatten(io_lib:format("Read a block which was misaligned: block_size=~p pos=~p", [?BLOCK_SIZE, Pos])); format_error(invalid_gnu_1_0_sparsemap) -> "Invalid GNU sparse map (version 1.0)"; format_error({invalid_gnu_0_1_sparsemap, Format}) -> lists:flatten(io_lib:format("Invalid GNU sparse map (version ~s)", [Format])); format_error(unsafe_path) -> "The path points above the current working directory"; format_error({Name,Reason}) -> lists:flatten(io_lib:format("~ts: ~ts", [Name,format_error(Reason)])); format_error(Atom) when is_atom(Atom) -> file:format_error(Atom); format_error(Term) -> lists:flatten(io_lib:format("~tp", [Term])). %% Initializes a new reader given a custom file handle and I/O wrappers -spec init(handle(), write | read, file_op()) -> {ok, reader()} | {error, badarg}. init(Handle, AccessMode, Fun) when is_function(Fun, 2) -> Reader = #reader{handle=Handle,access=AccessMode,func=Fun}, {ok, Pos, Reader2} = do_position(Reader, {cur, 0}), {ok, Reader2#reader{pos=Pos}}; init(_Handle, _AccessMode, _Fun) -> {error, badarg}. %%%================================================================ %% Extracts all files from the tar file Name. -spec extract(open_handle()) -> ok | {error, term()}. extract(Name) -> extract(Name, []). %% Extracts (all) files from the tar file Name. %% Options accepted: %% - cooked: Opens the tar file without mode `raw` %% - compressed: Uncompresses the tar file when reading %% - memory: Returns the tar contents as a list of tuples {Name, Bin} %% - keep_old_files: Extracted files will not overwrite the destination %% - {files, ListOfFilesToExtract}: Only extract ListOfFilesToExtract %% - verbose: Prints verbose information about the extraction, %% - {cwd, AbsoluteDir}: Sets the current working directory for the extraction -spec extract(open_handle(), [extract_opt()]) -> ok | {ok, [{string(), binary()}]} | {error, term()}. extract({binary, Bin}, Opts) when is_list(Opts) -> do_extract({binary, Bin}, Opts); extract({file, Fd}, Opts) when is_list(Opts) -> do_extract({file, Fd}, Opts); extract(#reader{}=Reader, Opts) when is_list(Opts) -> do_extract(Reader, Opts); extract(Name, Opts) when is_list(Name); is_binary(Name), is_list(Opts) -> do_extract(Name, Opts). do_extract(Handle, Opts) when is_list(Opts) -> Opts2 = extract_opts(Opts), Acc = if Opts2#read_opts.output =:= memory -> []; true -> ok end, foldl_read(Handle, fun extract1/4, Acc, Opts2). extract1(eof, Reader, _, Acc) when is_list(Acc) -> {ok, {ok, lists:reverse(Acc)}, Reader}; extract1(eof, Reader, _, leading_slash) -> error_logger:info_msg("erl_tar: removed leading '/' from member names\n"), {ok, ok, Reader}; extract1(eof, Reader, _, Acc) -> {ok, Acc, Reader}; extract1(#tar_header{name=Name,size=Size}=Header, Reader0, Opts, Acc0) -> case check_extract(Name, Opts) of true -> case do_read(Reader0, Size) of {ok, Bin, Reader1} -> Acc = extract2(Header, Bin, Opts, Acc0), {ok, Acc, Reader1}; {error, _} = Err -> throw(Err) end; false -> {ok, Acc0, skip_file(Reader0)} end. extract2(Header, Bin, Opts, Acc) -> case write_extracted_element(Header, Bin, Opts) of ok -> case Header of #tar_header{name="/"++_} -> leading_slash; #tar_header{} -> Acc end; {ok, NameBin} when is_list(Acc) -> [NameBin | Acc]; {error, _} = Err -> throw(Err) end. %% Checks if the file Name should be extracted. check_extract(_, #read_opts{files=all}) -> true; check_extract(Name, #read_opts{files=Files}) -> ordsets:is_element(Name, Files). %%%================================================================ %% The following table functions produce a list of information about %% the files contained in the archive. -type filename() :: string(). -type typeflag() :: regular | link | symlink | char | block | directory | fifo | reserved | unknown. -type mode() :: non_neg_integer(). -type uid() :: non_neg_integer(). -type gid() :: non_neg_integer(). -type tar_entry() :: {filename(), typeflag(), non_neg_integer(), tar_time(), mode(), uid(), gid()}. %% Returns a list of names of the files in the tar file Name. -spec table(open_handle()) -> {ok, [string()]} | {error, term()}. table(Name) -> table(Name, []). %% Returns a list of names of the files in the tar file Name. %% Options accepted: compressed, verbose, cooked. -spec table(open_handle(), [compressed | verbose | cooked]) -> {ok, [tar_entry()]} | {error, term()}. table(Name, Opts) when is_list(Opts) -> foldl_read(Name, fun table1/4, [], table_opts(Opts)). table1(eof, Reader, _, Result) -> {ok, {ok, lists:reverse(Result)}, Reader}; table1(#tar_header{}=Header, Reader, #read_opts{verbose=Verbose}, Result) -> Attrs = table1_attrs(Header, Verbose), Reader2 = skip_file(Reader), {ok, [Attrs|Result], Reader2}. %% Extracts attributes relevant to table1's output table1_attrs(#tar_header{typeflag=Typeflag,mode=Mode}=Header, true) -> Type = typeflag(Typeflag), Name = Header#tar_header.name, Mtime = Header#tar_header.mtime, Uid = Header#tar_header.uid, Gid = Header#tar_header.gid, Size = Header#tar_header.size, {Name, Type, Size, Mtime, Mode, Uid, Gid}; table1_attrs(#tar_header{name=Name}, _Verbose) -> Name. typeflag(?TYPE_REGULAR) -> regular; typeflag(?TYPE_REGULAR_A) -> regular; typeflag(?TYPE_GNU_SPARSE) -> regular; typeflag(?TYPE_CONT) -> regular; typeflag(?TYPE_LINK) -> link; typeflag(?TYPE_SYMLINK) -> symlink; typeflag(?TYPE_CHAR) -> char; typeflag(?TYPE_BLOCK) -> block; typeflag(?TYPE_DIR) -> directory; typeflag(?TYPE_FIFO) -> fifo; typeflag(_) -> unknown. %%%================================================================ %% Comments for printing the contents of a tape archive, %% meant to be invoked from the shell. %% Prints each filename in the archive -spec t(file:filename()) -> ok | {error, term()}. t(Name) when is_list(Name); is_binary(Name) -> case table(Name) of {ok, List} -> lists:foreach(fun(N) -> ok = io:format("~ts\n", [N]) end, List); Error -> Error end. %% Prints verbose information about each file in the archive -spec tt(open_handle()) -> ok | {error, term()}. tt(Name) -> case table(Name, [verbose]) of {ok, List} -> lists:foreach(fun print_header/1, List); Error -> Error end. %% Used by tt/1 to print a tar_entry tuple -spec print_header(tar_entry()) -> ok. print_header({Name, Type, Size, Mtime, Mode, Uid, Gid}) -> io:format("~s~s ~4w/~-4w ~7w ~s ~s\n", [type_to_string(Type), mode_to_string(Mode), Uid, Gid, Size, time_to_string(Mtime), Name]). type_to_string(regular) -> "-"; type_to_string(directory) -> "d"; type_to_string(link) -> "l"; type_to_string(symlink) -> "s"; type_to_string(char) -> "c"; type_to_string(block) -> "b"; type_to_string(fifo) -> "f"; type_to_string(unknown) -> "?". %% Converts a numeric mode to its human-readable representation mode_to_string(Mode) -> mode_to_string(Mode, "xwrxwrxwr", []). mode_to_string(Mode, [C|T], Acc) when Mode band 1 =:= 1 -> mode_to_string(Mode bsr 1, T, [C|Acc]); mode_to_string(Mode, [_|T], Acc) -> mode_to_string(Mode bsr 1, T, [$-|Acc]); mode_to_string(_, [], Acc) -> Acc. %% Converts a tar_time() (POSIX time) to a readable string time_to_string(Secs0) -> Epoch = calendar:datetime_to_gregorian_seconds(?EPOCH), Secs = Epoch + Secs0, DateTime0 = calendar:gregorian_seconds_to_datetime(Secs), DateTime = calendar:universal_time_to_local_time(DateTime0), {{Y, Mon, Day}, {H, Min, _}} = DateTime, io_lib:format("~s ~2w ~s:~s ~w", [month(Mon), Day, two_d(H), two_d(Min), Y]). two_d(N) -> tl(integer_to_list(N + 100)). month(1) -> "Jan"; month(2) -> "Feb"; month(3) -> "Mar"; month(4) -> "Apr"; month(5) -> "May"; month(6) -> "Jun"; month(7) -> "Jul"; month(8) -> "Aug"; month(9) -> "Sep"; month(10) -> "Oct"; month(11) -> "Nov"; month(12) -> "Dec". %%%================================================================ %% The open function with friends is to keep the file and binary api of this module -type open_handle() :: file:filename() | {binary, binary()} | {file, term()}. -spec open(open_handle(), [write | compressed | cooked]) -> {ok, reader()} | {error, term()}. open({binary, Bin}, Mode) when is_binary(Bin) -> do_open({binary, Bin}, Mode); open({file, Fd}, Mode) -> do_open({file, Fd}, Mode); open(Name, Mode) when is_list(Name); is_binary(Name) -> do_open(Name, Mode). do_open(Name, Mode) when is_list(Mode) -> case open_mode(Mode) of {ok, Access, Raw, Opts} -> open1(Name, Access, Raw, Opts); {error, Reason} -> {error, {Name, Reason}} end. open1({binary,Bin0}, read, _Raw, Opts) when is_binary(Bin0) -> Bin = case lists:member(compressed, Opts) of true -> try zlib:gunzip(Bin0) catch _:_ -> Bin0 end; false -> Bin0 end, case file:open(Bin, [ram,binary,read]) of {ok,File} -> {ok, #reader{handle=File,access=read,func=fun file_op/2}}; Error -> Error end; open1({file, Fd}, read, _Raw, _Opts) -> Reader = #reader{handle=Fd,access=read,func=fun file_op/2}, case do_position(Reader, {cur, 0}) of {ok, Pos, Reader2} -> {ok, Reader2#reader{pos=Pos}}; {error, _} = Err -> Err end; open1(Name, Access, Raw, Opts) when is_list(Name) or is_binary(Name) -> case file:open(Name, Raw ++ [binary, Access|Opts]) of {ok, File} -> {ok, #reader{handle=File,access=Access,func=fun file_op/2}}; {error, Reason} -> {error, {Name, Reason}} end. open_mode(Mode) -> open_mode(Mode, false, [raw], []). open_mode(read, _, Raw, _) -> {ok, read, Raw, []}; open_mode(write, _, Raw, _) -> {ok, write, Raw, []}; open_mode([read|Rest], false, Raw, Opts) -> open_mode(Rest, read, Raw, Opts); open_mode([write|Rest], false, Raw, Opts) -> open_mode(Rest, write, Raw, Opts); open_mode([compressed|Rest], Access, Raw, Opts) -> open_mode(Rest, Access, Raw, [compressed|Opts]); open_mode([cooked|Rest], Access, _Raw, Opts) -> open_mode(Rest, Access, [], Opts); open_mode([], Access, Raw, Opts) -> {ok, Access, Raw, Opts}; open_mode(_, _, _, _) -> {error, einval}. file_op(write, {Fd, Data}) -> file:write(Fd, Data); file_op(position, {Fd, Pos}) -> file:position(Fd, Pos); file_op(read2, {Fd, Size}) -> file:read(Fd, Size); file_op(close, Fd) -> file:close(Fd). %% Closes a tar archive. -spec close(reader()) -> ok | {error, term()}. close(#reader{access=read}=Reader) -> ok = do_close(Reader); close(#reader{access=write}=Reader) -> {ok, Reader2} = pad_file(Reader), ok = do_close(Reader2), ok; close(_) -> {error, einval}. pad_file(#reader{pos=Pos}=Reader) -> %% There must be at least two zero blocks at the end. PadCurrent = skip_padding(Pos+?BLOCK_SIZE), Padding = <<0:PadCurrent/unit:8>>, do_write(Reader, [Padding, ?ZERO_BLOCK, ?ZERO_BLOCK]). %%%================================================================ %% Creation/modification of tar archives %% Creates a tar file Name containing the given files. -spec create(file:filename(), filelist()) -> ok | {error, {string(), term()}}. create(Name, FileList) when is_list(Name); is_binary(Name) -> create(Name, FileList, []). %% Creates a tar archive Name containing the given files. %% Accepted options: verbose, compressed, cooked -spec create(file:filename(), filelist(), [create_opt()]) -> ok | {error, term()} | {error, {string(), term()}}. create(Name, FileList, Options) when is_list(Name); is_binary(Name) -> Mode = lists:filter(fun(X) -> (X=:=compressed) or (X=:=cooked) end, Options), case open(Name, [write|Mode]) of {ok, TarFile} -> do_create(TarFile, FileList, Options); {error, _} = Err -> Err end. do_create(TarFile, [], _Opts) -> close(TarFile); do_create(TarFile, [{NameInArchive, NameOrBin}|Rest], Opts) -> case add(TarFile, NameOrBin, NameInArchive, Opts) of ok -> do_create(TarFile, Rest, Opts); {error, _} = Err -> _ = close(TarFile), Err end; do_create(TarFile, [Name|Rest], Opts) -> case add(TarFile, Name, Name, Opts) of ok -> do_create(TarFile, Rest, Opts); {error, _} = Err -> _ = close(TarFile), Err end. %% Adds a file to a tape archive. -type add_type() :: string() | {string(), string()} | {string(), binary()}. -spec add(reader(), add_type(), [add_opt()]) -> ok | {error, term()}. add(Reader, {NameInArchive, Name}, Opts) when is_list(NameInArchive), is_list(Name) -> do_add(Reader, Name, NameInArchive, undefined, Opts); add(Reader, {NameInArchive, Bin}, Opts) when is_list(NameInArchive), is_binary(Bin) -> do_add(Reader, Bin, NameInArchive, undefined, Opts); add(Reader, {NameInArchive, Bin, Mode}, Opts) when is_list(NameInArchive), is_binary(Bin), is_integer(Mode) -> do_add(Reader, Bin, NameInArchive, Mode, Opts); add(Reader, Name, Opts) when is_list(Name) -> do_add(Reader, Name, Name, undefined, Opts). -spec add(reader(), string() | binary(), string(), [add_opt()]) -> ok | {error, term()}. add(Reader, NameOrBin, NameInArchive, Options) when is_list(NameOrBin); is_binary(NameOrBin), is_list(NameInArchive), is_list(Options) -> do_add(Reader, NameOrBin, NameInArchive, undefined, Options). -spec add(reader(), string() | binary(), string(), integer(), [add_opt()]) -> ok | {error, term()}. add(Reader, NameOrBin, NameInArchive, Mode, Options) when is_list(NameOrBin); is_binary(NameOrBin), is_list(NameInArchive), is_integer(Mode), is_list(Options) -> do_add(Reader, NameOrBin, NameInArchive, Mode, Options). do_add(#reader{access=write}=Reader, Name, NameInArchive, Mode, Options) when is_list(NameInArchive), is_list(Options) -> RF = fun(F) -> apply_file_info_opts(Options, file:read_link_info(F, [{time, posix}])) end, Opts = #add_opts{read_info=RF}, add1(Reader, Name, NameInArchive, Mode, add_opts(Options, Options, Opts)); do_add(#reader{access=read},_,_,_,_) -> {error, eacces}; do_add(Reader,_,_,_,_) -> {error, {badarg, Reader}}. add_opts([dereference|T], AllOptions, Opts) -> RF = fun(F) -> apply_file_info_opts(AllOptions, file:read_file_info(F, [{time, posix}])) end, add_opts(T, AllOptions, Opts#add_opts{read_info=RF}); add_opts([verbose|T], AllOptions, Opts) -> add_opts(T, AllOptions, Opts#add_opts{verbose=true}); add_opts([{chunks,N}|T], AllOptions, Opts) -> add_opts(T, AllOptions, Opts#add_opts{chunk_size=N}); add_opts([{atime,Value}|T], AllOptions, Opts) -> add_opts(T, AllOptions, Opts#add_opts{atime=Value}); add_opts([{mtime,Value}|T], AllOptions, Opts) -> add_opts(T, AllOptions, Opts#add_opts{mtime=Value}); add_opts([{ctime,Value}|T], AllOptions, Opts) -> add_opts(T, AllOptions, Opts#add_opts{ctime=Value}); add_opts([{uid,Value}|T], AllOptions, Opts) -> add_opts(T, AllOptions, Opts#add_opts{uid=Value}); add_opts([{gid,Value}|T], AllOptions, Opts) -> add_opts(T, AllOptions, Opts#add_opts{gid=Value}); add_opts([_|T], AllOptions, Opts) -> add_opts(T, AllOptions, Opts); add_opts([], _AllOptions, Opts) -> Opts. apply_file_info_opts(Opts, {ok, FileInfo}) -> {ok, do_apply_file_info_opts(Opts, FileInfo)}; apply_file_info_opts(_Opts, Other) -> Other. do_apply_file_info_opts([{atime,Value}|T], FileInfo) -> do_apply_file_info_opts(T, FileInfo#file_info{atime=Value}); do_apply_file_info_opts([{mtime,Value}|T], FileInfo) -> do_apply_file_info_opts(T, FileInfo#file_info{mtime=Value}); do_apply_file_info_opts([{ctime,Value}|T], FileInfo) -> do_apply_file_info_opts(T, FileInfo#file_info{ctime=Value}); do_apply_file_info_opts([{uid,Value}|T], FileInfo) -> do_apply_file_info_opts(T, FileInfo#file_info{uid=Value}); do_apply_file_info_opts([{gid,Value}|T], FileInfo) -> do_apply_file_info_opts(T, FileInfo#file_info{gid=Value}); do_apply_file_info_opts([_|T], FileInfo) -> do_apply_file_info_opts(T, FileInfo); do_apply_file_info_opts([], FileInfo) -> FileInfo. add1(#reader{}=Reader, Name, NameInArchive, undefined, #add_opts{read_info=ReadInfo}=Opts) when is_list(Name) -> Res = case ReadInfo(Name) of {error, Reason0} -> {error, {Name, Reason0}}; {ok, #file_info{type=symlink}=Fi} -> add_verbose(Opts, "a ~ts~n", [NameInArchive]), {ok, Linkname} = file:read_link(Name), Header = fileinfo_to_header(NameInArchive, Fi, Linkname), add_header(Reader, Header, Opts); {ok, #file_info{type=regular}=Fi} -> add_verbose(Opts, "a ~ts~n", [NameInArchive]), Header = fileinfo_to_header(NameInArchive, Fi, false), {ok, Reader2} = add_header(Reader, Header, Opts), FileSize = Header#tar_header.size, {ok, FileSize, Reader3} = do_copy(Reader2, Name, Opts), Padding = skip_padding(FileSize), Pad = <<0:Padding/unit:8>>, do_write(Reader3, Pad); {ok, #file_info{type=directory}=Fi} -> add_directory(Reader, Name, NameInArchive, Fi, Opts); {ok, #file_info{}=Fi} -> add_verbose(Opts, "a ~ts~n", [NameInArchive]), Header = fileinfo_to_header(NameInArchive, Fi, false), add_header(Reader, Header, Opts) end, case Res of ok -> ok; {ok, _Reader} -> ok; {error, _Reason} = Err -> Err end; add1(Reader, Bin, NameInArchive, Mode, Opts) when is_binary(Bin) -> add_verbose(Opts, "a ~ts~n", [NameInArchive]), Now = 0, Header = #tar_header{ name = NameInArchive, size = byte_size(Bin), typeflag = ?TYPE_REGULAR, atime = add_opts_time(Opts#add_opts.atime, Now), mtime = add_opts_time(Opts#add_opts.mtime, Now), ctime = add_opts_time(Opts#add_opts.ctime, Now), uid = Opts#add_opts.uid, gid = Opts#add_opts.gid, mode = default_mode(Mode, 8#100644)}, {ok, Reader2} = add_header(Reader, Header, Opts), Padding = skip_padding(byte_size(Bin)), Data = [Bin, <<0:Padding/unit:8>>], case do_write(Reader2, Data) of {ok, _Reader3} -> ok; {error, Reason} -> {error, {NameInArchive, Reason}} end. add_opts_time(undefined, _Now) -> 0; add_opts_time(Time, _Now) -> Time. default_mode(undefined, Mode) -> Mode; default_mode(Mode, _) -> Mode. add_directory(Reader, DirName, NameInArchive, Info, Opts) -> case file:list_dir(DirName) of {ok, []} -> add_verbose(Opts, "a ~ts~n", [NameInArchive]), Header = fileinfo_to_header(NameInArchive, Info, false), add_header(Reader, Header, Opts); {ok, Files} -> add_verbose(Opts, "a ~ts~n", [NameInArchive]), try add_files(Reader, Files, DirName, NameInArchive, Opts) of ok -> ok; {error, _} = Err -> Err catch throw:{error, {_Name, _Reason}} = Err -> Err; throw:{error, Reason} -> {error, {DirName, Reason}} end; {error, Reason} -> {error, {DirName, Reason}} end. add_files(_Reader, [], _Dir, _DirInArchive, _Opts) -> ok; add_files(Reader, [Name|Rest], Dir, DirInArchive, #add_opts{read_info=Info}=Opts) -> FullName = filename:join(Dir, Name), NameInArchive = filename:join(DirInArchive, Name), Res = case Info(FullName) of {error, Reason} -> {error, {FullName, Reason}}; {ok, #file_info{type=directory}=Fi} -> add_directory(Reader, FullName, NameInArchive, Fi, Opts); {ok, #file_info{type=symlink}=Fi} -> add_verbose(Opts, "a ~ts~n", [NameInArchive]), {ok, Linkname} = file:read_link(FullName), Header = fileinfo_to_header(NameInArchive, Fi, Linkname), add_header(Reader, Header, Opts); {ok, #file_info{type=regular}=Fi} -> add_verbose(Opts, "a ~ts~n", [NameInArchive]), Header = fileinfo_to_header(NameInArchive, Fi, false), {ok, Reader2} = add_header(Reader, Header, Opts), FileSize = Header#tar_header.size, {ok, FileSize, Reader3} = do_copy(Reader2, FullName, Opts), Padding = skip_padding(FileSize), Pad = <<0:Padding/unit:8>>, do_write(Reader3, Pad); {ok, #file_info{}=Fi} -> add_verbose(Opts, "a ~ts~n", [NameInArchive]), Header = fileinfo_to_header(NameInArchive, Fi, false), add_header(Reader, Header, Opts) end, case Res of ok -> add_files(Reader, Rest, Dir, DirInArchive, Opts); {ok, ReaderNext} -> add_files(ReaderNext, Rest, Dir, DirInArchive, Opts); {error, _} = Err -> Err end. format_string(String, Size) when length(String) > Size -> throw({error, {write_string, field_too_long}}); format_string(String, Size) -> Ascii = to_ascii(String), if byte_size(Ascii) < Size -> [Ascii, 0]; true -> Ascii end. format_octal(Octal) -> iolist_to_binary(io_lib:fwrite("~.8B", [Octal])). add_header(#reader{}=Reader, #tar_header{}=Header, Opts) -> {ok, Iodata} = build_header(Header, Opts), do_write(Reader, Iodata). write_to_block(Block, IoData, Start) when is_list(IoData) -> write_to_block(Block, iolist_to_binary(IoData), Start); write_to_block(Block, Bin, Start) when is_binary(Bin) -> Size = byte_size(Bin), <> = Block, <>. build_header(#tar_header{}=Header, Opts) -> #tar_header{ name=Name, mode=Mode, uid=Uid, gid=Gid, size=Size, typeflag=Type, linkname=Linkname, uname=Uname, gname=Gname, devmajor=Devmaj, devminor=Devmin } = Header, Mtime = Header#tar_header.mtime, Block0 = ?ZERO_BLOCK, {Block1, Pax0} = write_string(Block0, ?V7_NAME, ?V7_NAME_LEN, Name, ?PAX_PATH, #{}), Block2 = write_octal(Block1, ?V7_MODE, ?V7_MODE_LEN, Mode), {Block3, Pax1} = write_numeric(Block2, ?V7_UID, ?V7_UID_LEN, Uid, ?PAX_UID, Pax0), {Block4, Pax2} = write_numeric(Block3, ?V7_GID, ?V7_GID_LEN, Gid, ?PAX_GID, Pax1), {Block5, Pax3} = write_numeric(Block4, ?V7_SIZE, ?V7_SIZE_LEN, Size, ?PAX_SIZE, Pax2), {Block6, Pax4} = write_numeric(Block5, ?V7_MTIME, ?V7_MTIME_LEN, Mtime, ?PAX_NONE, Pax3), {Block7, Pax5} = write_string(Block6, ?V7_TYPE, ?V7_TYPE_LEN, <>, ?PAX_NONE, Pax4), {Block8, Pax6} = write_string(Block7, ?V7_LINKNAME, ?V7_LINKNAME_LEN, Linkname, ?PAX_LINKPATH, Pax5), {Block9, Pax7} = write_string(Block8, ?USTAR_UNAME, ?USTAR_UNAME_LEN, Uname, ?PAX_UNAME, Pax6), {Block10, Pax8} = write_string(Block9, ?USTAR_GNAME, ?USTAR_GNAME_LEN, Gname, ?PAX_GNAME, Pax7), {Block11, Pax9} = write_numeric(Block10, ?USTAR_DEVMAJ, ?USTAR_DEVMAJ_LEN, Devmaj, ?PAX_NONE, Pax8), {Block12, Pax10} = write_numeric(Block11, ?USTAR_DEVMIN, ?USTAR_DEVMIN_LEN, Devmin, ?PAX_NONE, Pax9), {Block13, Pax11} = set_path(Block12, Pax10), PaxEntry = case maps:size(Pax11) of 0 -> []; _ -> build_pax_entry(Header, Pax11, Opts) end, Block14 = set_format(Block13, ?FORMAT_USTAR), Block15 = set_checksum(Block14), {ok, [PaxEntry, Block15]}. set_path(Block0, Pax) -> %% only use ustar header when name is too long case maps:get(?PAX_PATH, Pax, nil) of nil -> {Block0, Pax}; PaxPath -> case split_ustar_path(PaxPath) of {ok, UstarName, UstarPrefix} -> {Block1, _} = write_string(Block0, ?V7_NAME, ?V7_NAME_LEN, UstarName, ?PAX_NONE, #{}), {Block2, _} = write_string(Block1, ?USTAR_PREFIX, ?USTAR_PREFIX_LEN, UstarPrefix, ?PAX_NONE, #{}), {Block2, maps:remove(?PAX_PATH, Pax)}; false -> {Block0, Pax} end end. set_format(Block0, Format) when Format =:= ?FORMAT_USTAR; Format =:= ?FORMAT_PAX -> Block1 = write_to_block(Block0, ?MAGIC_USTAR, ?USTAR_MAGIC), write_to_block(Block1, ?VERSION_USTAR, ?USTAR_VERSION); set_format(_Block, Format) -> throw({error, {invalid_format, Format}}). set_checksum(Block) -> Checksum = compute_checksum(Block), write_octal(Block, ?V7_CHKSUM, ?V7_CHKSUM_LEN, Checksum). build_pax_entry(Header, PaxAttrs, Opts) -> Path = Header#tar_header.name, Filename = filename:basename(Path), Dir = filename:dirname(Path), Path2 = filename:join([Dir, "PaxHeaders.0", Filename]), AsciiPath = to_ascii(Path2), Path3 = if byte_size(AsciiPath) > ?V7_NAME_LEN -> binary_part(AsciiPath, 0, ?V7_NAME_LEN - 1); true -> AsciiPath end, Keys = maps:keys(PaxAttrs), SortedKeys = lists:sort(Keys), PaxFile = build_pax_file(SortedKeys, PaxAttrs), Size = byte_size(PaxFile), Padding = (?BLOCK_SIZE - (byte_size(PaxFile) rem ?BLOCK_SIZE)) rem ?BLOCK_SIZE, Pad = <<0:Padding/unit:8>>, PaxHeader = #tar_header{ name=unicode:characters_to_list(Path3), size=Size, mtime=Header#tar_header.mtime, atime=Header#tar_header.atime, ctime=Header#tar_header.ctime, typeflag=?TYPE_X_HEADER }, {ok, PaxHeaderData} = build_header(PaxHeader, Opts), [PaxHeaderData, PaxFile, Pad]. build_pax_file(Keys, PaxAttrs) -> build_pax_file(Keys, PaxAttrs, []). build_pax_file([], _, Acc) -> unicode:characters_to_binary(Acc); build_pax_file([K|Rest], Attrs, Acc) -> V = maps:get(K, Attrs), Size = sizeof(K) + sizeof(V) + 3, Size2 = sizeof(Size) + Size, Key = to_string(K), Value = to_string(V), Record = unicode:characters_to_binary(io_lib:format("~B ~ts=~ts\n", [Size2, Key, Value])), if byte_size(Record) =/= Size2 -> Size3 = byte_size(Record), Record2 = io_lib:format("~B ~ts=~ts\n", [Size3, Key, Value]), build_pax_file(Rest, Attrs, [Acc, Record2]); true -> build_pax_file(Rest, Attrs, [Acc, Record]) end. sizeof(Bin) when is_binary(Bin) -> byte_size(Bin); sizeof(List) when is_list(List) -> length(List); sizeof(N) when is_integer(N) -> byte_size(integer_to_binary(N)); sizeof(N) when is_float(N) -> byte_size(float_to_binary(N)). to_string(Bin) when is_binary(Bin) -> unicode:characters_to_list(Bin); to_string(List) when is_list(List) -> List; to_string(N) when is_integer(N) -> integer_to_list(N); to_string(N) when is_float(N) -> float_to_list(N). split_ustar_path(Path) -> Len = length(Path), NotAscii = not is_ascii(Path), if Len =< ?V7_NAME_LEN; NotAscii -> false; true -> PathBin = binary:list_to_bin(Path), case binary:split(PathBin, [<<$/>>], [global, trim_all]) of [Part] when byte_size(Part) >= ?V7_NAME_LEN -> false; Parts -> case lists:last(Parts) of Name when byte_size(Name) >= ?V7_NAME_LEN -> false; Name -> Parts2 = lists:sublist(Parts, length(Parts) - 1), join_split_ustar_path(Parts2, {ok, Name, nil}) end end end. join_split_ustar_path([], Acc) -> Acc; join_split_ustar_path([Part|_], {ok, _, nil}) when byte_size(Part) > ?USTAR_PREFIX_LEN -> false; join_split_ustar_path([Part|_], {ok, _Name, Acc}) when (byte_size(Part)+byte_size(Acc)) > ?USTAR_PREFIX_LEN -> false; join_split_ustar_path([Part|Rest], {ok, Name, nil}) -> join_split_ustar_path(Rest, {ok, Name, Part}); join_split_ustar_path([Part|Rest], {ok, Name, Acc}) -> join_split_ustar_path(Rest, {ok, Name, <>}). write_octal(Block, Pos, Size, X) -> Octal = zero_pad(format_octal(X), Size-1), if byte_size(Octal) < Size -> write_to_block(Block, Octal, Pos); true -> throw({error, {write_failed, octal_field_too_long}}) end. write_string(Block, Pos, Size, Str, PaxAttr, Pax0) -> NotAscii = not is_ascii(Str), if PaxAttr =/= ?PAX_NONE andalso (length(Str) > Size orelse NotAscii) -> Pax1 = maps:put(PaxAttr, Str, Pax0), {Block, Pax1}; true -> Formatted = format_string(Str, Size), {write_to_block(Block, Formatted, Pos), Pax0} end. write_numeric(Block, Pos, Size, X, PaxAttr, Pax0) -> %% attempt octal Octal = zero_pad(format_octal(X), Size-1), if byte_size(Octal) < Size -> {write_to_block(Block, [Octal, 0], Pos), Pax0}; PaxAttr =/= ?PAX_NONE -> Pax1 = maps:put(PaxAttr, X, Pax0), {Block, Pax1}; true -> throw({error, {write_failed, numeric_field_too_long}}) end. zero_pad(Str, Size) when byte_size(Str) >= Size -> Str; zero_pad(Str, Size) -> Padding = Size - byte_size(Str), Pad = binary:copy(<<$0>>, Padding), <>. %%%================================================================ %% Functions for creating or modifying tar archives read_block(Reader) -> case do_read(Reader, ?BLOCK_SIZE) of eof -> throw({error, eof}); %% Two zero blocks mark the end of the archive {ok, ?ZERO_BLOCK, Reader1} -> case do_read(Reader1, ?BLOCK_SIZE) of eof -> % This is technically a malformed end-of-archive marker, % as two ZERO_BLOCKs are expected as the marker, % but if we've already made it this far, we should just ignore it eof; {ok, ?ZERO_BLOCK, _Reader2} -> eof; {ok, _Block, _Reader2} -> throw({error, invalid_end_of_archive}); {error,_} = Err -> throw(Err) end; {ok, Block, Reader1} when is_binary(Block) -> {ok, Block, Reader1}; {error, _} = Err -> throw(Err) end. get_header(#reader{}=Reader) -> case read_block(Reader) of eof -> eof; {ok, Block, Reader1} -> convert_header(Block, Reader1) end. %% Converts the tar header to a record. to_v7(Bin) when is_binary(Bin), byte_size(Bin) =:= ?BLOCK_SIZE -> #header_v7{ name=binary_part(Bin, ?V7_NAME, ?V7_NAME_LEN), mode=binary_part(Bin, ?V7_MODE, ?V7_MODE_LEN), uid=binary_part(Bin, ?V7_UID, ?V7_UID_LEN), gid=binary_part(Bin, ?V7_GID, ?V7_GID_LEN), size=binary_part(Bin, ?V7_SIZE, ?V7_SIZE_LEN), mtime=binary_part(Bin, ?V7_MTIME, ?V7_MTIME_LEN), checksum=binary_part(Bin, ?V7_CHKSUM, ?V7_CHKSUM_LEN), typeflag=binary:at(Bin, ?V7_TYPE), linkname=binary_part(Bin, ?V7_LINKNAME, ?V7_LINKNAME_LEN) }; to_v7(_) -> {error, header_block_too_small}. to_gnu(#header_v7{}=V7, Bin) when is_binary(Bin), byte_size(Bin) =:= ?BLOCK_SIZE -> #header_gnu{ header_v7=V7, magic=binary_part(Bin, ?GNU_MAGIC, ?GNU_MAGIC_LEN), version=binary_part(Bin, ?GNU_VERSION, ?GNU_VERSION_LEN), uname=binary_part(Bin, 265, 32), gname=binary_part(Bin, 297, 32), devmajor=binary_part(Bin, 329, 8), devminor=binary_part(Bin, 337, 8), atime=binary_part(Bin, 345, 12), ctime=binary_part(Bin, 357, 12), sparse=to_sparse_array(binary_part(Bin, 386, 24*4+1)), real_size=binary_part(Bin, 483, 12) }. to_star(#header_v7{}=V7, Bin) when is_binary(Bin), byte_size(Bin) =:= ?BLOCK_SIZE -> #header_star{ header_v7=V7, magic=binary_part(Bin, ?USTAR_MAGIC, ?USTAR_MAGIC_LEN), version=binary_part(Bin, ?USTAR_VERSION, ?USTAR_VERSION_LEN), uname=binary_part(Bin, ?USTAR_UNAME, ?USTAR_UNAME_LEN), gname=binary_part(Bin, ?USTAR_GNAME, ?USTAR_GNAME_LEN), devmajor=binary_part(Bin, ?USTAR_DEVMAJ, ?USTAR_DEVMAJ_LEN), devminor=binary_part(Bin, ?USTAR_DEVMIN, ?USTAR_DEVMIN_LEN), prefix=binary_part(Bin, 345, 131), atime=binary_part(Bin, 476, 12), ctime=binary_part(Bin, 488, 12), trailer=binary_part(Bin, ?STAR_TRAILER, ?STAR_TRAILER_LEN) }. to_ustar(#header_v7{}=V7, Bin) when is_binary(Bin), byte_size(Bin) =:= ?BLOCK_SIZE -> #header_ustar{ header_v7=V7, magic=binary_part(Bin, ?USTAR_MAGIC, ?USTAR_MAGIC_LEN), version=binary_part(Bin, ?USTAR_VERSION, ?USTAR_VERSION_LEN), uname=binary_part(Bin, ?USTAR_UNAME, ?USTAR_UNAME_LEN), gname=binary_part(Bin, ?USTAR_GNAME, ?USTAR_GNAME_LEN), devmajor=binary_part(Bin, ?USTAR_DEVMAJ, ?USTAR_DEVMAJ_LEN), devminor=binary_part(Bin, ?USTAR_DEVMIN, ?USTAR_DEVMIN_LEN), prefix=binary_part(Bin, 345, 155) }. to_sparse_array(Bin) when is_binary(Bin) -> MaxEntries = byte_size(Bin) div 24, IsExtended = 1 =:= binary:at(Bin, 24*MaxEntries), Entries = parse_sparse_entries(Bin, MaxEntries-1, []), #sparse_array{ entries=Entries, max_entries=MaxEntries, is_extended=IsExtended }. parse_sparse_entries(<<>>, _, Acc) -> Acc; parse_sparse_entries(_, -1, Acc) -> Acc; parse_sparse_entries(Bin, N, Acc) -> case to_sparse_entry(binary_part(Bin, N*24, 24)) of nil -> parse_sparse_entries(Bin, N-1, Acc); Entry = #sparse_entry{} -> parse_sparse_entries(Bin, N-1, [Entry|Acc]) end. -define(EMPTY_ENTRY, <<0,0,0,0,0,0,0,0,0,0,0,0>>). to_sparse_entry(Bin) when is_binary(Bin), byte_size(Bin) =:= 24 -> OffsetBin = binary_part(Bin, 0, 12), NumBytesBin = binary_part(Bin, 12, 12), case {OffsetBin, NumBytesBin} of {?EMPTY_ENTRY, ?EMPTY_ENTRY} -> nil; _ -> #sparse_entry{ offset=parse_numeric(OffsetBin), num_bytes=parse_numeric(NumBytesBin)} end. -spec get_format(binary()) -> {ok, pos_integer(), header_v7()} | ?FORMAT_UNKNOWN | {error, term()}. get_format(Bin) when is_binary(Bin), byte_size(Bin) =:= ?BLOCK_SIZE -> do_get_format(to_v7(Bin), Bin). do_get_format({error, _} = Err, _Bin) -> Err; do_get_format(#header_v7{}=V7, Bin) when is_binary(Bin), byte_size(Bin) =:= ?BLOCK_SIZE -> Checksum = parse_octal(V7#header_v7.checksum), Chk1 = compute_checksum(Bin), Chk2 = compute_signed_checksum(Bin), if Checksum =/= Chk1 andalso Checksum =/= Chk2 -> ?FORMAT_UNKNOWN; true -> %% guess magic Ustar = to_ustar(V7, Bin), Star = to_star(V7, Bin), Magic = Ustar#header_ustar.magic, Version = Ustar#header_ustar.version, Trailer = Star#header_star.trailer, Format = if Magic =:= ?MAGIC_USTAR, Trailer =:= ?TRAILER_STAR -> ?FORMAT_STAR; Magic =:= ?MAGIC_USTAR -> ?FORMAT_USTAR; Magic =:= ?MAGIC_GNU, Version =:= ?VERSION_GNU -> ?FORMAT_GNU; true -> ?FORMAT_V7 end, {ok, Format, V7} end. unpack_format(Format, #header_v7{}=V7, Bin, Reader) when is_binary(Bin), byte_size(Bin) =:= ?BLOCK_SIZE -> Mtime = parse_numeric(V7#header_v7.mtime), Header0 = #tar_header{ name=parse_string(V7#header_v7.name), mode=parse_numeric(V7#header_v7.mode), uid=parse_numeric(V7#header_v7.uid), gid=parse_numeric(V7#header_v7.gid), size=parse_numeric(V7#header_v7.size), mtime=Mtime, atime=Mtime, ctime=Mtime, typeflag=V7#header_v7.typeflag, linkname=parse_string(V7#header_v7.linkname) }, Typeflag = Header0#tar_header.typeflag, Header1 = if Format > ?FORMAT_V7 -> unpack_modern(Format, V7, Bin, Header0); true -> Name = Header0#tar_header.name, Header0#tar_header{name=safe_join_path("", Name)} end, HeaderOnly = is_header_only_type(Typeflag), Header2 = if HeaderOnly -> Header1#tar_header{size=0}; true -> Header1 end, if Typeflag =:= ?TYPE_GNU_SPARSE -> Gnu = to_gnu(V7, Bin), RealSize = parse_numeric(Gnu#header_gnu.real_size), {Sparsemap, Reader2} = parse_sparse_map(Gnu, Reader), Header3 = Header2#tar_header{size=RealSize}, {Header3, new_sparse_file_reader(Reader2, Sparsemap, RealSize)}; true -> FileReader = #reg_file_reader{ handle=Reader, num_bytes=Header2#tar_header.size, size=Header2#tar_header.size, pos = 0 }, {Header2, FileReader} end. unpack_modern(Format, #header_v7{}=V7, Bin, #tar_header{}=Header0) when is_binary(Bin) -> Typeflag = Header0#tar_header.typeflag, Ustar = to_ustar(V7, Bin), H0 = Header0#tar_header{ uname=parse_string(Ustar#header_ustar.uname), gname=parse_string(Ustar#header_ustar.gname)}, H1 = if Typeflag =:= ?TYPE_CHAR orelse Typeflag =:= ?TYPE_BLOCK -> Ma = parse_numeric(Ustar#header_ustar.devmajor), Mi = parse_numeric(Ustar#header_ustar.devminor), H0#tar_header{ devmajor=Ma, devminor=Mi }; true -> H0 end, {Prefix, H2} = case Format of ?FORMAT_USTAR -> {parse_string(Ustar#header_ustar.prefix), H1}; ?FORMAT_STAR -> Star = to_star(V7, Bin), Prefix0 = parse_string(Star#header_star.prefix), Atime0 = Star#header_star.atime, Atime = parse_numeric(Atime0), Ctime0 = Star#header_star.ctime, Ctime = parse_numeric(Ctime0), {Prefix0, H1#tar_header{ atime=Atime, ctime=Ctime }}; _ -> {"", H1} end, Name = H2#tar_header.name, H2#tar_header{name=safe_join_path(Prefix, Name)}. safe_join_path([], Name) -> filename:join([Name]); safe_join_path(Prefix, []) -> filename:join([Prefix]); safe_join_path(Prefix, Name) -> filename:join(Prefix, Name). new_sparse_file_reader(Reader, Sparsemap, RealSize) -> true = validate_sparse_entries(Sparsemap, RealSize), #sparse_file_reader{ handle = Reader, num_bytes = RealSize, pos = 0, size = RealSize, sparse_map = Sparsemap}. validate_sparse_entries(Entries, RealSize) -> validate_sparse_entries(Entries, RealSize, 0, 0). validate_sparse_entries([], _RealSize, _I, _LastOffset) -> true; validate_sparse_entries([#sparse_entry{}=Entry|Rest], RealSize, I, LastOffset) -> Offset = Entry#sparse_entry.offset, NumBytes = Entry#sparse_entry.num_bytes, if Offset > ?MAX_INT64-NumBytes -> throw({error, {invalid_sparse_map_entry, offset_too_large}}); Offset+NumBytes > RealSize -> throw({error, {invalid_sparse_map_entry, offset_too_large}}); I > 0 andalso LastOffset > Offset -> throw({error, {invalid_sparse_map_entry, overlapping_offsets}}); true -> ok end, validate_sparse_entries(Rest, RealSize, I+1, Offset+NumBytes). -spec parse_sparse_map(header_gnu(), reader_type()) -> {[sparse_entry()], reader_type()}. parse_sparse_map(#header_gnu{sparse=Sparse}, Reader) when Sparse#sparse_array.is_extended -> parse_sparse_map(Sparse, Reader, []); parse_sparse_map(#header_gnu{sparse=Sparse}, Reader) -> {Sparse#sparse_array.entries, Reader}. parse_sparse_map(#sparse_array{is_extended=true,entries=Entries}, Reader, Acc) -> case read_block(Reader) of eof -> throw({error, eof}); {ok, Block, Reader2} -> Sparse2 = to_sparse_array(Block), parse_sparse_map(Sparse2, Reader2, Entries++Acc) end; parse_sparse_map(#sparse_array{entries=Entries}, Reader, Acc) -> Sorted = lists:sort(fun (#sparse_entry{offset=A},#sparse_entry{offset=B}) -> A =< B end, Entries++Acc), {Sorted, Reader}. %% Defined by taking the sum of the unsigned byte values of the %% entire header record, treating the checksum bytes to as ASCII spaces compute_checksum(<>) -> C0 = checksum(H1) + (byte_size(H2) * $\s), C1 = checksum(Rest), C0 + C1. compute_signed_checksum(<>) -> C0 = signed_checksum(H1) + (byte_size(H2) * $\s), C1 = signed_checksum(Rest), C0 + C1. %% Returns the checksum of a binary. checksum(Bin) -> checksum(Bin, 0). checksum(<>, Sum) -> checksum(Rest, Sum+A); checksum(<<>>, Sum) -> Sum. signed_checksum(Bin) -> signed_checksum(Bin, 0). signed_checksum(<>, Sum) -> signed_checksum(Rest, Sum+A); signed_checksum(<<>>, Sum) -> Sum. -spec parse_numeric(binary()) -> non_neg_integer(). parse_numeric(<<>>) -> 0; parse_numeric(<> = Bin) -> %% check for base-256 format first %% if the bit is set, then all following bits constitute a two's %% complement encoded number in big-endian byte order if First band 16#80 =/= 0 -> %% Handling negative numbers relies on the following identity: %% -a-1 == ^a %% If the number is negative, we use an inversion mask to invert %% the data bytes and treat the value as an unsigned number Inv = if First band 16#40 =/= 0 -> 16#00; true -> 16#FF end, Bytes = binary:bin_to_list(Bin), Reducer = fun (C, {I, X}) -> C1 = C bxor Inv, C2 = if I =:= 0 -> C1 band 16#7F; true -> C1 end, if (X bsr 56) > 0 -> throw({error,integer_overflow}); true -> {I+1, (X bsl 8) bor C2} end end, {_, N} = lists:foldl(Reducer, {0,0}, Bytes), if (N bsr 63) > 0 -> throw({error, integer_overflow}); true -> if Inv =:= 16#FF -> -1 bxor N; true -> N end end; true -> %% normal case is an octal number parse_octal(Bin) end. parse_octal(Bin) when is_binary(Bin) -> %% skip leading/trailing zero bytes and spaces do_parse_octal(Bin, <<>>). do_parse_octal(<<>>, <<>>) -> 0; do_parse_octal(<<>>, Acc) -> case io_lib:fread("~8u", binary:bin_to_list(Acc)) of {error, _} -> throw({error, invalid_tar_checksum}); {ok, [Octal], []} -> Octal; {ok, _, _} -> throw({error, invalid_tar_checksum}) end; do_parse_octal(<<$\s,Rest/binary>>, Acc) -> do_parse_octal(Rest, Acc); do_parse_octal(<<0, Rest/binary>>, Acc) -> do_parse_octal(Rest, Acc); do_parse_octal(<>, Acc) -> do_parse_octal(Rest, <>). parse_string(Bin) when is_binary(Bin) -> do_parse_string(Bin, <<>>). do_parse_string(<<>>, Acc) -> case unicode:characters_to_list(Acc) of Str when is_list(Str) -> Str; {incomplete, _Str, _Rest} -> binary:bin_to_list(Acc); {error, _Str, _Rest} -> throw({error, {bad_header, invalid_string}}) end; do_parse_string(<<0, _/binary>>, Acc) -> do_parse_string(<<>>, Acc); do_parse_string(<>, Acc) -> do_parse_string(Rest, <>). convert_header(Bin, #reader{pos=Pos}=Reader) when byte_size(Bin) =:= ?BLOCK_SIZE, (Pos rem ?BLOCK_SIZE) =:= 0 -> case get_format(Bin) of ?FORMAT_UNKNOWN -> throw({error, bad_header}); {ok, Format, V7} -> unpack_format(Format, V7, Bin, Reader); {error, Reason} -> throw({error, {bad_header, Reason}}) end; convert_header(Bin, #reader{pos=Pos}) when byte_size(Bin) =:= ?BLOCK_SIZE -> throw({error, misaligned_read, Pos}); convert_header(Bin, _Reader) when byte_size(Bin) =:= 0 -> eof; convert_header(_Bin, _Reader) -> throw({error, eof}). %% Creates a partially-populated header record based %% on the provided file_info record. If the file is %% a symlink, then `link` is used as the link target. %% If the file is a directory, a slash is appended to the name. fileinfo_to_header(Name, #file_info{}=Fi, Link) when is_list(Name) -> BaseHeader = #tar_header{name=Name, mtime=0, atime=0, ctime=0, mode=Fi#file_info.mode, typeflag=?TYPE_REGULAR}, do_fileinfo_to_header(BaseHeader, Fi, Link). do_fileinfo_to_header(Header, #file_info{size=Size,type=regular}, _Link) -> Header#tar_header{size=Size,typeflag=?TYPE_REGULAR}; do_fileinfo_to_header(#tar_header{name=Name}=Header, #file_info{type=directory}, _Link) -> Header#tar_header{name=Name++"/",typeflag=?TYPE_DIR}; do_fileinfo_to_header(Header, #file_info{type=symlink}, Link) -> Header#tar_header{typeflag=?TYPE_SYMLINK,linkname=Link}; do_fileinfo_to_header(Header, #file_info{type=device,mode=Mode}=Fi, _Link) when (Mode band ?S_IFMT) =:= ?S_IFCHR -> Header#tar_header{typeflag=?TYPE_CHAR, devmajor=Fi#file_info.major_device, devminor=Fi#file_info.minor_device}; do_fileinfo_to_header(Header, #file_info{type=device,mode=Mode}=Fi, _Link) when (Mode band ?S_IFMT) =:= ?S_IFBLK -> Header#tar_header{typeflag=?TYPE_BLOCK, devmajor=Fi#file_info.major_device, devminor=Fi#file_info.minor_device}; do_fileinfo_to_header(Header, #file_info{type=other,mode=Mode}, _Link) when (Mode band ?S_IFMT) =:= ?S_FIFO -> Header#tar_header{typeflag=?TYPE_FIFO}; do_fileinfo_to_header(Header, Fi, _Link) -> {error, {invalid_file_type, Header#tar_header.name, Fi}}. is_ascii(Str) when is_list(Str) -> not lists:any(fun (Char) -> Char >= 16#80 end, Str); is_ascii(Bin) when is_binary(Bin) -> is_ascii1(Bin). is_ascii1(<<>>) -> true; is_ascii1(<>) when C >= 16#80 -> false; is_ascii1(<<_, Rest/binary>>) -> is_ascii1(Rest). to_ascii(Str) when is_list(Str) -> case is_ascii(Str) of true -> unicode:characters_to_binary(Str); false -> Chars = lists:filter(fun (Char) -> Char < 16#80 end, Str), unicode:characters_to_binary(Chars) end; to_ascii(Bin) when is_binary(Bin) -> to_ascii(Bin, <<>>). to_ascii(<<>>, Acc) -> Acc; to_ascii(<>, Acc) when C < 16#80 -> to_ascii(Rest, <>); to_ascii(<<_, Rest/binary>>, Acc) -> to_ascii(Rest, Acc). is_header_only_type(?TYPE_SYMLINK) -> true; is_header_only_type(?TYPE_LINK) -> true; is_header_only_type(?TYPE_DIR) -> true; is_header_only_type(_) -> false. foldl_read(#reader{access=read}=Reader, Fun, Accu, #read_opts{}=Opts) when is_function(Fun,4) -> case foldl_read0(Reader, Fun, Accu, Opts) of {ok, Result, _Reader2} -> Result; {error, _} = Err -> Err end; foldl_read(#reader{access=Access}, _Fun, _Accu, _Opts) -> {error, {read_mode_expected, Access}}; foldl_read(TarName, Fun, Accu, #read_opts{}=Opts) when is_function(Fun,4) -> try open(TarName, [read|Opts#read_opts.open_mode]) of {ok, #reader{access=read}=Reader} -> try foldl_read(Reader, Fun, Accu, Opts) after _ = close(Reader) end; {error, _} = Err -> Err catch throw:Err -> Err end. foldl_read0(Reader, Fun, Accu, Opts) -> try foldl_read1(Fun, Accu, Reader, Opts, #{}) of {ok,_,_} = Ok -> Ok catch throw:{error, {Reason, Format, Args}} -> read_verbose(Opts, Format, Args), {error, Reason}; throw:Err -> Err end. foldl_read1(Fun, Accu0, Reader0, Opts, ExtraHeaders) -> {ok, Reader1} = skip_unread(Reader0), case get_header(Reader1) of eof -> Fun(eof, Reader1, Opts, Accu0); {Header, Reader2} -> case Header#tar_header.typeflag of ?TYPE_X_HEADER -> {ExtraHeaders2, Reader3} = parse_pax(Reader2), ExtraHeaders3 = maps:merge(ExtraHeaders, ExtraHeaders2), foldl_read1(Fun, Accu0, Reader3, Opts, ExtraHeaders3); ?TYPE_GNU_LONGNAME -> {RealName, Reader3} = get_real_name(Reader2), ExtraHeaders2 = maps:put(?PAX_PATH, parse_string(RealName), ExtraHeaders), foldl_read1(Fun, Accu0, Reader3, Opts, ExtraHeaders2); ?TYPE_GNU_LONGLINK -> {RealName, Reader3} = get_real_name(Reader2), ExtraHeaders2 = maps:put(?PAX_LINKPATH, parse_string(RealName), ExtraHeaders), foldl_read1(Fun, Accu0, Reader3, Opts, ExtraHeaders2); _ -> Header1 = merge_pax(Header, ExtraHeaders), {ok, NewAccu, Reader3} = Fun(Header1, Reader2, Opts, Accu0), foldl_read1(Fun, NewAccu, Reader3, Opts, #{}) end end. %% Applies all known PAX attributes to the current tar header -spec merge_pax(tar_header(), #{binary() => binary()}) -> tar_header(). merge_pax(Header, ExtraHeaders) when is_map(ExtraHeaders) -> do_merge_pax(Header, maps:to_list(ExtraHeaders)). do_merge_pax(Header, []) -> Header; do_merge_pax(Header, [{?PAX_PATH, Path}|Rest]) -> do_merge_pax(Header#tar_header{name=unicode:characters_to_list(Path)}, Rest); do_merge_pax(Header, [{?PAX_LINKPATH, LinkPath}|Rest]) -> do_merge_pax(Header#tar_header{linkname=unicode:characters_to_list(LinkPath)}, Rest); do_merge_pax(Header, [{?PAX_GNAME, Gname}|Rest]) -> do_merge_pax(Header#tar_header{gname=unicode:characters_to_list(Gname)}, Rest); do_merge_pax(Header, [{?PAX_UNAME, Uname}|Rest]) -> do_merge_pax(Header#tar_header{uname=unicode:characters_to_list(Uname)}, Rest); do_merge_pax(Header, [{?PAX_UID, Uid}|Rest]) -> Uid2 = binary_to_integer(Uid), do_merge_pax(Header#tar_header{uid=Uid2}, Rest); do_merge_pax(Header, [{?PAX_GID, Gid}|Rest]) -> Gid2 = binary_to_integer(Gid), do_merge_pax(Header#tar_header{gid=Gid2}, Rest); do_merge_pax(Header, [{?PAX_ATIME, Atime}|Rest]) -> Atime2 = parse_pax_time(Atime), do_merge_pax(Header#tar_header{atime=Atime2}, Rest); do_merge_pax(Header, [{?PAX_MTIME, Mtime}|Rest]) -> Mtime2 = parse_pax_time(Mtime), do_merge_pax(Header#tar_header{mtime=Mtime2}, Rest); do_merge_pax(Header, [{?PAX_CTIME, Ctime}|Rest]) -> Ctime2 = parse_pax_time(Ctime), do_merge_pax(Header#tar_header{ctime=Ctime2}, Rest); do_merge_pax(Header, [{?PAX_SIZE, Size}|Rest]) -> Size2 = binary_to_integer(Size), do_merge_pax(Header#tar_header{size=Size2}, Rest); do_merge_pax(Header, [{<>, _Value}|Rest]) -> do_merge_pax(Header, Rest); do_merge_pax(Header, [_Ignore|Rest]) -> do_merge_pax(Header, Rest). %% Returns the time since UNIX epoch as a datetime -spec parse_pax_time(binary()) -> tar_time(). parse_pax_time(Bin) when is_binary(Bin) -> TotalNano = case binary:split(Bin, [<<$.>>]) of [SecondsStr, NanoStr0] -> Seconds = binary_to_integer(SecondsStr), if byte_size(NanoStr0) < ?MAX_NANO_INT_SIZE -> %% right pad PaddingN = ?MAX_NANO_INT_SIZE-byte_size(NanoStr0), Padding = binary:copy(<<$0>>, PaddingN), NanoStr1 = <>, Nano = binary_to_integer(NanoStr1), (Seconds*?BILLION)+Nano; byte_size(NanoStr0) > ?MAX_NANO_INT_SIZE -> %% right truncate NanoStr1 = binary_part(NanoStr0, 0, ?MAX_NANO_INT_SIZE), Nano = binary_to_integer(NanoStr1), (Seconds*?BILLION)+Nano; true -> (Seconds*?BILLION)+binary_to_integer(NanoStr0) end; [SecondsStr] -> binary_to_integer(SecondsStr)*?BILLION end, %% truncate to microseconds Micro = TotalNano div 1000, Mega = Micro div 1000000000000, Secs = Micro div 1000000 - (Mega*1000000), Secs. %% Given a regular file reader, reads the whole file and %% parses all extended attributes it contains. parse_pax(#reg_file_reader{handle=Handle,num_bytes=0}) -> {#{}, Handle}; parse_pax(#reg_file_reader{handle=Handle0,num_bytes=NumBytes}) -> case do_read(Handle0, NumBytes) of {ok, Bytes, Handle1} -> do_parse_pax(Handle1, Bytes, #{}); {error, _} = Err -> throw(Err) end. do_parse_pax(Reader, <<>>, Headers) -> {Headers, Reader}; do_parse_pax(Reader, Bin, Headers) -> {Key, Value, Residual} = parse_pax_record(Bin), NewHeaders = maps:put(Key, Value, Headers), do_parse_pax(Reader, Residual, NewHeaders). %% Parse an extended attribute parse_pax_record(Bin) when is_binary(Bin) -> case binary:split(Bin, [<<$\n>>]) of [Record, Residual] -> case [X || X <- binary:split(Record, [<<$\s>>], [global]), X =/= <<>>] of [_Len, Record1] -> case [X || X <- binary:split(Record1, [<<$=>>], [global]), X =/= <<>>] of [AttrName, AttrValue] -> {AttrName, AttrValue, Residual}; _Other -> throw({error, malformed_pax_record}) end; _Other -> throw({error, malformed_pax_record}) end; _Other -> throw({error, malformed_pax_record}) end. get_real_name(#reg_file_reader{handle=Handle,num_bytes=0}) -> {"", Handle}; get_real_name(#reg_file_reader{handle=Handle0,num_bytes=NumBytes}) -> case do_read(Handle0, NumBytes) of {ok, RealName, Handle1} -> {RealName, Handle1}; {error, _} = Err -> throw(Err) end; get_real_name(#sparse_file_reader{num_bytes=NumBytes}=Reader0) -> case do_read(Reader0, NumBytes) of {ok, RealName, Reader1} -> {RealName, Reader1}; {error, _} = Err -> throw(Err) end. %% Skip the remaining bytes for the current file entry skip_file(#reg_file_reader{handle=Handle0,pos=Pos,size=Size}=Reader) -> Padding = skip_padding(Size), AbsPos = Handle0#reader.pos + (Size-Pos) + Padding, case do_position(Handle0, AbsPos) of {ok, _, Handle1} -> Reader#reg_file_reader{handle=Handle1,num_bytes=0,pos=Size}; Err -> throw(Err) end; skip_file(#sparse_file_reader{pos=Pos,size=Size}=Reader) -> case do_read(Reader, Size-Pos) of {ok, _, Reader2} -> Reader2; Err -> throw(Err) end. skip_padding(0) -> 0; skip_padding(Size) when (Size rem ?BLOCK_SIZE) =:= 0 -> 0; skip_padding(Size) when Size =< ?BLOCK_SIZE -> ?BLOCK_SIZE - Size; skip_padding(Size) -> ?BLOCK_SIZE - (Size rem ?BLOCK_SIZE). skip_unread(#reader{pos=Pos}=Reader0) when (Pos rem ?BLOCK_SIZE) > 0 -> Padding = skip_padding(Pos + ?BLOCK_SIZE), AbsPos = Pos + Padding, case do_position(Reader0, AbsPos) of {ok, _, Reader1} -> {ok, Reader1}; Err -> throw(Err) end; skip_unread(#reader{}=Reader) -> {ok, Reader}; skip_unread(#reg_file_reader{handle=Handle,num_bytes=0}) -> skip_unread(Handle); skip_unread(#reg_file_reader{}=Reader) -> #reg_file_reader{handle=Handle} = skip_file(Reader), {ok, Handle}; skip_unread(#sparse_file_reader{handle=Handle,num_bytes=0}) -> skip_unread(Handle); skip_unread(#sparse_file_reader{}=Reader) -> #sparse_file_reader{handle=Handle} = skip_file(Reader), {ok, Handle}. write_extracted_element(#tar_header{name=Name,typeflag=Type}, Bin, #read_opts{output=memory}=Opts) -> case typeflag(Type) of regular -> read_verbose(Opts, "x ~ts~n", [Name]), {ok, {Name, Bin}}; _ -> ok end; write_extracted_element(#tar_header{name=Name0}=Header, Bin, Opts) -> Name1 = make_safe_path(Name0, Opts), Created = case typeflag(Header#tar_header.typeflag) of regular -> create_regular(Name1, Name0, Bin, Opts); directory -> read_verbose(Opts, "x ~ts~n", [Name0]), create_extracted_dir(Name1, Opts); symlink -> read_verbose(Opts, "x ~ts~n", [Name0]), create_symlink(Name1, Header#tar_header.linkname, Opts); Device when Device =:= char orelse Device =:= block -> %% char/block devices will be created as empty files %% and then have their major/minor device set later create_regular(Name1, Name0, <<>>, Opts); fifo -> %% fifo devices will be created as empty files create_regular(Name1, Name0, <<>>, Opts); Other -> % Ignore. read_verbose(Opts, "x ~ts - unsupported type ~p~n", [Name0, Other]), not_written end, case Created of ok -> set_extracted_file_info(Name1, Header); not_written -> ok end. make_safe_path([$/|Path], Opts) -> make_safe_path(Path, Opts); make_safe_path(Path, #read_opts{cwd=Cwd}) -> case safe_relative_path_links(Path, Cwd) of unsafe -> throw({error,{Path,unsafe_path}}); SafePath -> filename:absname(SafePath, Cwd) end. safe_relative_path_links(Path, Cwd) -> case filename:pathtype(Path) of relative -> safe_relative_path_links(filename:split(Path), Cwd, [], ""); _ -> unsafe end. safe_relative_path_links([], _Cwd, _PrevLinks, Acc) -> Acc; safe_relative_path_links([Segment | Segments], Cwd, PrevLinks, Acc) -> AccSegment = join(Acc, Segment), case mix_hex_filename:safe_relative_path(AccSegment) of unsafe -> unsafe; SafeAccSegment -> case file:read_link(join(Cwd, SafeAccSegment)) of {ok, LinkPath} -> case lists:member(LinkPath, PrevLinks) of true -> unsafe; false -> case safe_relative_path_links(filename:split(LinkPath), Cwd, [LinkPath | PrevLinks], Acc) of unsafe -> unsafe; NewAcc -> safe_relative_path_links(Segments, Cwd, [], NewAcc) end end; {error, _} -> safe_relative_path_links(Segments, Cwd, PrevLinks, SafeAccSegment) end end. join([], Path) -> Path; join(Left, Right) -> filename:join(Left, Right). create_regular(Name, NameInArchive, Bin, Opts) -> case write_extracted_file(Name, Bin, Opts) of not_written -> read_verbose(Opts, "x ~ts - exists, not created~n", [NameInArchive]), not_written; Ok -> read_verbose(Opts, "x ~ts~n", [NameInArchive]), Ok end. create_extracted_dir(Name, _Opts) -> case file:make_dir(Name) of ok -> ok; {error,enotsup} -> not_written; {error,eexist} -> not_written; {error,enoent} -> make_dirs(Name, dir); {error,Reason} -> throw({error, Reason}) end. create_symlink(Name, Linkname, Opts) -> case file:make_symlink(Linkname, Name) of ok -> ok; {error,enoent} -> ok = make_dirs(Name, file), create_symlink(Name, Linkname, Opts); {error,eexist} -> not_written; {error,enotsup} -> read_verbose(Opts, "x ~ts - symbolic links not supported~n", [Name]), not_written; {error,Reason} -> throw({error, Reason}) end. write_extracted_file(Name, Bin, Opts) -> Write = case Opts#read_opts.keep_old_files of true -> case file:read_file_info(Name) of {ok, _} -> false; _ -> true end; false -> true end, case Write of true -> write_file(Name, Bin); false -> not_written end. write_file(Name, Bin) -> case file:write_file(Name, Bin) of ok -> ok; {error,enoent} -> case make_dirs(Name, file) of ok -> write_file(Name, Bin); {error,Reason} -> throw({error, Reason}) end; {error,Reason} -> throw({error, Reason}) end. set_extracted_file_info(_, #tar_header{typeflag = ?TYPE_SYMLINK}) -> ok; set_extracted_file_info(_, #tar_header{typeflag = ?TYPE_LINK}) -> ok; set_extracted_file_info(Name, #tar_header{typeflag = ?TYPE_CHAR}=Header) -> set_device_info(Name, Header); set_extracted_file_info(Name, #tar_header{typeflag = ?TYPE_BLOCK}=Header) -> set_device_info(Name, Header); set_extracted_file_info(Name, #tar_header{mtime=Mtime,mode=Mode}) -> Info = #file_info{mode=Mode, mtime=Mtime}, file:write_file_info(Name, Info, [{time, posix}]). set_device_info(Name, #tar_header{}=Header) -> Mtime = Header#tar_header.mtime, Mode = Header#tar_header.mode, Devmajor = Header#tar_header.devmajor, Devminor = Header#tar_header.devminor, Info = #file_info{ mode=Mode, mtime=Mtime, major_device=Devmajor, minor_device=Devminor }, file:write_file_info(Name, Info). %% Makes all directories leading up to the file. make_dirs(Name, file) -> filelib:ensure_dir(Name); make_dirs(Name, dir) -> filelib:ensure_dir(filename:join(Name,"*")). %% Prints the message on if the verbose option is given (for reading). read_verbose(#read_opts{verbose=true}, Format, Args) -> io:format(Format, Args); read_verbose(_, _, _) -> ok. %% Prints the message on if the verbose option is given. add_verbose(#add_opts{verbose=true}, Format, Args) -> io:format(Format, Args); add_verbose(_, _, _) -> ok. %%%%%%%%%%%%%%%%%% %% I/O primitives %%%%%%%%%%%%%%%%%% do_write(#reader{handle=Handle,func=Fun}=Reader0, Data) when is_function(Fun,2) -> case Fun(write,{Handle,Data}) of ok -> {ok, Pos, Reader1} = do_position(Reader0, {cur,0}), {ok, Reader1#reader{pos=Pos}}; {error, _} = Err -> Err end. do_copy(#reader{func=Fun}=Reader, Source, #add_opts{chunk_size=0}=Opts) when is_function(Fun, 2) -> do_copy(Reader, Source, Opts#add_opts{chunk_size=65536}); do_copy(#reader{func=Fun}=Reader, Source, #add_opts{chunk_size=ChunkSize}) when is_function(Fun, 2) -> case file:open(Source, [read, binary]) of {ok, SourceFd} -> case copy_chunked(Reader, SourceFd, ChunkSize, 0) of {ok, _Copied, _Reader2} = Ok-> _ = file:close(SourceFd), Ok; Err -> _ = file:close(SourceFd), throw(Err) end; Err -> throw(Err) end. copy_chunked(#reader{}=Reader, Source, ChunkSize, Copied) -> case file:read(Source, ChunkSize) of {ok, Bin} -> {ok, Reader2} = do_write(Reader, Bin), copy_chunked(Reader2, Source, ChunkSize, Copied+byte_size(Bin)); eof -> {ok, Copied, Reader}; Other -> Other end. do_position(#reader{handle=Handle,func=Fun}=Reader, Pos) when is_function(Fun,2)-> case Fun(position, {Handle,Pos}) of {ok, NewPos} -> %% since Pos may not always be an absolute seek, %% make sure we update the reader with the new absolute position {ok, AbsPos} = Fun(position, {Handle, {cur, 0}}), {ok, NewPos, Reader#reader{pos=AbsPos}}; Other -> Other end. do_read(#reg_file_reader{handle=Handle,pos=Pos,size=Size}=Reader, Len) -> NumBytes = Size - Pos, ActualLen = if NumBytes - Len < 0 -> NumBytes; true -> Len end, case do_read(Handle, ActualLen) of {ok, Bin, Handle2} -> NewPos = Pos + ActualLen, NumBytes2 = Size - NewPos, Reader1 = Reader#reg_file_reader{ handle=Handle2, pos=NewPos, num_bytes=NumBytes2}, {ok, Bin, Reader1}; Other -> Other end; do_read(#sparse_file_reader{}=Reader, Len) -> do_sparse_read(Reader, Len); do_read(#reader{pos=Pos,handle=Handle,func=Fun}=Reader, Len) when is_function(Fun,2)-> %% Always convert to binary internally case Fun(read2,{Handle,Len}) of {ok, List} when is_list(List) -> Bin = list_to_binary(List), NewPos = Pos+byte_size(Bin), {ok, Bin, Reader#reader{pos=NewPos}}; {ok, Bin} when is_binary(Bin) -> NewPos = Pos+byte_size(Bin), {ok, Bin, Reader#reader{pos=NewPos}}; Other -> Other end. do_sparse_read(Reader, Len) -> do_sparse_read(Reader, Len, <<>>). do_sparse_read(#sparse_file_reader{sparse_map=[#sparse_entry{num_bytes=0}|Entries] }=Reader0, Len, Acc) -> %% skip all empty fragments Reader1 = Reader0#sparse_file_reader{sparse_map=Entries}, do_sparse_read(Reader1, Len, Acc); do_sparse_read(#sparse_file_reader{sparse_map=[], pos=Pos,size=Size}=Reader0, Len, Acc) when Pos < Size -> %% if there are no more fragments, it is possible that there is one last sparse hole %% this behaviour matches the BSD tar utility %% however, GNU tar stops returning data even if we haven't reached the end {ok, Bin, Reader1} = read_sparse_hole(Reader0, Size, Len), do_sparse_read(Reader1, Len-byte_size(Bin), <>); do_sparse_read(#sparse_file_reader{sparse_map=[]}=Reader, _Len, Acc) -> {ok, Acc, Reader}; do_sparse_read(#sparse_file_reader{}=Reader, 0, Acc) -> {ok, Acc, Reader}; do_sparse_read(#sparse_file_reader{sparse_map=[#sparse_entry{offset=Offset}|_], pos=Pos}=Reader0, Len, Acc) when Pos < Offset -> {ok, Bin, Reader1} = read_sparse_hole(Reader0, Offset, Offset-Pos), do_sparse_read(Reader1, Len-byte_size(Bin), <>); do_sparse_read(#sparse_file_reader{sparse_map=[Entry|Entries], pos=Pos}=Reader0, Len, Acc) -> %% we're in a data fragment, so read from it %% end offset of fragment EndPos = Entry#sparse_entry.offset + Entry#sparse_entry.num_bytes, %% bytes left in fragment NumBytes = EndPos - Pos, ActualLen = if Len > NumBytes -> NumBytes; true -> Len end, case do_read(Reader0#sparse_file_reader.handle, ActualLen) of {ok, Bin, Handle} -> BytesRead = byte_size(Bin), ActualEndPos = Pos+BytesRead, Reader1 = if ActualEndPos =:= EndPos -> Reader0#sparse_file_reader{sparse_map=Entries}; true -> Reader0 end, Size = Reader1#sparse_file_reader.size, NumBytes2 = Size - ActualEndPos, Reader2 = Reader1#sparse_file_reader{ handle=Handle, pos=ActualEndPos, num_bytes=NumBytes2}, do_sparse_read(Reader2, Len-byte_size(Bin), <>); Other -> Other end. %% Reads a sparse hole ending at Offset read_sparse_hole(#sparse_file_reader{pos=Pos}=Reader, Offset, Len) -> N = Offset - Pos, N2 = if N > Len -> Len; true -> N end, Bin = <<0:N2/unit:8>>, NumBytes = Reader#sparse_file_reader.size - (Pos+N2), {ok, Bin, Reader#sparse_file_reader{ num_bytes=NumBytes, pos=Pos+N2}}. -spec do_close(reader()) -> ok | {error, term()}. do_close(#reader{handle=Handle,func=Fun}) when is_function(Fun,2) -> Fun(close,Handle). %%%%%%%%%%%%%%%%%% %% Option parsing %%%%%%%%%%%%%%%%%% extract_opts(List) -> extract_opts(List, default_options()). table_opts(List) -> read_opts(List, default_options()). default_options() -> {ok, Cwd} = file:get_cwd(), #read_opts{cwd=Cwd}. extract_opts([keep_old_files|Rest], Opts) -> extract_opts(Rest, Opts#read_opts{keep_old_files=true}); extract_opts([{cwd, Cwd}|Rest], Opts) -> extract_opts(Rest, Opts#read_opts{cwd=Cwd}); extract_opts([{files, Files}|Rest], Opts) -> Set = ordsets:from_list(Files), extract_opts(Rest, Opts#read_opts{files=Set}); extract_opts([memory|Rest], Opts) -> extract_opts(Rest, Opts#read_opts{output=memory}); extract_opts([compressed|Rest], Opts=#read_opts{open_mode=OpenMode}) -> extract_opts(Rest, Opts#read_opts{open_mode=[compressed|OpenMode]}); extract_opts([cooked|Rest], Opts=#read_opts{open_mode=OpenMode}) -> extract_opts(Rest, Opts#read_opts{open_mode=[cooked|OpenMode]}); extract_opts([verbose|Rest], Opts) -> extract_opts(Rest, Opts#read_opts{verbose=true}); extract_opts([Other|Rest], Opts) -> extract_opts(Rest, read_opts([Other], Opts)); extract_opts([], Opts) -> Opts. read_opts([compressed|Rest], Opts=#read_opts{open_mode=OpenMode}) -> read_opts(Rest, Opts#read_opts{open_mode=[compressed|OpenMode]}); read_opts([cooked|Rest], Opts=#read_opts{open_mode=OpenMode}) -> read_opts(Rest, Opts#read_opts{open_mode=[cooked|OpenMode]}); read_opts([verbose|Rest], Opts) -> read_opts(Rest, Opts#read_opts{verbose=true}); read_opts([_|Rest], Opts) -> read_opts(Rest, Opts); read_opts([], Opts) -> Opts. hex-2.0.6/src/mix_hex_erl_tar.hrl000066400000000000000000000372071437023760000167650ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually % Copied from https://github.com/erlang/otp/blob/OTP-20.0.1/lib/stdlib/src/erl_tar.hrl %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% Options used when adding files to a tar archive. -record(add_opts, { read_info, %% Fun to use for read file/link info. chunk_size = 0 :: integer(), %% For file reading when sending to sftp. 0=do not chunk verbose = false :: boolean(), %% Verbose on/off. atime = undefined :: undefined | integer(), mtime = undefined :: undefined | integer(), ctime = undefined :: undefined | integer(), uid = 0 :: integer(), gid = 0 :: integer()}). -type add_opts() :: #add_opts{}. %% Options used when reading a tar archive. -record(read_opts, { cwd :: string(), %% Current working directory. keep_old_files = false :: boolean(), %% Owerwrite or not. files = all, %% Set of files to extract (or all) output = file :: 'file' | 'memory', open_mode = [], %% Open mode options. verbose = false :: boolean()}). %% Verbose on/off. -type read_opts() :: #read_opts{}. -type add_opt() :: dereference | verbose | {chunks, pos_integer()} | {atime, integer()} | {mtime, integer()} | {ctime, integer()} | {uid, integer()} | {gid, integer()}. -type extract_opt() :: {cwd, string()} | {files, [string()]} | compressed | cooked | memory | keep_old_files | verbose. -type create_opt() :: compressed | cooked | dereference | verbose. -type filelist() :: [file:filename() | {string(), binary()} | {string(), file:filename()}]. -type tar_time() :: non_neg_integer(). %% The tar header, once fully parsed. -record(tar_header, { name = "" :: string(), %% name of header file entry mode = 8#100644 :: non_neg_integer(), %% permission and mode bits uid = 0 :: non_neg_integer(), %% user id of owner gid = 0 :: non_neg_integer(), %% group id of owner size = 0 :: non_neg_integer(), %% length in bytes mtime :: tar_time(), %% modified time typeflag :: char(), %% type of header entry linkname = "" :: string(), %% target name of link uname = "" :: string(), %% user name of owner gname = "" :: string(), %% group name of owner devmajor = 0 :: non_neg_integer(), %% major number of character or block device devminor = 0 :: non_neg_integer(), %% minor number of character or block device atime :: tar_time(), %% access time ctime :: tar_time() %% status change time }). -type tar_header() :: #tar_header{}. %% Metadata for a sparse file fragment -record(sparse_entry, { offset = 0 :: non_neg_integer(), num_bytes = 0 :: non_neg_integer()}). -type sparse_entry() :: #sparse_entry{}. %% Contains metadata about fragments of a sparse file -record(sparse_array, { entries = [] :: [sparse_entry()], is_extended = false :: boolean(), max_entries = 0 :: non_neg_integer()}). -type sparse_array() :: #sparse_array{}. %% A subset of tar header fields common to all tar implementations -record(header_v7, { name :: binary(), mode :: binary(), %% octal uid :: binary(), %% integer gid :: binary(), %% integer size :: binary(), %% integer mtime :: binary(), %% integer checksum :: binary(), %% integer typeflag :: byte(), %% char linkname :: binary()}). -type header_v7() :: #header_v7{}. %% The set of fields specific to GNU tar formatted archives -record(header_gnu, { header_v7 :: header_v7(), magic :: binary(), version :: binary(), uname :: binary(), gname :: binary(), devmajor :: binary(), %% integer devminor :: binary(), %% integer atime :: binary(), %% integer ctime :: binary(), %% integer sparse :: sparse_array(), real_size :: binary()}). %% integer -type header_gnu() :: #header_gnu{}. %% The set of fields specific to STAR-formatted archives -record(header_star, { header_v7 :: header_v7(), magic :: binary(), version :: binary(), uname :: binary(), gname :: binary(), devmajor :: binary(), %% integer devminor :: binary(), %% integer prefix :: binary(), atime :: binary(), %% integer ctime :: binary(), %% integer trailer :: binary()}). -type header_star() :: #header_star{}. %% The set of fields specific to USTAR-formatted archives -record(header_ustar, { header_v7 :: header_v7(), magic :: binary(), version :: binary(), uname :: binary(), gname :: binary(), devmajor :: binary(), %% integer devminor :: binary(), %% integer prefix :: binary()}). -type header_ustar() :: #header_ustar{}. -type header_fields() :: header_v7() | header_gnu() | header_star() | header_ustar(). %% The overall tar reader, it holds the low-level file handle, %% its access, position, and the I/O primitives wrapper. -record(reader, { handle :: file:io_device() | term(), access :: read | write | ram, pos = 0 :: non_neg_integer(), func :: file_op() }). -type reader() :: #reader{}. %% A reader for a regular file within the tar archive, %% It tracks its current state relative to that file. -record(reg_file_reader, { handle :: reader(), num_bytes = 0, pos = 0, size = 0 }). -type reg_file_reader() :: #reg_file_reader{}. %% A reader for a sparse file within the tar archive, %% It tracks its current state relative to that file. -record(sparse_file_reader, { handle :: reader(), num_bytes = 0, %% bytes remaining pos = 0, %% pos size = 0, %% total size of file sparse_map = #sparse_array{} }). -type sparse_file_reader() :: #sparse_file_reader{}. %% Types for the readers -type reader_type() :: reader() | reg_file_reader() | sparse_file_reader(). -type handle() :: file:io_device() | term(). %% Type for the I/O primitive wrapper function -type file_op() :: fun((write | close | read2 | position, {handle(), iodata()} | handle() | {handle(), non_neg_integer()} | {handle(), non_neg_integer()}) -> ok | eof | {ok, string() | binary()} | {ok, non_neg_integer()} | {error, term()}). %% These constants (except S_IFMT) are %% used to determine what type of device %% a file is. Namely, `S_IFMT band file_info.mode` %% will equal one of these contants, and tells us %% which type it is. The stdlib file_info record %% does not differentiate between device types, and %% will not allow us to differentiate between sockets %% and named pipes. These constants are pulled from libc. -define(S_IFMT, 61440). -define(S_IFSOCK, 49152). %% socket -define(S_FIFO, 4096). %% fifo/named pipe -define(S_IFBLK, 24576). %% block device -define(S_IFCHR, 8192). %% character device %% Typeflag constants for the tar header -define(TYPE_REGULAR, $0). %% regular file -define(TYPE_REGULAR_A, 0). %% regular file -define(TYPE_LINK, $1). %% hard link -define(TYPE_SYMLINK, $2). %% symbolic link -define(TYPE_CHAR, $3). %% character device node -define(TYPE_BLOCK, $4). %% block device node -define(TYPE_DIR, $5). %% directory -define(TYPE_FIFO, $6). %% fifo node -define(TYPE_CONT, $7). %% reserved -define(TYPE_X_HEADER, $x). %% extended header -define(TYPE_X_GLOBAL_HEADER, $g). %% global extended header -define(TYPE_GNU_LONGNAME, $L). %% next file has a long name -define(TYPE_GNU_LONGLINK, $K). %% next file symlinks to a file with a long name -define(TYPE_GNU_SPARSE, $S). %% sparse file %% Mode constants from tar spec -define(MODE_ISUID, 4000). %% set uid -define(MODE_ISGID, 2000). %% set gid -define(MODE_ISVTX, 1000). %% save text (sticky bit) -define(MODE_ISDIR, 40000). %% directory -define(MODE_ISFIFO, 10000). %% fifo -define(MODE_ISREG, 100000). %% regular file -define(MODE_ISLNK, 120000). %% symbolic link -define(MODE_ISBLK, 60000). %% block special file -define(MODE_ISCHR, 20000). %% character special file -define(MODE_ISSOCK, 140000). %% socket %% Keywords for PAX extended header -define(PAX_ATIME, <<"atime">>). -define(PAX_CHARSET, <<"charset">>). -define(PAX_COMMENT, <<"comment">>). -define(PAX_CTIME, <<"ctime">>). %% ctime is not a valid pax header -define(PAX_GID, <<"gid">>). -define(PAX_GNAME, <<"gname">>). -define(PAX_LINKPATH, <<"linkpath">>). -define(PAX_MTIME, <<"mtime">>). -define(PAX_PATH, <<"path">>). -define(PAX_SIZE, <<"size">>). -define(PAX_UID, <<"uid">>). -define(PAX_UNAME, <<"uname">>). -define(PAX_XATTR, <<"SCHILY.xattr.">>). -define(PAX_XATTR_STR, "SCHILY.xattr."). -define(PAX_NONE, <<"">>). %% Tar format constants %% Unknown format -define(FORMAT_UNKNOWN, 0). %% The format of the original Unix V7 tar tool prior to standardization -define(FORMAT_V7, 1). %% The old and new GNU formats, incompatible with USTAR. %% This covers the old GNU sparse extension, but it does %% not cover the GNU sparse extensions using PAX headers, %% versions 0.0, 0.1, and 1.0; these fall under the PAX format. -define(FORMAT_GNU, 2). %% Schily's tar format, which is incompatible with USTAR. %% This does not cover STAR extensions to the PAX format; these %% fall under the PAX format. -define(FORMAT_STAR, 3). %% USTAR is the former standardization of tar defined in POSIX.1-1988, %% it is incompatible with the GNU and STAR formats. -define(FORMAT_USTAR, 4). %% PAX is the latest standardization of tar defined in POSIX.1-2001. %% This is an extension of USTAR and is "backwards compatible" with it. %% %% Some newer formats add their own extensions to PAX, such as GNU sparse %% files and SCHILY extended attributes. Since they are backwards compatible %% with PAX, they will be labelled as "PAX". -define(FORMAT_PAX, 5). %% Magic constants -define(MAGIC_GNU, <<"ustar ">>). -define(VERSION_GNU, <<" \x00">>). -define(MAGIC_USTAR, <<"ustar\x00">>). -define(VERSION_USTAR, <<"00">>). -define(TRAILER_STAR, <<"tar\x00">>). %% Size constants -define(BLOCK_SIZE, 512). %% size of each block in a tar stream -define(NAME_SIZE, 100). %% max length of the name field in USTAR format -define(PREFIX_SIZE, 155). %% max length of the prefix field in USTAR format %% Maximum size of a nanosecond value as an integer -define(MAX_NANO_INT_SIZE, 9). %% Maximum size of a 64-bit signed integer -define(MAX_INT64, (1 bsl 63 - 1)). -define(PAX_GNU_SPARSE_NUMBLOCKS, <<"GNU.sparse.numblocks">>). -define(PAX_GNU_SPARSE_OFFSET, <<"GNU.sparse.offset">>). -define(PAX_GNU_SPARSE_NUMBYTES, <<"GNU.sparse.numbytes">>). -define(PAX_GNU_SPARSE_MAP, <<"GNU.sparse.map">>). -define(PAX_GNU_SPARSE_NAME, <<"GNU.sparse.name">>). -define(PAX_GNU_SPARSE_MAJOR, <<"GNU.sparse.major">>). -define(PAX_GNU_SPARSE_MINOR, <<"GNU.sparse.minor">>). -define(PAX_GNU_SPARSE_SIZE, <<"GNU.sparse.size">>). -define(PAX_GNU_SPARSE_REALSIZE, <<"GNU.sparse.realsize">>). -define(V7_NAME, 0). -define(V7_NAME_LEN, 100). -define(V7_MODE, 100). -define(V7_MODE_LEN, 8). -define(V7_UID, 108). -define(V7_UID_LEN, 8). -define(V7_GID, 116). -define(V7_GID_LEN, 8). -define(V7_SIZE, 124). -define(V7_SIZE_LEN, 12). -define(V7_MTIME, 136). -define(V7_MTIME_LEN, 12). -define(V7_CHKSUM, 148). -define(V7_CHKSUM_LEN, 8). -define(V7_TYPE, 156). -define(V7_TYPE_LEN, 1). -define(V7_LINKNAME, 157). -define(V7_LINKNAME_LEN, 100). -define(STAR_TRAILER, 508). -define(STAR_TRAILER_LEN, 4). -define(USTAR_MAGIC, 257). -define(USTAR_MAGIC_LEN, 6). -define(USTAR_VERSION, 263). -define(USTAR_VERSION_LEN, 2). -define(USTAR_UNAME, 265). -define(USTAR_UNAME_LEN, 32). -define(USTAR_GNAME, 297). -define(USTAR_GNAME_LEN, 32). -define(USTAR_DEVMAJ, 329). -define(USTAR_DEVMAJ_LEN, 8). -define(USTAR_DEVMIN, 337). -define(USTAR_DEVMIN_LEN, 8). -define(USTAR_PREFIX, 345). -define(USTAR_PREFIX_LEN, 155). -define(GNU_MAGIC, 257). -define(GNU_MAGIC_LEN, 6). -define(GNU_VERSION, 263). -define(GNU_VERSION_LEN, 2). %% ?BLOCK_SIZE of zero-bytes. %% Two of these in a row mark the end of an archive. -define(ZERO_BLOCK, <<0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0>>). -define(BILLION, 1000000000). -define(EPOCH, {{1970,1,1}, {0,0,0}}). hex-2.0.6/src/mix_hex_filename.erl000066400000000000000000000035171437023760000171070ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually % @private % Excerpt from https://github.com/erlang/otp/blob/OTP-20.0.1/lib/stdlib/src/filename.erl#L761-L788 % with modifications for changing local function calls to remote function calls % to the `filename` module, for the functions `pathtype/1`, `split/1`, and `join/1` % % safe_relative_path/1 was not present in earlier OTP releases. %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1997-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(mix_hex_filename). -export([safe_relative_path/1]). safe_relative_path(Path) -> case filename:pathtype(Path) of relative -> Cs0 = filename:split(Path), safe_relative_path_1(Cs0, []); _ -> unsafe end. safe_relative_path_1(["."|T], Acc) -> safe_relative_path_1(T, Acc); safe_relative_path_1([<<".">>|T], Acc) -> safe_relative_path_1(T, Acc); safe_relative_path_1([".."|T], Acc) -> climb(T, Acc); safe_relative_path_1([<<"..">>|T], Acc) -> climb(T, Acc); safe_relative_path_1([H|T], Acc) -> safe_relative_path_1(T, [H|Acc]); safe_relative_path_1([], []) -> []; safe_relative_path_1([], Acc) -> filename:join(lists:reverse(Acc)). climb(_, []) -> unsafe; climb(T, [_|Acc]) -> safe_relative_path_1(T, Acc). hex-2.0.6/src/mix_hex_http.erl000066400000000000000000000043561437023760000163100ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% @doc %% HTTP contract. -module(mix_hex_http). -export([request/5]). -ifdef(TEST). -export([user_agent/1]). -endif. -include_lib("mix_hex_core.hrl"). -type method() :: get | post | put | patch | delete. -type status() :: non_neg_integer(). -export_type([status/0]). -type headers() :: #{binary() => binary()}. -export_type([headers/0]). -type body() :: {ContentType :: binary(), Body :: binary()} | undefined. -type adapter_config() :: map(). -callback request(method(), URI :: binary(), headers(), body(), adapter_config()) -> {ok, status(), headers(), binary()} | {error, term()}. -spec request(mix_hex_core:config(), method(), URI :: binary(), headers(), body()) -> {ok, {status(), headers(), binary()}} | {error, term()}. request(Config, Method, URI, Headers, Body) when is_binary(URI) and is_map(Headers) -> {Adapter, AdapterConfig} = case maps:get(http_adapter, Config, {mix_hex_http_httpc, #{}}) of {Adapter0, AdapterConfig0} -> {Adapter0, AdapterConfig0}; %% TODO: remove in v0.9 Adapter0 when is_atom(Adapter0) -> AdapterConfig0 = maps:get(http_adapter_config, Config, #{}), io:format("[mix_hex_http] setting #{http_adapter => Module, http_adapter_config => Map} " "is deprecated in favour of #{http_adapter => {Module, Map}}~n"), {Adapter0, AdapterConfig0} end, UserAgentFragment = maps:get(http_user_agent_fragment, Config), Headers2 = put_new(<<"user-agent">>, user_agent(UserAgentFragment), Headers), Adapter:request(Method, URI, Headers2, Body, AdapterConfig). %% @private user_agent(UserAgentFragment) -> OTPRelease = erlang:system_info(otp_release), ERTSVersion = erlang:system_info(version), OTPString = " (OTP/" ++ OTPRelease ++ ") (erts/" ++ ERTSVersion ++ ")", iolist_to_binary(["hex_core/", ?HEX_CORE_VERSION, " ", UserAgentFragment, OTPString]). %%==================================================================== %% Internal functions %%==================================================================== %% @private put_new(Key, Value, Map) -> case maps:find(Key, Map) of {ok, _} -> Map; error -> maps:put(Key, Value, Map) end. hex-2.0.6/src/mix_hex_http_httpc.erl000066400000000000000000000046601437023760000175100ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% @doc %% httpc-based implementation of {@link mix_hex_http} contract. %% %% Configuration keys: %% %% * `profile' - the name of the profile, defaults to `default'. See %% {@link httpc:set_options/2} for more information on setting %% options on profiles. %% %% * `http_options' - a list of HTTP options, defaults to `[]'. See %% {@link httpc:request/5} for a list of available HTTP options. -module(mix_hex_http_httpc). -behaviour(mix_hex_http). -export([request/5]). %%==================================================================== %% API functions %%==================================================================== request(Method, URI, ReqHeaders, Body, AdapterConfig) when is_binary(URI) -> Profile = maps:get(profile, AdapterConfig, default), HTTPOptions = maps:get(http_options, AdapterConfig, []), HTTPS = case URI of <<"https", _/binary>> -> true; _ -> false end, SSLOpts = proplists:get_value(ssl, HTTPOptions), if HTTPS == true andalso SSLOpts == undefined -> io:format("[mix_hex_http_httpc] using default ssl options which are insecure.~n" "Configure your adapter with: " "{mix_hex_http_httpc, #{http_options => [{ssl, SslOpts}]}}~n"); true -> ok end, Request = build_request(URI, ReqHeaders, Body), case httpc:request(Method, Request, HTTPOptions, [{body_format, binary}], Profile) of {ok, {{_, StatusCode, _}, RespHeaders, RespBody}} -> RespHeaders2 = load_headers(RespHeaders), {ok, {StatusCode, RespHeaders2, RespBody}}; {error, Reason} -> {error, Reason} end. %%==================================================================== %% Internal functions %%==================================================================== %% @private build_request(URI, ReqHeaders, Body) -> build_request2(binary_to_list(URI), dump_headers(ReqHeaders), Body). %% @private build_request2(URI, ReqHeaders, undefined) -> {URI, ReqHeaders}; build_request2(URI, ReqHeaders, {ContentType, Body}) -> {URI, ReqHeaders, ContentType, Body}. %% @private dump_headers(Map) -> maps:fold(fun(K, V, Acc) -> [{binary_to_list(K), binary_to_list(V)} | Acc] end, [], Map). %% @private load_headers(List) -> lists:foldl(fun({K, V}, Acc) -> maps:put(list_to_binary(K), list_to_binary(V), Acc) end, #{}, List). hex-2.0.6/src/mix_hex_licenses.erl000066400000000000000000000363521437023760000171370ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% File generated by spdx.ex. Do not edit manually. -module(mix_hex_licenses). -export([valid/1]). valid(<<"0BSD">>) -> true; valid(<<"AAL">>) -> true; valid(<<"ADSL">>) -> true; valid(<<"AFL-1.1">>) -> true; valid(<<"AFL-1.2">>) -> true; valid(<<"AFL-2.0">>) -> true; valid(<<"AFL-2.1">>) -> true; valid(<<"AFL-3.0">>) -> true; valid(<<"AGPL-1.0">>) -> true; valid(<<"AGPL-1.0-only">>) -> true; valid(<<"AGPL-1.0-or-later">>) -> true; valid(<<"AGPL-3.0">>) -> true; valid(<<"AGPL-3.0-only">>) -> true; valid(<<"AGPL-3.0-or-later">>) -> true; valid(<<"AMDPLPA">>) -> true; valid(<<"AML">>) -> true; valid(<<"AMPAS">>) -> true; valid(<<"ANTLR-PD">>) -> true; valid(<<"ANTLR-PD-fallback">>) -> true; valid(<<"APAFML">>) -> true; valid(<<"APL-1.0">>) -> true; valid(<<"APSL-1.0">>) -> true; valid(<<"APSL-1.1">>) -> true; valid(<<"APSL-1.2">>) -> true; valid(<<"APSL-2.0">>) -> true; valid(<<"Abstyles">>) -> true; valid(<<"Adobe-2006">>) -> true; valid(<<"Adobe-Glyph">>) -> true; valid(<<"Afmparse">>) -> true; valid(<<"Aladdin">>) -> true; valid(<<"Apache-1.0">>) -> true; valid(<<"Apache-1.1">>) -> true; valid(<<"Apache-2.0">>) -> true; valid(<<"Artistic-1.0">>) -> true; valid(<<"Artistic-1.0-Perl">>) -> true; valid(<<"Artistic-1.0-cl8">>) -> true; valid(<<"Artistic-2.0">>) -> true; valid(<<"BSD-1-Clause">>) -> true; valid(<<"BSD-2-Clause">>) -> true; valid(<<"BSD-2-Clause-FreeBSD">>) -> true; valid(<<"BSD-2-Clause-NetBSD">>) -> true; valid(<<"BSD-2-Clause-Patent">>) -> true; valid(<<"BSD-2-Clause-Views">>) -> true; valid(<<"BSD-3-Clause">>) -> true; valid(<<"BSD-3-Clause-Attribution">>) -> true; valid(<<"BSD-3-Clause-Clear">>) -> true; valid(<<"BSD-3-Clause-LBNL">>) -> true; valid(<<"BSD-3-Clause-Modification">>) -> true; valid(<<"BSD-3-Clause-No-Military-License">>) -> true; valid(<<"BSD-3-Clause-No-Nuclear-License">>) -> true; valid(<<"BSD-3-Clause-No-Nuclear-License-2014">>) -> true; valid(<<"BSD-3-Clause-No-Nuclear-Warranty">>) -> true; valid(<<"BSD-3-Clause-Open-MPI">>) -> true; valid(<<"BSD-4-Clause">>) -> true; valid(<<"BSD-4-Clause-Shortened">>) -> true; valid(<<"BSD-4-Clause-UC">>) -> true; valid(<<"BSD-Protection">>) -> true; valid(<<"BSD-Source-Code">>) -> true; valid(<<"BSL-1.0">>) -> true; valid(<<"BUSL-1.1">>) -> true; valid(<<"Bahyph">>) -> true; valid(<<"Barr">>) -> true; valid(<<"Beerware">>) -> true; valid(<<"BitTorrent-1.0">>) -> true; valid(<<"BitTorrent-1.1">>) -> true; valid(<<"BlueOak-1.0.0">>) -> true; valid(<<"Borceux">>) -> true; valid(<<"C-UDA-1.0">>) -> true; valid(<<"CAL-1.0">>) -> true; valid(<<"CAL-1.0-Combined-Work-Exception">>) -> true; valid(<<"CATOSL-1.1">>) -> true; valid(<<"CC-BY-1.0">>) -> true; valid(<<"CC-BY-2.0">>) -> true; valid(<<"CC-BY-2.5">>) -> true; valid(<<"CC-BY-3.0">>) -> true; valid(<<"CC-BY-3.0-AT">>) -> true; valid(<<"CC-BY-3.0-US">>) -> true; valid(<<"CC-BY-4.0">>) -> true; valid(<<"CC-BY-NC-1.0">>) -> true; valid(<<"CC-BY-NC-2.0">>) -> true; valid(<<"CC-BY-NC-2.5">>) -> true; valid(<<"CC-BY-NC-3.0">>) -> true; valid(<<"CC-BY-NC-4.0">>) -> true; valid(<<"CC-BY-NC-ND-1.0">>) -> true; valid(<<"CC-BY-NC-ND-2.0">>) -> true; valid(<<"CC-BY-NC-ND-2.5">>) -> true; valid(<<"CC-BY-NC-ND-3.0">>) -> true; valid(<<"CC-BY-NC-ND-3.0-IGO">>) -> true; valid(<<"CC-BY-NC-ND-4.0">>) -> true; valid(<<"CC-BY-NC-SA-1.0">>) -> true; valid(<<"CC-BY-NC-SA-2.0">>) -> true; valid(<<"CC-BY-NC-SA-2.5">>) -> true; valid(<<"CC-BY-NC-SA-3.0">>) -> true; valid(<<"CC-BY-NC-SA-4.0">>) -> true; valid(<<"CC-BY-ND-1.0">>) -> true; valid(<<"CC-BY-ND-2.0">>) -> true; valid(<<"CC-BY-ND-2.5">>) -> true; valid(<<"CC-BY-ND-3.0">>) -> true; valid(<<"CC-BY-ND-4.0">>) -> true; valid(<<"CC-BY-SA-1.0">>) -> true; valid(<<"CC-BY-SA-2.0">>) -> true; valid(<<"CC-BY-SA-2.0-UK">>) -> true; valid(<<"CC-BY-SA-2.1-JP">>) -> true; valid(<<"CC-BY-SA-2.5">>) -> true; valid(<<"CC-BY-SA-3.0">>) -> true; valid(<<"CC-BY-SA-3.0-AT">>) -> true; valid(<<"CC-BY-SA-4.0">>) -> true; valid(<<"CC-PDDC">>) -> true; valid(<<"CC0-1.0">>) -> true; valid(<<"CDDL-1.0">>) -> true; valid(<<"CDDL-1.1">>) -> true; valid(<<"CDL-1.0">>) -> true; valid(<<"CDLA-Permissive-1.0">>) -> true; valid(<<"CDLA-Sharing-1.0">>) -> true; valid(<<"CECILL-1.0">>) -> true; valid(<<"CECILL-1.1">>) -> true; valid(<<"CECILL-2.0">>) -> true; valid(<<"CECILL-2.1">>) -> true; valid(<<"CECILL-B">>) -> true; valid(<<"CECILL-C">>) -> true; valid(<<"CERN-OHL-1.1">>) -> true; valid(<<"CERN-OHL-1.2">>) -> true; valid(<<"CERN-OHL-P-2.0">>) -> true; valid(<<"CERN-OHL-S-2.0">>) -> true; valid(<<"CERN-OHL-W-2.0">>) -> true; valid(<<"CNRI-Jython">>) -> true; valid(<<"CNRI-Python">>) -> true; valid(<<"CNRI-Python-GPL-Compatible">>) -> true; valid(<<"CPAL-1.0">>) -> true; valid(<<"CPL-1.0">>) -> true; valid(<<"CPOL-1.02">>) -> true; valid(<<"CUA-OPL-1.0">>) -> true; valid(<<"Caldera">>) -> true; valid(<<"ClArtistic">>) -> true; valid(<<"Condor-1.1">>) -> true; valid(<<"Crossword">>) -> true; valid(<<"CrystalStacker">>) -> true; valid(<<"Cube">>) -> true; valid(<<"D-FSL-1.0">>) -> true; valid(<<"DOC">>) -> true; valid(<<"DRL-1.0">>) -> true; valid(<<"DSDP">>) -> true; valid(<<"Dotseqn">>) -> true; valid(<<"ECL-1.0">>) -> true; valid(<<"ECL-2.0">>) -> true; valid(<<"EFL-1.0">>) -> true; valid(<<"EFL-2.0">>) -> true; valid(<<"EPICS">>) -> true; valid(<<"EPL-1.0">>) -> true; valid(<<"EPL-2.0">>) -> true; valid(<<"EUDatagrid">>) -> true; valid(<<"EUPL-1.0">>) -> true; valid(<<"EUPL-1.1">>) -> true; valid(<<"EUPL-1.2">>) -> true; valid(<<"Entessa">>) -> true; valid(<<"ErlPL-1.1">>) -> true; valid(<<"Eurosym">>) -> true; valid(<<"FSFAP">>) -> true; valid(<<"FSFUL">>) -> true; valid(<<"FSFULLR">>) -> true; valid(<<"FTL">>) -> true; valid(<<"Fair">>) -> true; valid(<<"Frameworx-1.0">>) -> true; valid(<<"FreeBSD-DOC">>) -> true; valid(<<"FreeImage">>) -> true; valid(<<"GD">>) -> true; valid(<<"GFDL-1.1">>) -> true; valid(<<"GFDL-1.1-invariants-only">>) -> true; valid(<<"GFDL-1.1-invariants-or-later">>) -> true; valid(<<"GFDL-1.1-no-invariants-only">>) -> true; valid(<<"GFDL-1.1-no-invariants-or-later">>) -> true; valid(<<"GFDL-1.1-only">>) -> true; valid(<<"GFDL-1.1-or-later">>) -> true; valid(<<"GFDL-1.2">>) -> true; valid(<<"GFDL-1.2-invariants-only">>) -> true; valid(<<"GFDL-1.2-invariants-or-later">>) -> true; valid(<<"GFDL-1.2-no-invariants-only">>) -> true; valid(<<"GFDL-1.2-no-invariants-or-later">>) -> true; valid(<<"GFDL-1.2-only">>) -> true; valid(<<"GFDL-1.2-or-later">>) -> true; valid(<<"GFDL-1.3">>) -> true; valid(<<"GFDL-1.3-invariants-only">>) -> true; valid(<<"GFDL-1.3-invariants-or-later">>) -> true; valid(<<"GFDL-1.3-no-invariants-only">>) -> true; valid(<<"GFDL-1.3-no-invariants-or-later">>) -> true; valid(<<"GFDL-1.3-only">>) -> true; valid(<<"GFDL-1.3-or-later">>) -> true; valid(<<"GL2PS">>) -> true; valid(<<"GLWTPL">>) -> true; valid(<<"GPL-1.0">>) -> true; valid(<<"GPL-1.0+">>) -> true; valid(<<"GPL-1.0-only">>) -> true; valid(<<"GPL-1.0-or-later">>) -> true; valid(<<"GPL-2.0">>) -> true; valid(<<"GPL-2.0+">>) -> true; valid(<<"GPL-2.0-only">>) -> true; valid(<<"GPL-2.0-or-later">>) -> true; valid(<<"GPL-2.0-with-GCC-exception">>) -> true; valid(<<"GPL-2.0-with-autoconf-exception">>) -> true; valid(<<"GPL-2.0-with-bison-exception">>) -> true; valid(<<"GPL-2.0-with-classpath-exception">>) -> true; valid(<<"GPL-2.0-with-font-exception">>) -> true; valid(<<"GPL-3.0">>) -> true; valid(<<"GPL-3.0+">>) -> true; valid(<<"GPL-3.0-only">>) -> true; valid(<<"GPL-3.0-or-later">>) -> true; valid(<<"GPL-3.0-with-GCC-exception">>) -> true; valid(<<"GPL-3.0-with-autoconf-exception">>) -> true; valid(<<"Giftware">>) -> true; valid(<<"Glide">>) -> true; valid(<<"Glulxe">>) -> true; valid(<<"HPND">>) -> true; valid(<<"HPND-sell-variant">>) -> true; valid(<<"HTMLTIDY">>) -> true; valid(<<"HaskellReport">>) -> true; valid(<<"Hippocratic-2.1">>) -> true; valid(<<"IBM-pibs">>) -> true; valid(<<"ICU">>) -> true; valid(<<"IJG">>) -> true; valid(<<"IPA">>) -> true; valid(<<"IPL-1.0">>) -> true; valid(<<"ISC">>) -> true; valid(<<"ImageMagick">>) -> true; valid(<<"Imlib2">>) -> true; valid(<<"Info-ZIP">>) -> true; valid(<<"Intel">>) -> true; valid(<<"Intel-ACPI">>) -> true; valid(<<"Interbase-1.0">>) -> true; valid(<<"JPNIC">>) -> true; valid(<<"JSON">>) -> true; valid(<<"JasPer-2.0">>) -> true; valid(<<"LAL-1.2">>) -> true; valid(<<"LAL-1.3">>) -> true; valid(<<"LGPL-2.0">>) -> true; valid(<<"LGPL-2.0+">>) -> true; valid(<<"LGPL-2.0-only">>) -> true; valid(<<"LGPL-2.0-or-later">>) -> true; valid(<<"LGPL-2.1">>) -> true; valid(<<"LGPL-2.1+">>) -> true; valid(<<"LGPL-2.1-only">>) -> true; valid(<<"LGPL-2.1-or-later">>) -> true; valid(<<"LGPL-3.0">>) -> true; valid(<<"LGPL-3.0+">>) -> true; valid(<<"LGPL-3.0-only">>) -> true; valid(<<"LGPL-3.0-or-later">>) -> true; valid(<<"LGPLLR">>) -> true; valid(<<"LPL-1.0">>) -> true; valid(<<"LPL-1.02">>) -> true; valid(<<"LPPL-1.0">>) -> true; valid(<<"LPPL-1.1">>) -> true; valid(<<"LPPL-1.2">>) -> true; valid(<<"LPPL-1.3a">>) -> true; valid(<<"LPPL-1.3c">>) -> true; valid(<<"Latex2e">>) -> true; valid(<<"Leptonica">>) -> true; valid(<<"LiLiQ-P-1.1">>) -> true; valid(<<"LiLiQ-R-1.1">>) -> true; valid(<<"LiLiQ-Rplus-1.1">>) -> true; valid(<<"Libpng">>) -> true; valid(<<"Linux-OpenIB">>) -> true; valid(<<"MIT">>) -> true; valid(<<"MIT-0">>) -> true; valid(<<"MIT-CMU">>) -> true; valid(<<"MIT-Modern-Variant">>) -> true; valid(<<"MIT-advertising">>) -> true; valid(<<"MIT-enna">>) -> true; valid(<<"MIT-feh">>) -> true; valid(<<"MIT-open-group">>) -> true; valid(<<"MITNFA">>) -> true; valid(<<"MPL-1.0">>) -> true; valid(<<"MPL-1.1">>) -> true; valid(<<"MPL-2.0">>) -> true; valid(<<"MPL-2.0-no-copyleft-exception">>) -> true; valid(<<"MS-PL">>) -> true; valid(<<"MS-RL">>) -> true; valid(<<"MTLL">>) -> true; valid(<<"MakeIndex">>) -> true; valid(<<"MirOS">>) -> true; valid(<<"Motosoto">>) -> true; valid(<<"MulanPSL-1.0">>) -> true; valid(<<"MulanPSL-2.0">>) -> true; valid(<<"Multics">>) -> true; valid(<<"Mup">>) -> true; valid(<<"NAIST-2003">>) -> true; valid(<<"NASA-1.3">>) -> true; valid(<<"NBPL-1.0">>) -> true; valid(<<"NCGL-UK-2.0">>) -> true; valid(<<"NCSA">>) -> true; valid(<<"NGPL">>) -> true; valid(<<"NIST-PD">>) -> true; valid(<<"NIST-PD-fallback">>) -> true; valid(<<"NLOD-1.0">>) -> true; valid(<<"NLPL">>) -> true; valid(<<"NOSL">>) -> true; valid(<<"NPL-1.0">>) -> true; valid(<<"NPL-1.1">>) -> true; valid(<<"NPOSL-3.0">>) -> true; valid(<<"NRL">>) -> true; valid(<<"NTP">>) -> true; valid(<<"NTP-0">>) -> true; valid(<<"Naumen">>) -> true; valid(<<"Net-SNMP">>) -> true; valid(<<"NetCDF">>) -> true; valid(<<"Newsletr">>) -> true; valid(<<"Nokia">>) -> true; valid(<<"Noweb">>) -> true; valid(<<"Nunit">>) -> true; valid(<<"O-UDA-1.0">>) -> true; valid(<<"OCCT-PL">>) -> true; valid(<<"OCLC-2.0">>) -> true; valid(<<"ODC-By-1.0">>) -> true; valid(<<"ODbL-1.0">>) -> true; valid(<<"OFL-1.0">>) -> true; valid(<<"OFL-1.0-RFN">>) -> true; valid(<<"OFL-1.0-no-RFN">>) -> true; valid(<<"OFL-1.1">>) -> true; valid(<<"OFL-1.1-RFN">>) -> true; valid(<<"OFL-1.1-no-RFN">>) -> true; valid(<<"OGC-1.0">>) -> true; valid(<<"OGDL-Taiwan-1.0">>) -> true; valid(<<"OGL-Canada-2.0">>) -> true; valid(<<"OGL-UK-1.0">>) -> true; valid(<<"OGL-UK-2.0">>) -> true; valid(<<"OGL-UK-3.0">>) -> true; valid(<<"OGTSL">>) -> true; valid(<<"OLDAP-1.1">>) -> true; valid(<<"OLDAP-1.2">>) -> true; valid(<<"OLDAP-1.3">>) -> true; valid(<<"OLDAP-1.4">>) -> true; valid(<<"OLDAP-2.0">>) -> true; valid(<<"OLDAP-2.0.1">>) -> true; valid(<<"OLDAP-2.1">>) -> true; valid(<<"OLDAP-2.2">>) -> true; valid(<<"OLDAP-2.2.1">>) -> true; valid(<<"OLDAP-2.2.2">>) -> true; valid(<<"OLDAP-2.3">>) -> true; valid(<<"OLDAP-2.4">>) -> true; valid(<<"OLDAP-2.5">>) -> true; valid(<<"OLDAP-2.6">>) -> true; valid(<<"OLDAP-2.7">>) -> true; valid(<<"OLDAP-2.8">>) -> true; valid(<<"OML">>) -> true; valid(<<"OPL-1.0">>) -> true; valid(<<"OSET-PL-2.1">>) -> true; valid(<<"OSL-1.0">>) -> true; valid(<<"OSL-1.1">>) -> true; valid(<<"OSL-2.0">>) -> true; valid(<<"OSL-2.1">>) -> true; valid(<<"OSL-3.0">>) -> true; valid(<<"OpenSSL">>) -> true; valid(<<"PDDL-1.0">>) -> true; valid(<<"PHP-3.0">>) -> true; valid(<<"PHP-3.01">>) -> true; valid(<<"PSF-2.0">>) -> true; valid(<<"Parity-6.0.0">>) -> true; valid(<<"Parity-7.0.0">>) -> true; valid(<<"Plexus">>) -> true; valid(<<"PolyForm-Noncommercial-1.0.0">>) -> true; valid(<<"PolyForm-Small-Business-1.0.0">>) -> true; valid(<<"PostgreSQL">>) -> true; valid(<<"Python-2.0">>) -> true; valid(<<"QPL-1.0">>) -> true; valid(<<"Qhull">>) -> true; valid(<<"RHeCos-1.1">>) -> true; valid(<<"RPL-1.1">>) -> true; valid(<<"RPL-1.5">>) -> true; valid(<<"RPSL-1.0">>) -> true; valid(<<"RSA-MD">>) -> true; valid(<<"RSCPL">>) -> true; valid(<<"Rdisc">>) -> true; valid(<<"Ruby">>) -> true; valid(<<"SAX-PD">>) -> true; valid(<<"SCEA">>) -> true; valid(<<"SGI-B-1.0">>) -> true; valid(<<"SGI-B-1.1">>) -> true; valid(<<"SGI-B-2.0">>) -> true; valid(<<"SHL-0.5">>) -> true; valid(<<"SHL-0.51">>) -> true; valid(<<"SISSL">>) -> true; valid(<<"SISSL-1.2">>) -> true; valid(<<"SMLNJ">>) -> true; valid(<<"SMPPL">>) -> true; valid(<<"SNIA">>) -> true; valid(<<"SPL-1.0">>) -> true; valid(<<"SSH-OpenSSH">>) -> true; valid(<<"SSH-short">>) -> true; valid(<<"SSPL-1.0">>) -> true; valid(<<"SWL">>) -> true; valid(<<"Saxpath">>) -> true; valid(<<"Sendmail">>) -> true; valid(<<"Sendmail-8.23">>) -> true; valid(<<"SimPL-2.0">>) -> true; valid(<<"Sleepycat">>) -> true; valid(<<"Spencer-86">>) -> true; valid(<<"Spencer-94">>) -> true; valid(<<"Spencer-99">>) -> true; valid(<<"StandardML-NJ">>) -> true; valid(<<"SugarCRM-1.1.3">>) -> true; valid(<<"TAPR-OHL-1.0">>) -> true; valid(<<"TCL">>) -> true; valid(<<"TCP-wrappers">>) -> true; valid(<<"TMate">>) -> true; valid(<<"TORQUE-1.1">>) -> true; valid(<<"TOSL">>) -> true; valid(<<"TU-Berlin-1.0">>) -> true; valid(<<"TU-Berlin-2.0">>) -> true; valid(<<"UCL-1.0">>) -> true; valid(<<"UPL-1.0">>) -> true; valid(<<"Unicode-DFS-2015">>) -> true; valid(<<"Unicode-DFS-2016">>) -> true; valid(<<"Unicode-TOU">>) -> true; valid(<<"Unlicense">>) -> true; valid(<<"VOSTROM">>) -> true; valid(<<"VSL-1.0">>) -> true; valid(<<"Vim">>) -> true; valid(<<"W3C">>) -> true; valid(<<"W3C-19980720">>) -> true; valid(<<"W3C-20150513">>) -> true; valid(<<"WTFPL">>) -> true; valid(<<"Watcom-1.0">>) -> true; valid(<<"Wsuipa">>) -> true; valid(<<"X11">>) -> true; valid(<<"XFree86-1.1">>) -> true; valid(<<"XSkat">>) -> true; valid(<<"Xerox">>) -> true; valid(<<"Xnet">>) -> true; valid(<<"YPL-1.0">>) -> true; valid(<<"YPL-1.1">>) -> true; valid(<<"ZPL-1.1">>) -> true; valid(<<"ZPL-2.0">>) -> true; valid(<<"ZPL-2.1">>) -> true; valid(<<"Zed">>) -> true; valid(<<"Zend-2.0">>) -> true; valid(<<"Zimbra-1.3">>) -> true; valid(<<"Zimbra-1.4">>) -> true; valid(<<"Zlib">>) -> true; valid(<<"blessing">>) -> true; valid(<<"bzip2-1.0.5">>) -> true; valid(<<"bzip2-1.0.6">>) -> true; valid(<<"copyleft-next-0.3.0">>) -> true; valid(<<"copyleft-next-0.3.1">>) -> true; valid(<<"curl">>) -> true; valid(<<"diffmark">>) -> true; valid(<<"dvipdfm">>) -> true; valid(<<"eCos-2.0">>) -> true; valid(<<"eGenix">>) -> true; valid(<<"etalab-2.0">>) -> true; valid(<<"gSOAP-1.3b">>) -> true; valid(<<"gnuplot">>) -> true; valid(<<"iMatix">>) -> true; valid(<<"libpng-2.0">>) -> true; valid(<<"libselinux-1.0">>) -> true; valid(<<"libtiff">>) -> true; valid(<<"mpich2">>) -> true; valid(<<"psfrag">>) -> true; valid(<<"psutils">>) -> true; valid(<<"wxWindows">>) -> true; valid(<<"xinetd">>) -> true; valid(<<"xpp">>) -> true; valid(<<"zlib-acknowledgement">>) -> true; valid(_) -> false. hex-2.0.6/src/mix_hex_pb_names.erl000066400000000000000000001127421437023760000171140ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% -*- coding: utf-8 -*- %% @private %% Automatically generated, do not edit %% Generated by gpb_compile version 4.17.6 %% Version source: file -module(mix_hex_pb_names). -export([encode_msg/2, encode_msg/3]). -export([decode_msg/2, decode_msg/3]). -export([merge_msgs/3, merge_msgs/4]). -export([verify_msg/2, verify_msg/3]). -export([get_msg_defs/0]). -export([get_msg_names/0]). -export([get_group_names/0]). -export([get_msg_or_group_names/0]). -export([get_enum_names/0]). -export([find_msg_def/1, fetch_msg_def/1]). -export([find_enum_def/1, fetch_enum_def/1]). -export([enum_symbol_by_value/2, enum_value_by_symbol/2]). -export([get_service_names/0]). -export([get_service_def/1]). -export([get_rpc_names/1]). -export([find_rpc_def/2, fetch_rpc_def/2]). -export([fqbin_to_service_name/1]). -export([service_name_to_fqbin/1]). -export([fqbins_to_service_and_rpc_name/2]). -export([service_and_rpc_name_to_fqbins/2]). -export([fqbin_to_msg_name/1]). -export([msg_name_to_fqbin/1]). -export([fqbin_to_enum_name/1]). -export([enum_name_to_fqbin/1]). -export([get_package_name/0]). -export([uses_packages/0]). -export([source_basename/0]). -export([get_all_source_basenames/0]). -export([get_all_proto_names/0]). -export([get_msg_containment/1]). -export([get_pkg_containment/1]). -export([get_service_containment/1]). -export([get_rpc_containment/1]). -export([get_enum_containment/1]). -export([get_proto_by_msg_name_as_fqbin/1]). -export([get_proto_by_service_name_as_fqbin/1]). -export([get_proto_by_enum_name_as_fqbin/1]). -export([get_protos_by_pkg_name_as_fqbin/1]). -export([gpb_version_as_string/0, gpb_version_as_list/0]). -export([gpb_version_source/0]). %% enumerated types -export_type([]). %% message types -type 'Names'() :: #{packages => ['Package'()], % = 1, repeated repository => unicode:chardata() % = 2, required }. -type 'Package'() :: #{name => unicode:chardata(), % = 1, required updated_at => 'Timestamp'() % = 3, optional }. -type 'Timestamp'() :: #{seconds => integer(), % = 1, required, 64 bits nanos => integer() % = 2, required, 32 bits }. -export_type(['Names'/0, 'Package'/0, 'Timestamp'/0]). -type '$msg_name'() :: 'Names' | 'Package' | 'Timestamp'. -type '$msg'() :: 'Names'() | 'Package'() | 'Timestamp'(). -export_type(['$msg_name'/0, '$msg'/0]). -spec encode_msg('$msg'(), '$msg_name'()) -> binary(). encode_msg(Msg, MsgName) when is_atom(MsgName) -> encode_msg(Msg, MsgName, []). -spec encode_msg('$msg'(), '$msg_name'(), list()) -> binary(). encode_msg(Msg, MsgName, Opts) -> verify_msg(Msg, MsgName, Opts), TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Names' -> encode_msg_Names(id(Msg, TrUserData), TrUserData); 'Package' -> encode_msg_Package(id(Msg, TrUserData), TrUserData); 'Timestamp' -> encode_msg_Timestamp(id(Msg, TrUserData), TrUserData) end. encode_msg_Names(Msg, TrUserData) -> encode_msg_Names(Msg, <<>>, TrUserData). encode_msg_Names(#{repository := F2} = M, Bin, TrUserData) -> B1 = case M of #{packages := F1} -> TrF1 = id(F1, TrUserData), if TrF1 == [] -> Bin; true -> e_field_Names_packages(TrF1, Bin, TrUserData) end; _ -> Bin end, begin TrF2 = id(F2, TrUserData), e_type_string(TrF2, <>, TrUserData) end. encode_msg_Package(Msg, TrUserData) -> encode_msg_Package(Msg, <<>>, TrUserData). encode_msg_Package(#{name := F1} = M, Bin, TrUserData) -> B1 = begin TrF1 = id(F1, TrUserData), e_type_string(TrF1, <>, TrUserData) end, case M of #{updated_at := F2} -> begin TrF2 = id(F2, TrUserData), e_mfield_Package_updated_at(TrF2, <>, TrUserData) end; _ -> B1 end. encode_msg_Timestamp(Msg, TrUserData) -> encode_msg_Timestamp(Msg, <<>>, TrUserData). encode_msg_Timestamp(#{seconds := F1, nanos := F2}, Bin, TrUserData) -> B1 = begin TrF1 = id(F1, TrUserData), e_type_int64(TrF1, <>, TrUserData) end, begin TrF2 = id(F2, TrUserData), e_type_int32(TrF2, <>, TrUserData) end. e_mfield_Names_packages(Msg, Bin, TrUserData) -> SubBin = encode_msg_Package(Msg, <<>>, TrUserData), Bin2 = e_varint(byte_size(SubBin), Bin), <>. e_field_Names_packages([Elem | Rest], Bin, TrUserData) -> Bin2 = <>, Bin3 = e_mfield_Names_packages(id(Elem, TrUserData), Bin2, TrUserData), e_field_Names_packages(Rest, Bin3, TrUserData); e_field_Names_packages([], Bin, _TrUserData) -> Bin. e_mfield_Package_updated_at(Msg, Bin, TrUserData) -> SubBin = encode_msg_Timestamp(Msg, <<>>, TrUserData), Bin2 = e_varint(byte_size(SubBin), Bin), <>. -compile({nowarn_unused_function,e_type_sint/3}). e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> e_varint(Value * 2, Bin); e_type_sint(Value, Bin, _TrUserData) -> e_varint(Value * -2 - 1, Bin). -compile({nowarn_unused_function,e_type_int32/3}). e_type_int32(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; e_type_int32(Value, Bin, _TrUserData) -> <> = <>, e_varint(N, Bin). -compile({nowarn_unused_function,e_type_int64/3}). e_type_int64(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; e_type_int64(Value, Bin, _TrUserData) -> <> = <>, e_varint(N, Bin). -compile({nowarn_unused_function,e_type_bool/3}). e_type_bool(true, Bin, _TrUserData) -> <>; e_type_bool(false, Bin, _TrUserData) -> <>; e_type_bool(1, Bin, _TrUserData) -> <>; e_type_bool(0, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_string/3}). e_type_string(S, Bin, _TrUserData) -> Utf8 = unicode:characters_to_binary(S), Bin2 = e_varint(byte_size(Utf8), Bin), <>. -compile({nowarn_unused_function,e_type_bytes/3}). e_type_bytes(Bytes, Bin, _TrUserData) when is_binary(Bytes) -> Bin2 = e_varint(byte_size(Bytes), Bin), <>; e_type_bytes(Bytes, Bin, _TrUserData) when is_list(Bytes) -> BytesBin = iolist_to_binary(Bytes), Bin2 = e_varint(byte_size(BytesBin), Bin), <>. -compile({nowarn_unused_function,e_type_fixed32/3}). e_type_fixed32(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_sfixed32/3}). e_type_sfixed32(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_fixed64/3}). e_type_fixed64(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_sfixed64/3}). e_type_sfixed64(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_float/3}). e_type_float(V, Bin, _) when is_number(V) -> <>; e_type_float(infinity, Bin, _) -> <>; e_type_float('-infinity', Bin, _) -> <>; e_type_float(nan, Bin, _) -> <>. -compile({nowarn_unused_function,e_type_double/3}). e_type_double(V, Bin, _) when is_number(V) -> <>; e_type_double(infinity, Bin, _) -> <>; e_type_double('-infinity', Bin, _) -> <>; e_type_double(nan, Bin, _) -> <>. -compile({nowarn_unused_function,e_unknown_elems/2}). e_unknown_elems([Elem | Rest], Bin) -> BinR = case Elem of {varint, FNum, N} -> BinF = e_varint(FNum bsl 3, Bin), e_varint(N, BinF); {length_delimited, FNum, Data} -> BinF = e_varint(FNum bsl 3 bor 2, Bin), BinL = e_varint(byte_size(Data), BinF), <>; {group, FNum, GroupFields} -> Bin1 = e_varint(FNum bsl 3 bor 3, Bin), Bin2 = e_unknown_elems(GroupFields, Bin1), e_varint(FNum bsl 3 bor 4, Bin2); {fixed32, FNum, V} -> BinF = e_varint(FNum bsl 3 bor 5, Bin), <>; {fixed64, FNum, V} -> BinF = e_varint(FNum bsl 3 bor 1, Bin), <> end, e_unknown_elems(Rest, BinR); e_unknown_elems([], Bin) -> Bin. -compile({nowarn_unused_function,e_varint/3}). e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin). -compile({nowarn_unused_function,e_varint/2}). e_varint(N, Bin) when N =< 127 -> <>; e_varint(N, Bin) -> Bin2 = <>, e_varint(N bsr 7, Bin2). decode_msg(Bin, MsgName) when is_binary(Bin) -> decode_msg(Bin, MsgName, []). decode_msg(Bin, MsgName, Opts) when is_binary(Bin) -> TrUserData = proplists:get_value(user_data, Opts), decode_msg_1_catch(Bin, MsgName, TrUserData). -ifdef('OTP_RELEASE'). decode_msg_1_catch(Bin, MsgName, TrUserData) -> try decode_msg_2_doit(MsgName, Bin, TrUserData) catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) end. -else. decode_msg_1_catch(Bin, MsgName, TrUserData) -> try decode_msg_2_doit(MsgName, Bin, TrUserData) catch Class:Reason -> StackTrace = erlang:get_stacktrace(), error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) end. -endif. decode_msg_2_doit('Names', Bin, TrUserData) -> id(decode_msg_Names(Bin, TrUserData), TrUserData); decode_msg_2_doit('Package', Bin, TrUserData) -> id(decode_msg_Package(Bin, TrUserData), TrUserData); decode_msg_2_doit('Timestamp', Bin, TrUserData) -> id(decode_msg_Timestamp(Bin, TrUserData), TrUserData). decode_msg_Names(Bin, TrUserData) -> dfp_read_field_def_Names(Bin, 0, 0, 0, id([], TrUserData), id('$undef', TrUserData), TrUserData). dfp_read_field_def_Names(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Names_packages(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Names(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Names_repository(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Names(<<>>, 0, 0, _, R1, F@_2, TrUserData) -> S1 = #{repository => F@_2}, if R1 == '$undef' -> S1; true -> S1#{packages => lists_reverse(R1, TrUserData)} end; dfp_read_field_def_Names(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_Names(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). dg_read_field_def_Names(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_Names(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); dg_read_field_def_Names(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> Key = X bsl N + Acc, case Key of 10 -> d_field_Names_packages(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); 18 -> d_field_Names_repository(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_Names(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 1 -> skip_64_Names(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 2 -> skip_length_delimited_Names(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 3 -> skip_group_Names(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 5 -> skip_32_Names(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) end end; dg_read_field_def_Names(<<>>, 0, 0, _, R1, F@_2, TrUserData) -> S1 = #{repository => F@_2}, if R1 == '$undef' -> S1; true -> S1#{packages => lists_reverse(R1, TrUserData)} end. d_field_Names_packages(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Names_packages(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Names_packages(<<0:1, X:7, Rest/binary>>, N, Acc, F, Prev, F@_2, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_Package(Bs, TrUserData), TrUserData), Rest2} end, dfp_read_field_def_Names(RestF, 0, 0, F, cons(NewFValue, Prev, TrUserData), F@_2, TrUserData). d_field_Names_repository(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Names_repository(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Names_repository(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Names(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). skip_varint_Names(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_Names(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); skip_varint_Names(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Names(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_length_delimited_Names(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_Names(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); skip_length_delimited_Names(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_Names(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). skip_group_Names(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_Names(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). skip_32_Names(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Names(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_64_Names(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Names(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). decode_msg_Package(Bin, TrUserData) -> dfp_read_field_def_Package(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), TrUserData). dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Package_name(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Package(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Package_updated_at(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Package(<<>>, 0, 0, _, F@_1, F@_2, _) -> S1 = #{name => F@_1}, if F@_2 == '$undef' -> S1; true -> S1#{updated_at => F@_2} end; dfp_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> Key = X bsl N + Acc, case Key of 10 -> d_field_Package_name(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); 26 -> d_field_Package_updated_at(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 1 -> skip_64_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 2 -> skip_length_delimited_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 3 -> skip_group_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 5 -> skip_32_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) end end; dg_read_field_def_Package(<<>>, 0, 0, _, F@_1, F@_2, _) -> S1 = #{name => F@_1}, if F@_2 == '$undef' -> S1; true -> S1#{updated_at => F@_2} end. d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Package_name(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Package(RestF, 0, 0, F, NewFValue, F@_2, TrUserData). d_field_Package_updated_at(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Package_updated_at(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Package_updated_at(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, Prev, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_Timestamp(Bs, TrUserData), TrUserData), Rest2} end, dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, if Prev == '$undef' -> NewFValue; true -> merge_msg_Timestamp(Prev, NewFValue, TrUserData) end, TrUserData). skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_Package(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). skip_group_Package(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_Package(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). decode_msg_Timestamp(Bin, TrUserData) -> dfp_read_field_def_Timestamp(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), TrUserData). dfp_read_field_def_Timestamp(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Timestamp_seconds(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Timestamp(<<16, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Timestamp_nanos(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Timestamp(<<>>, 0, 0, _, F@_1, F@_2, _) -> #{seconds => F@_1, nanos => F@_2}; dfp_read_field_def_Timestamp(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_Timestamp(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). dg_read_field_def_Timestamp(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_Timestamp(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); dg_read_field_def_Timestamp(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> Key = X bsl N + Acc, case Key of 8 -> d_field_Timestamp_seconds(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); 16 -> d_field_Timestamp_nanos(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 1 -> skip_64_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 2 -> skip_length_delimited_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 3 -> skip_group_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 5 -> skip_32_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) end end; dg_read_field_def_Timestamp(<<>>, 0, 0, _, F@_1, F@_2, _) -> #{seconds => F@_1, nanos => F@_2}. d_field_Timestamp_seconds(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Timestamp_seconds(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Timestamp_seconds(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) -> {NewFValue, RestF} = {begin <> = <<(X bsl N + Acc):64/unsigned-native>>, id(Res, TrUserData) end, Rest}, dfp_read_field_def_Timestamp(RestF, 0, 0, F, NewFValue, F@_2, TrUserData). d_field_Timestamp_nanos(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Timestamp_nanos(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Timestamp_nanos(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> {NewFValue, RestF} = {begin <> = <<(X bsl N + Acc):32/unsigned-native>>, id(Res, TrUserData) end, Rest}, dfp_read_field_def_Timestamp(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). skip_varint_Timestamp(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_Timestamp(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); skip_varint_Timestamp(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Timestamp(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_length_delimited_Timestamp(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_Timestamp(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); skip_length_delimited_Timestamp(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_Timestamp(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). skip_group_Timestamp(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_Timestamp(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). skip_32_Timestamp(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Timestamp(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_64_Timestamp(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Timestamp(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). read_group(Bin, FieldNum) -> {NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum), <> = Bin, {Group, Rest}. %% Like skipping over fields, but record the total length, %% Each field is <(FieldNum bsl 3) bor FieldType> ++ %% Record the length because varints may be non-optimally encoded. %% %% Groups can be nested, but assume the same FieldNum cannot be nested %% because group field numbers are shared with the rest of the fields %% numbers. Thus we can search just for an group-end with the same %% field number. %% %% (The only time the same group field number could occur would %% be in a nested sub message, but then it would be inside a %% length-delimited entry, which we skip-read by length.) read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) when N < (32-7) -> read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum); read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) -> Key = X bsl N + Acc, TagLen1 = TagLen + 1, case {Key bsr 3, Key band 7} of {FieldNum, 4} -> % 4 = group_end {NumBytes, TagLen1}; {_, 0} -> % 0 = varint read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum); {_, 1} -> % 1 = bits64 <<_:64, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum); {_, 2} -> % 2 = length_delimited read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum); {_, 3} -> % 3 = group_start read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); {_, 4} -> % 4 = group_end read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); {_, 5} -> % 5 = bits32 <<_:32, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum) end. read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum) when N < (64-7) -> read_gr_vi(Tl, N+7, NumBytes+1, FieldNum); read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) -> read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum). read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) when N < (64-7) -> read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum); read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) -> Len = X bsl N + Acc, NumBytes1 = NumBytes + 1, <<_:Len/binary, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum). merge_msgs(Prev, New, MsgName) when is_atom(MsgName) -> merge_msgs(Prev, New, MsgName, []). merge_msgs(Prev, New, MsgName, Opts) -> TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Names' -> merge_msg_Names(Prev, New, TrUserData); 'Package' -> merge_msg_Package(Prev, New, TrUserData); 'Timestamp' -> merge_msg_Timestamp(Prev, New, TrUserData) end. -compile({nowarn_unused_function,merge_msg_Names/3}). merge_msg_Names(#{} = PMsg, #{repository := NFrepository} = NMsg, TrUserData) -> S1 = #{repository => NFrepository}, case {PMsg, NMsg} of {#{packages := PFpackages}, #{packages := NFpackages}} -> S1#{packages => 'erlang_++'(PFpackages, NFpackages, TrUserData)}; {_, #{packages := NFpackages}} -> S1#{packages => NFpackages}; {#{packages := PFpackages}, _} -> S1#{packages => PFpackages}; {_, _} -> S1 end. -compile({nowarn_unused_function,merge_msg_Package/3}). merge_msg_Package(#{} = PMsg, #{name := NFname} = NMsg, TrUserData) -> S1 = #{name => NFname}, case {PMsg, NMsg} of {#{updated_at := PFupdated_at}, #{updated_at := NFupdated_at}} -> S1#{updated_at => merge_msg_Timestamp(PFupdated_at, NFupdated_at, TrUserData)}; {_, #{updated_at := NFupdated_at}} -> S1#{updated_at => NFupdated_at}; {#{updated_at := PFupdated_at}, _} -> S1#{updated_at => PFupdated_at}; {_, _} -> S1 end. -compile({nowarn_unused_function,merge_msg_Timestamp/3}). merge_msg_Timestamp(#{}, #{seconds := NFseconds, nanos := NFnanos}, _) -> #{seconds => NFseconds, nanos => NFnanos}. verify_msg(Msg, MsgName) when is_atom(MsgName) -> verify_msg(Msg, MsgName, []). verify_msg(Msg, MsgName, Opts) -> TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Names' -> v_msg_Names(Msg, [MsgName], TrUserData); 'Package' -> v_msg_Package(Msg, [MsgName], TrUserData); 'Timestamp' -> v_msg_Timestamp(Msg, [MsgName], TrUserData); _ -> mk_type_error(not_a_known_message, Msg, []) end. -compile({nowarn_unused_function,v_msg_Names/3}). v_msg_Names(#{repository := F2} = M, Path, TrUserData) -> case M of #{packages := F1} -> if is_list(F1) -> _ = [v_msg_Package(Elem, [packages | Path], TrUserData) || Elem <- F1], ok; true -> mk_type_error({invalid_list_of, {msg, 'Package'}}, F1, [packages | Path]) end; _ -> ok end, v_type_string(F2, [repository | Path], TrUserData), lists:foreach(fun (packages) -> ok; (repository) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_Names(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [repository] -- maps:keys(M), 'Names'}, M, Path); v_msg_Names(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Names'}, X, Path). -compile({nowarn_unused_function,v_msg_Package/3}). v_msg_Package(#{name := F1} = M, Path, TrUserData) -> v_type_string(F1, [name | Path], TrUserData), case M of #{updated_at := F2} -> v_msg_Timestamp(F2, [updated_at | Path], TrUserData); _ -> ok end, lists:foreach(fun (name) -> ok; (updated_at) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_Package(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [name] -- maps:keys(M), 'Package'}, M, Path); v_msg_Package(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Package'}, X, Path). -compile({nowarn_unused_function,v_msg_Timestamp/3}). v_msg_Timestamp(#{seconds := F1, nanos := F2} = M, Path, TrUserData) -> v_type_int64(F1, [seconds | Path], TrUserData), v_type_int32(F2, [nanos | Path], TrUserData), lists:foreach(fun (seconds) -> ok; (nanos) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_Timestamp(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [seconds, nanos] -- maps:keys(M), 'Timestamp'}, M, Path); v_msg_Timestamp(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Timestamp'}, X, Path). -compile({nowarn_unused_function,v_type_int32/3}). v_type_int32(N, _Path, _TrUserData) when -2147483648 =< N, N =< 2147483647 -> ok; v_type_int32(N, Path, _TrUserData) when is_integer(N) -> mk_type_error({value_out_of_range, int32, signed, 32}, N, Path); v_type_int32(X, Path, _TrUserData) -> mk_type_error({bad_integer, int32, signed, 32}, X, Path). -compile({nowarn_unused_function,v_type_int64/3}). v_type_int64(N, _Path, _TrUserData) when -9223372036854775808 =< N, N =< 9223372036854775807 -> ok; v_type_int64(N, Path, _TrUserData) when is_integer(N) -> mk_type_error({value_out_of_range, int64, signed, 64}, N, Path); v_type_int64(X, Path, _TrUserData) -> mk_type_error({bad_integer, int64, signed, 64}, X, Path). -compile({nowarn_unused_function,v_type_string/3}). v_type_string(S, Path, _TrUserData) when is_list(S); is_binary(S) -> try unicode:characters_to_binary(S) of B when is_binary(B) -> ok; {error, _, _} -> mk_type_error(bad_unicode_string, S, Path) catch error:badarg -> mk_type_error(bad_unicode_string, S, Path) end; v_type_string(X, Path, _TrUserData) -> mk_type_error(bad_unicode_string, X, Path). -compile({nowarn_unused_function,mk_type_error/3}). -spec mk_type_error(_, _, list()) -> no_return(). mk_type_error(Error, ValueSeen, Path) -> Path2 = prettify_path(Path), erlang:error({gpb_type_error, {Error, [{value, ValueSeen}, {path, Path2}]}}). -compile({nowarn_unused_function,prettify_path/1}). prettify_path([]) -> top_level; prettify_path(PathR) -> string:join(lists:map(fun atom_to_list/1, lists:reverse(PathR)), "."). -compile({nowarn_unused_function,id/2}). -compile({inline,id/2}). id(X, _TrUserData) -> X. -compile({nowarn_unused_function,v_ok/3}). -compile({inline,v_ok/3}). v_ok(_Value, _Path, _TrUserData) -> ok. -compile({nowarn_unused_function,m_overwrite/3}). -compile({inline,m_overwrite/3}). m_overwrite(_Prev, New, _TrUserData) -> New. -compile({nowarn_unused_function,cons/3}). -compile({inline,cons/3}). cons(Elem, Acc, _TrUserData) -> [Elem | Acc]. -compile({nowarn_unused_function,lists_reverse/2}). -compile({inline,lists_reverse/2}). 'lists_reverse'(L, _TrUserData) -> lists:reverse(L). -compile({nowarn_unused_function,'erlang_++'/3}). -compile({inline,'erlang_++'/3}). 'erlang_++'(A, B, _TrUserData) -> A ++ B. get_msg_defs() -> [{{msg, 'Names'}, [#{name => packages, fnum => 1, rnum => 2, type => {msg, 'Package'}, occurrence => repeated, opts => []}, #{name => repository, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []}]}, {{msg, 'Package'}, [#{name => name, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []}, #{name => updated_at, fnum => 3, rnum => 3, type => {msg, 'Timestamp'}, occurrence => optional, opts => []}]}, {{msg, 'Timestamp'}, [#{name => seconds, fnum => 1, rnum => 2, type => int64, occurrence => required, opts => []}, #{name => nanos, fnum => 2, rnum => 3, type => int32, occurrence => required, opts => []}]}]. get_msg_names() -> ['Names', 'Package', 'Timestamp']. get_group_names() -> []. get_msg_or_group_names() -> ['Names', 'Package', 'Timestamp']. get_enum_names() -> []. fetch_msg_def(MsgName) -> case find_msg_def(MsgName) of Fs when is_list(Fs) -> Fs; error -> erlang:error({no_such_msg, MsgName}) end. -spec fetch_enum_def(_) -> no_return(). fetch_enum_def(EnumName) -> erlang:error({no_such_enum, EnumName}). find_msg_def('Names') -> [#{name => packages, fnum => 1, rnum => 2, type => {msg, 'Package'}, occurrence => repeated, opts => []}, #{name => repository, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []}]; find_msg_def('Package') -> [#{name => name, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []}, #{name => updated_at, fnum => 3, rnum => 3, type => {msg, 'Timestamp'}, occurrence => optional, opts => []}]; find_msg_def('Timestamp') -> [#{name => seconds, fnum => 1, rnum => 2, type => int64, occurrence => required, opts => []}, #{name => nanos, fnum => 2, rnum => 3, type => int32, occurrence => required, opts => []}]; find_msg_def(_) -> error. find_enum_def(_) -> error. -spec enum_symbol_by_value(_, _) -> no_return(). enum_symbol_by_value(E, V) -> erlang:error({no_enum_defs, E, V}). -spec enum_value_by_symbol(_, _) -> no_return(). enum_value_by_symbol(E, V) -> erlang:error({no_enum_defs, E, V}). get_service_names() -> []. get_service_def(_) -> error. get_rpc_names(_) -> error. find_rpc_def(_, _) -> error. -spec fetch_rpc_def(_, _) -> no_return(). fetch_rpc_def(ServiceName, RpcName) -> erlang:error({no_such_rpc, ServiceName, RpcName}). %% Convert a a fully qualified (ie with package name) service name %% as a binary to a service name as an atom. -spec fqbin_to_service_name(_) -> no_return(). fqbin_to_service_name(X) -> error({gpb_error, {badservice, X}}). %% Convert a service name as an atom to a fully qualified %% (ie with package name) name as a binary. -spec service_name_to_fqbin(_) -> no_return(). service_name_to_fqbin(X) -> error({gpb_error, {badservice, X}}). %% Convert a a fully qualified (ie with package name) service name %% and an rpc name, both as binaries to a service name and an rpc %% name, as atoms. -spec fqbins_to_service_and_rpc_name(_, _) -> no_return(). fqbins_to_service_and_rpc_name(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). %% Convert a service name and an rpc name, both as atoms, %% to a fully qualified (ie with package name) service name and %% an rpc name as binaries. -spec service_and_rpc_name_to_fqbins(_, _) -> no_return(). service_and_rpc_name_to_fqbins(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). fqbin_to_msg_name(<<"Names">>) -> 'Names'; fqbin_to_msg_name(<<"Package">>) -> 'Package'; fqbin_to_msg_name(<<"Timestamp">>) -> 'Timestamp'; fqbin_to_msg_name(E) -> error({gpb_error, {badmsg, E}}). msg_name_to_fqbin('Names') -> <<"Names">>; msg_name_to_fqbin('Package') -> <<"Package">>; msg_name_to_fqbin('Timestamp') -> <<"Timestamp">>; msg_name_to_fqbin(E) -> error({gpb_error, {badmsg, E}}). -spec fqbin_to_enum_name(_) -> no_return(). fqbin_to_enum_name(E) -> error({gpb_error, {badenum, E}}). -spec enum_name_to_fqbin(_) -> no_return(). enum_name_to_fqbin(E) -> error({gpb_error, {badenum, E}}). get_package_name() -> undefined. %% Whether or not the message names %% are prepended with package name or not. uses_packages() -> false. source_basename() -> "mix_hex_pb_names.proto". %% Retrieve all proto file names, also imported ones. %% The order is top-down. The first element is always the main %% source file. The files are returned with extension, %% see get_all_proto_names/0 for a version that returns %% the basenames sans extension get_all_source_basenames() -> ["mix_hex_pb_names.proto"]. %% Retrieve all proto file names, also imported ones. %% The order is top-down. The first element is always the main %% source file. The files are returned sans .proto extension, %% to make it easier to use them with the various get_xyz_containment %% functions. get_all_proto_names() -> ["mix_hex_pb_names"]. get_msg_containment("mix_hex_pb_names") -> ['Names', 'Package', 'Timestamp']; get_msg_containment(P) -> error({gpb_error, {badproto, P}}). get_pkg_containment("mix_hex_pb_names") -> undefined; get_pkg_containment(P) -> error({gpb_error, {badproto, P}}). get_service_containment("mix_hex_pb_names") -> []; get_service_containment(P) -> error({gpb_error, {badproto, P}}). get_rpc_containment("mix_hex_pb_names") -> []; get_rpc_containment(P) -> error({gpb_error, {badproto, P}}). get_enum_containment("mix_hex_pb_names") -> []; get_enum_containment(P) -> error({gpb_error, {badproto, P}}). get_proto_by_msg_name_as_fqbin(<<"Timestamp">>) -> "mix_hex_pb_names"; get_proto_by_msg_name_as_fqbin(<<"Names">>) -> "mix_hex_pb_names"; get_proto_by_msg_name_as_fqbin(<<"Package">>) -> "mix_hex_pb_names"; get_proto_by_msg_name_as_fqbin(E) -> error({gpb_error, {badmsg, E}}). -spec get_proto_by_service_name_as_fqbin(_) -> no_return(). get_proto_by_service_name_as_fqbin(E) -> error({gpb_error, {badservice, E}}). -spec get_proto_by_enum_name_as_fqbin(_) -> no_return(). get_proto_by_enum_name_as_fqbin(E) -> error({gpb_error, {badenum, E}}). -spec get_protos_by_pkg_name_as_fqbin(_) -> no_return(). get_protos_by_pkg_name_as_fqbin(E) -> error({gpb_error, {badpkg, E}}). gpb_version_as_string() -> "4.17.6". gpb_version_as_list() -> [4,17,6]. gpb_version_source() -> "file". hex-2.0.6/src/mix_hex_pb_package.erl000066400000000000000000001756031437023760000174110ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% -*- coding: utf-8 -*- %% @private %% Automatically generated, do not edit %% Generated by gpb_compile version 4.17.6 %% Version source: file -module(mix_hex_pb_package). -export([encode_msg/2, encode_msg/3]). -export([decode_msg/2, decode_msg/3]). -export([merge_msgs/3, merge_msgs/4]). -export([verify_msg/2, verify_msg/3]). -export([get_msg_defs/0]). -export([get_msg_names/0]). -export([get_group_names/0]). -export([get_msg_or_group_names/0]). -export([get_enum_names/0]). -export([find_msg_def/1, fetch_msg_def/1]). -export([find_enum_def/1, fetch_enum_def/1]). -export([enum_symbol_by_value/2, enum_value_by_symbol/2]). -export([enum_symbol_by_value_RetirementReason/1, enum_value_by_symbol_RetirementReason/1]). -export([get_service_names/0]). -export([get_service_def/1]). -export([get_rpc_names/1]). -export([find_rpc_def/2, fetch_rpc_def/2]). -export([fqbin_to_service_name/1]). -export([service_name_to_fqbin/1]). -export([fqbins_to_service_and_rpc_name/2]). -export([service_and_rpc_name_to_fqbins/2]). -export([fqbin_to_msg_name/1]). -export([msg_name_to_fqbin/1]). -export([fqbin_to_enum_name/1]). -export([enum_name_to_fqbin/1]). -export([get_package_name/0]). -export([uses_packages/0]). -export([source_basename/0]). -export([get_all_source_basenames/0]). -export([get_all_proto_names/0]). -export([get_msg_containment/1]). -export([get_pkg_containment/1]). -export([get_service_containment/1]). -export([get_rpc_containment/1]). -export([get_enum_containment/1]). -export([get_proto_by_msg_name_as_fqbin/1]). -export([get_proto_by_service_name_as_fqbin/1]). -export([get_proto_by_enum_name_as_fqbin/1]). -export([get_protos_by_pkg_name_as_fqbin/1]). -export([gpb_version_as_string/0, gpb_version_as_list/0]). -export([gpb_version_source/0]). %% enumerated types -type 'RetirementReason'() :: 'RETIRED_OTHER' | 'RETIRED_INVALID' | 'RETIRED_SECURITY' | 'RETIRED_DEPRECATED' | 'RETIRED_RENAMED'. -export_type(['RetirementReason'/0]). %% message types -type 'Package'() :: #{releases => ['Release'()], % = 1, repeated name => unicode:chardata(), % = 2, required repository => unicode:chardata() % = 3, required }. -type 'Release'() :: #{version => unicode:chardata(), % = 1, required inner_checksum => iodata(), % = 2, required dependencies => ['Dependency'()], % = 3, repeated retired => 'RetirementStatus'(), % = 4, optional outer_checksum => iodata() % = 5, optional }. -type 'RetirementStatus'() :: #{reason => 'RETIRED_OTHER' | 'RETIRED_INVALID' | 'RETIRED_SECURITY' | 'RETIRED_DEPRECATED' | 'RETIRED_RENAMED' | integer(), % = 1, required, enum RetirementReason message => unicode:chardata() % = 2, optional }. -type 'Dependency'() :: #{package => unicode:chardata(), % = 1, required requirement => unicode:chardata(), % = 2, required optional => boolean() | 0 | 1, % = 3, optional app => unicode:chardata(), % = 4, optional repository => unicode:chardata() % = 5, optional }. -export_type(['Package'/0, 'Release'/0, 'RetirementStatus'/0, 'Dependency'/0]). -type '$msg_name'() :: 'Package' | 'Release' | 'RetirementStatus' | 'Dependency'. -type '$msg'() :: 'Package'() | 'Release'() | 'RetirementStatus'() | 'Dependency'(). -export_type(['$msg_name'/0, '$msg'/0]). -spec encode_msg('$msg'(), '$msg_name'()) -> binary(). encode_msg(Msg, MsgName) when is_atom(MsgName) -> encode_msg(Msg, MsgName, []). -spec encode_msg('$msg'(), '$msg_name'(), list()) -> binary(). encode_msg(Msg, MsgName, Opts) -> verify_msg(Msg, MsgName, Opts), TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Package' -> encode_msg_Package(id(Msg, TrUserData), TrUserData); 'Release' -> encode_msg_Release(id(Msg, TrUserData), TrUserData); 'RetirementStatus' -> encode_msg_RetirementStatus(id(Msg, TrUserData), TrUserData); 'Dependency' -> encode_msg_Dependency(id(Msg, TrUserData), TrUserData) end. encode_msg_Package(Msg, TrUserData) -> encode_msg_Package(Msg, <<>>, TrUserData). encode_msg_Package(#{name := F2, repository := F3} = M, Bin, TrUserData) -> B1 = case M of #{releases := F1} -> TrF1 = id(F1, TrUserData), if TrF1 == [] -> Bin; true -> e_field_Package_releases(TrF1, Bin, TrUserData) end; _ -> Bin end, B2 = begin TrF2 = id(F2, TrUserData), e_type_string(TrF2, <>, TrUserData) end, begin TrF3 = id(F3, TrUserData), e_type_string(TrF3, <>, TrUserData) end. encode_msg_Release(Msg, TrUserData) -> encode_msg_Release(Msg, <<>>, TrUserData). encode_msg_Release(#{version := F1, inner_checksum := F2} = M, Bin, TrUserData) -> B1 = begin TrF1 = id(F1, TrUserData), e_type_string(TrF1, <>, TrUserData) end, B2 = begin TrF2 = id(F2, TrUserData), e_type_bytes(TrF2, <>, TrUserData) end, B3 = case M of #{dependencies := F3} -> TrF3 = id(F3, TrUserData), if TrF3 == [] -> B2; true -> e_field_Release_dependencies(TrF3, B2, TrUserData) end; _ -> B2 end, B4 = case M of #{retired := F4} -> begin TrF4 = id(F4, TrUserData), e_mfield_Release_retired(TrF4, <>, TrUserData) end; _ -> B3 end, case M of #{outer_checksum := F5} -> begin TrF5 = id(F5, TrUserData), e_type_bytes(TrF5, <>, TrUserData) end; _ -> B4 end. encode_msg_RetirementStatus(Msg, TrUserData) -> encode_msg_RetirementStatus(Msg, <<>>, TrUserData). encode_msg_RetirementStatus(#{reason := F1} = M, Bin, TrUserData) -> B1 = begin TrF1 = id(F1, TrUserData), e_enum_RetirementReason(TrF1, <>, TrUserData) end, case M of #{message := F2} -> begin TrF2 = id(F2, TrUserData), e_type_string(TrF2, <>, TrUserData) end; _ -> B1 end. encode_msg_Dependency(Msg, TrUserData) -> encode_msg_Dependency(Msg, <<>>, TrUserData). encode_msg_Dependency(#{package := F1, requirement := F2} = M, Bin, TrUserData) -> B1 = begin TrF1 = id(F1, TrUserData), e_type_string(TrF1, <>, TrUserData) end, B2 = begin TrF2 = id(F2, TrUserData), e_type_string(TrF2, <>, TrUserData) end, B3 = case M of #{optional := F3} -> begin TrF3 = id(F3, TrUserData), e_type_bool(TrF3, <>, TrUserData) end; _ -> B2 end, B4 = case M of #{app := F4} -> begin TrF4 = id(F4, TrUserData), e_type_string(TrF4, <>, TrUserData) end; _ -> B3 end, case M of #{repository := F5} -> begin TrF5 = id(F5, TrUserData), e_type_string(TrF5, <>, TrUserData) end; _ -> B4 end. e_mfield_Package_releases(Msg, Bin, TrUserData) -> SubBin = encode_msg_Release(Msg, <<>>, TrUserData), Bin2 = e_varint(byte_size(SubBin), Bin), <>. e_field_Package_releases([Elem | Rest], Bin, TrUserData) -> Bin2 = <>, Bin3 = e_mfield_Package_releases(id(Elem, TrUserData), Bin2, TrUserData), e_field_Package_releases(Rest, Bin3, TrUserData); e_field_Package_releases([], Bin, _TrUserData) -> Bin. e_mfield_Release_dependencies(Msg, Bin, TrUserData) -> SubBin = encode_msg_Dependency(Msg, <<>>, TrUserData), Bin2 = e_varint(byte_size(SubBin), Bin), <>. e_field_Release_dependencies([Elem | Rest], Bin, TrUserData) -> Bin2 = <>, Bin3 = e_mfield_Release_dependencies(id(Elem, TrUserData), Bin2, TrUserData), e_field_Release_dependencies(Rest, Bin3, TrUserData); e_field_Release_dependencies([], Bin, _TrUserData) -> Bin. e_mfield_Release_retired(Msg, Bin, TrUserData) -> SubBin = encode_msg_RetirementStatus(Msg, <<>>, TrUserData), Bin2 = e_varint(byte_size(SubBin), Bin), <>. e_enum_RetirementReason('RETIRED_OTHER', Bin, _TrUserData) -> <>; e_enum_RetirementReason('RETIRED_INVALID', Bin, _TrUserData) -> <>; e_enum_RetirementReason('RETIRED_SECURITY', Bin, _TrUserData) -> <>; e_enum_RetirementReason('RETIRED_DEPRECATED', Bin, _TrUserData) -> <>; e_enum_RetirementReason('RETIRED_RENAMED', Bin, _TrUserData) -> <>; e_enum_RetirementReason(V, Bin, _TrUserData) -> e_varint(V, Bin). -compile({nowarn_unused_function,e_type_sint/3}). e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> e_varint(Value * 2, Bin); e_type_sint(Value, Bin, _TrUserData) -> e_varint(Value * -2 - 1, Bin). -compile({nowarn_unused_function,e_type_int32/3}). e_type_int32(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; e_type_int32(Value, Bin, _TrUserData) -> <> = <>, e_varint(N, Bin). -compile({nowarn_unused_function,e_type_int64/3}). e_type_int64(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; e_type_int64(Value, Bin, _TrUserData) -> <> = <>, e_varint(N, Bin). -compile({nowarn_unused_function,e_type_bool/3}). e_type_bool(true, Bin, _TrUserData) -> <>; e_type_bool(false, Bin, _TrUserData) -> <>; e_type_bool(1, Bin, _TrUserData) -> <>; e_type_bool(0, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_string/3}). e_type_string(S, Bin, _TrUserData) -> Utf8 = unicode:characters_to_binary(S), Bin2 = e_varint(byte_size(Utf8), Bin), <>. -compile({nowarn_unused_function,e_type_bytes/3}). e_type_bytes(Bytes, Bin, _TrUserData) when is_binary(Bytes) -> Bin2 = e_varint(byte_size(Bytes), Bin), <>; e_type_bytes(Bytes, Bin, _TrUserData) when is_list(Bytes) -> BytesBin = iolist_to_binary(Bytes), Bin2 = e_varint(byte_size(BytesBin), Bin), <>. -compile({nowarn_unused_function,e_type_fixed32/3}). e_type_fixed32(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_sfixed32/3}). e_type_sfixed32(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_fixed64/3}). e_type_fixed64(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_sfixed64/3}). e_type_sfixed64(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_float/3}). e_type_float(V, Bin, _) when is_number(V) -> <>; e_type_float(infinity, Bin, _) -> <>; e_type_float('-infinity', Bin, _) -> <>; e_type_float(nan, Bin, _) -> <>. -compile({nowarn_unused_function,e_type_double/3}). e_type_double(V, Bin, _) when is_number(V) -> <>; e_type_double(infinity, Bin, _) -> <>; e_type_double('-infinity', Bin, _) -> <>; e_type_double(nan, Bin, _) -> <>. -compile({nowarn_unused_function,e_unknown_elems/2}). e_unknown_elems([Elem | Rest], Bin) -> BinR = case Elem of {varint, FNum, N} -> BinF = e_varint(FNum bsl 3, Bin), e_varint(N, BinF); {length_delimited, FNum, Data} -> BinF = e_varint(FNum bsl 3 bor 2, Bin), BinL = e_varint(byte_size(Data), BinF), <>; {group, FNum, GroupFields} -> Bin1 = e_varint(FNum bsl 3 bor 3, Bin), Bin2 = e_unknown_elems(GroupFields, Bin1), e_varint(FNum bsl 3 bor 4, Bin2); {fixed32, FNum, V} -> BinF = e_varint(FNum bsl 3 bor 5, Bin), <>; {fixed64, FNum, V} -> BinF = e_varint(FNum bsl 3 bor 1, Bin), <> end, e_unknown_elems(Rest, BinR); e_unknown_elems([], Bin) -> Bin. -compile({nowarn_unused_function,e_varint/3}). e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin). -compile({nowarn_unused_function,e_varint/2}). e_varint(N, Bin) when N =< 127 -> <>; e_varint(N, Bin) -> Bin2 = <>, e_varint(N bsr 7, Bin2). decode_msg(Bin, MsgName) when is_binary(Bin) -> decode_msg(Bin, MsgName, []). decode_msg(Bin, MsgName, Opts) when is_binary(Bin) -> TrUserData = proplists:get_value(user_data, Opts), decode_msg_1_catch(Bin, MsgName, TrUserData). -ifdef('OTP_RELEASE'). decode_msg_1_catch(Bin, MsgName, TrUserData) -> try decode_msg_2_doit(MsgName, Bin, TrUserData) catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) end. -else. decode_msg_1_catch(Bin, MsgName, TrUserData) -> try decode_msg_2_doit(MsgName, Bin, TrUserData) catch Class:Reason -> StackTrace = erlang:get_stacktrace(), error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) end. -endif. decode_msg_2_doit('Package', Bin, TrUserData) -> id(decode_msg_Package(Bin, TrUserData), TrUserData); decode_msg_2_doit('Release', Bin, TrUserData) -> id(decode_msg_Release(Bin, TrUserData), TrUserData); decode_msg_2_doit('RetirementStatus', Bin, TrUserData) -> id(decode_msg_RetirementStatus(Bin, TrUserData), TrUserData); decode_msg_2_doit('Dependency', Bin, TrUserData) -> id(decode_msg_Dependency(Bin, TrUserData), TrUserData). decode_msg_Package(Bin, TrUserData) -> dfp_read_field_def_Package(Bin, 0, 0, 0, id([], TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), TrUserData). dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_releases(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); dfp_read_field_def_Package(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_name(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); dfp_read_field_def_Package(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_repository(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); dfp_read_field_def_Package(<<>>, 0, 0, _, R1, F@_2, F@_3, TrUserData) -> S1 = #{name => F@_2, repository => F@_3}, if R1 == '$undef' -> S1; true -> S1#{releases => lists_reverse(R1, TrUserData)} end; dfp_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) -> Key = X bsl N + Acc, case Key of 10 -> d_field_Package_releases(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); 18 -> d_field_Package_name(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); 26 -> d_field_Package_repository(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); 1 -> skip_64_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); 2 -> skip_length_delimited_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); 3 -> skip_group_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); 5 -> skip_32_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData) end end; dg_read_field_def_Package(<<>>, 0, 0, _, R1, F@_2, F@_3, TrUserData) -> S1 = #{name => F@_2, repository => F@_3}, if R1 == '$undef' -> S1; true -> S1#{releases => lists_reverse(R1, TrUserData)} end. d_field_Package_releases(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_releases(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); d_field_Package_releases(<<0:1, X:7, Rest/binary>>, N, Acc, F, Prev, F@_2, F@_3, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_Release(Bs, TrUserData), TrUserData), Rest2} end, dfp_read_field_def_Package(RestF, 0, 0, F, cons(NewFValue, Prev, TrUserData), F@_2, F@_3, TrUserData). d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_name(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, NewFValue, F@_3, TrUserData). d_field_Package_repository(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_repository(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); d_field_Package_repository(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, F@_2, NewFValue, TrUserData). skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData). skip_group_Package(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_Package(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData). skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). decode_msg_Release(Bin, TrUserData) -> dfp_read_field_def_Release(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), id([], TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), TrUserData). dfp_read_field_def_Release(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_version(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Release(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_inner_checksum(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Release(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_dependencies(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Release(<<34, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_retired(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Release(<<42, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_outer_checksum(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Release(<<>>, 0, 0, _, F@_1, F@_2, R1, F@_4, F@_5, TrUserData) -> S1 = #{version => F@_1, inner_checksum => F@_2}, S2 = if R1 == '$undef' -> S1; true -> S1#{dependencies => lists_reverse(R1, TrUserData)} end, S3 = if F@_4 == '$undef' -> S2; true -> S2#{retired => F@_4} end, if F@_5 == '$undef' -> S3; true -> S3#{outer_checksum => F@_5} end; dfp_read_field_def_Release(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dg_read_field_def_Release(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). dg_read_field_def_Release(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 32 - 7 -> dg_read_field_def_Release(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dg_read_field_def_Release(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> Key = X bsl N + Acc, case Key of 10 -> d_field_Release_version(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 18 -> d_field_Release_inner_checksum(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 26 -> d_field_Release_dependencies(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 34 -> d_field_Release_retired(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 42 -> d_field_Release_outer_checksum(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 1 -> skip_64_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 2 -> skip_length_delimited_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 3 -> skip_group_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 5 -> skip_32_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) end end; dg_read_field_def_Release(<<>>, 0, 0, _, F@_1, F@_2, R1, F@_4, F@_5, TrUserData) -> S1 = #{version => F@_1, inner_checksum => F@_2}, S2 = if R1 == '$undef' -> S1; true -> S1#{dependencies => lists_reverse(R1, TrUserData)} end, S3 = if F@_4 == '$undef' -> S2; true -> S2#{retired => F@_4} end, if F@_5 == '$undef' -> S3; true -> S3#{outer_checksum => F@_5} end. d_field_Release_version(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_version(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Release_version(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, F@_5, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Release(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, F@_5, TrUserData). d_field_Release_inner_checksum(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_inner_checksum(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Release_inner_checksum(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, TrUserData). d_field_Release_dependencies(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_dependencies(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Release_dependencies(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, Prev, F@_4, F@_5, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_Dependency(Bs, TrUserData), TrUserData), Rest2} end, dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, F@_2, cons(NewFValue, Prev, TrUserData), F@_4, F@_5, TrUserData). d_field_Release_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_retired(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Release_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, Prev, F@_5, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_RetirementStatus(Bs, TrUserData), TrUserData), Rest2} end, dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, F@_2, F@_3, if Prev == '$undef' -> NewFValue; true -> merge_msg_RetirementStatus(Prev, NewFValue, TrUserData) end, F@_5, TrUserData). d_field_Release_outer_checksum(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_outer_checksum(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Release_outer_checksum(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, _, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, NewFValue, TrUserData). skip_varint_Release(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> skip_varint_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); skip_varint_Release(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). skip_length_delimited_Release(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> skip_length_delimited_Release(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); skip_length_delimited_Release(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_Release(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). skip_group_Release(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_Release(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). skip_32_Release(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). skip_64_Release(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). decode_msg_RetirementStatus(Bin, TrUserData) -> dfp_read_field_def_RetirementStatus(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), TrUserData). dfp_read_field_def_RetirementStatus(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_RetirementStatus_reason(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_RetirementStatus(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_RetirementStatus_message(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_RetirementStatus(<<>>, 0, 0, _, F@_1, F@_2, _) -> S1 = #{reason => F@_1}, if F@_2 == '$undef' -> S1; true -> S1#{message => F@_2} end; dfp_read_field_def_RetirementStatus(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_RetirementStatus(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). dg_read_field_def_RetirementStatus(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_RetirementStatus(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); dg_read_field_def_RetirementStatus(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> Key = X bsl N + Acc, case Key of 8 -> d_field_RetirementStatus_reason(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); 18 -> d_field_RetirementStatus_message(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_RetirementStatus(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 1 -> skip_64_RetirementStatus(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 2 -> skip_length_delimited_RetirementStatus(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 3 -> skip_group_RetirementStatus(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 5 -> skip_32_RetirementStatus(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) end end; dg_read_field_def_RetirementStatus(<<>>, 0, 0, _, F@_1, F@_2, _) -> S1 = #{reason => F@_1}, if F@_2 == '$undef' -> S1; true -> S1#{message => F@_2} end. d_field_RetirementStatus_reason(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_RetirementStatus_reason(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_RetirementStatus_reason(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) -> {NewFValue, RestF} = {id(d_enum_RetirementReason(begin <> = <<(X bsl N + Acc):32/unsigned-native>>, id(Res, TrUserData) end), TrUserData), Rest}, dfp_read_field_def_RetirementStatus(RestF, 0, 0, F, NewFValue, F@_2, TrUserData). d_field_RetirementStatus_message(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_RetirementStatus_message(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_RetirementStatus_message(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_RetirementStatus(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). skip_varint_RetirementStatus(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_RetirementStatus(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); skip_varint_RetirementStatus(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_RetirementStatus(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_length_delimited_RetirementStatus(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_RetirementStatus(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); skip_length_delimited_RetirementStatus(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_RetirementStatus(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). skip_group_RetirementStatus(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_RetirementStatus(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). skip_32_RetirementStatus(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_RetirementStatus(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_64_RetirementStatus(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_RetirementStatus(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). decode_msg_Dependency(Bin, TrUserData) -> dfp_read_field_def_Dependency(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), TrUserData). dfp_read_field_def_Dependency(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Dependency_package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Dependency(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Dependency_requirement(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Dependency(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Dependency_optional(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Dependency(<<34, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Dependency_app(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Dependency(<<42, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Dependency_repository(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dfp_read_field_def_Dependency(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, _) -> S1 = #{package => F@_1, requirement => F@_2}, S2 = if F@_3 == '$undef' -> S1; true -> S1#{optional => F@_3} end, S3 = if F@_4 == '$undef' -> S2; true -> S2#{app => F@_4} end, if F@_5 == '$undef' -> S3; true -> S3#{repository => F@_5} end; dfp_read_field_def_Dependency(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dg_read_field_def_Dependency(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). dg_read_field_def_Dependency(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 32 - 7 -> dg_read_field_def_Dependency(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); dg_read_field_def_Dependency(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> Key = X bsl N + Acc, case Key of 10 -> d_field_Dependency_package(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 18 -> d_field_Dependency_requirement(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 24 -> d_field_Dependency_optional(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 34 -> d_field_Dependency_app(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 42 -> d_field_Dependency_repository(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_Dependency(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 1 -> skip_64_Dependency(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 2 -> skip_length_delimited_Dependency(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 3 -> skip_group_Dependency(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); 5 -> skip_32_Dependency(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) end end; dg_read_field_def_Dependency(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, _) -> S1 = #{package => F@_1, requirement => F@_2}, S2 = if F@_3 == '$undef' -> S1; true -> S1#{optional => F@_3} end, S3 = if F@_4 == '$undef' -> S2; true -> S2#{app => F@_4} end, if F@_5 == '$undef' -> S3; true -> S3#{repository => F@_5} end. d_field_Dependency_package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Dependency_package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Dependency_package(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, F@_5, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Dependency(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, F@_5, TrUserData). d_field_Dependency_requirement(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Dependency_requirement(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Dependency_requirement(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Dependency(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, TrUserData). d_field_Dependency_optional(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Dependency_optional(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Dependency_optional(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, F@_4, F@_5, TrUserData) -> {NewFValue, RestF} = {id(X bsl N + Acc =/= 0, TrUserData), Rest}, dfp_read_field_def_Dependency(RestF, 0, 0, F, F@_1, F@_2, NewFValue, F@_4, F@_5, TrUserData). d_field_Dependency_app(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Dependency_app(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Dependency_app(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, _, F@_5, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Dependency(RestF, 0, 0, F, F@_1, F@_2, F@_3, NewFValue, F@_5, TrUserData). d_field_Dependency_repository(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Dependency_repository(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); d_field_Dependency_repository(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, _, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Dependency(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, NewFValue, TrUserData). skip_varint_Dependency(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> skip_varint_Dependency(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); skip_varint_Dependency(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Dependency(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). skip_length_delimited_Dependency(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> skip_length_delimited_Dependency(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); skip_length_delimited_Dependency(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_Dependency(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). skip_group_Dependency(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_Dependency(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). skip_32_Dependency(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Dependency(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). skip_64_Dependency(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Dependency(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). d_enum_RetirementReason(0) -> 'RETIRED_OTHER'; d_enum_RetirementReason(1) -> 'RETIRED_INVALID'; d_enum_RetirementReason(2) -> 'RETIRED_SECURITY'; d_enum_RetirementReason(3) -> 'RETIRED_DEPRECATED'; d_enum_RetirementReason(4) -> 'RETIRED_RENAMED'; d_enum_RetirementReason(V) -> V. read_group(Bin, FieldNum) -> {NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum), <> = Bin, {Group, Rest}. %% Like skipping over fields, but record the total length, %% Each field is <(FieldNum bsl 3) bor FieldType> ++ %% Record the length because varints may be non-optimally encoded. %% %% Groups can be nested, but assume the same FieldNum cannot be nested %% because group field numbers are shared with the rest of the fields %% numbers. Thus we can search just for an group-end with the same %% field number. %% %% (The only time the same group field number could occur would %% be in a nested sub message, but then it would be inside a %% length-delimited entry, which we skip-read by length.) read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) when N < (32-7) -> read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum); read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) -> Key = X bsl N + Acc, TagLen1 = TagLen + 1, case {Key bsr 3, Key band 7} of {FieldNum, 4} -> % 4 = group_end {NumBytes, TagLen1}; {_, 0} -> % 0 = varint read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum); {_, 1} -> % 1 = bits64 <<_:64, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum); {_, 2} -> % 2 = length_delimited read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum); {_, 3} -> % 3 = group_start read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); {_, 4} -> % 4 = group_end read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); {_, 5} -> % 5 = bits32 <<_:32, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum) end. read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum) when N < (64-7) -> read_gr_vi(Tl, N+7, NumBytes+1, FieldNum); read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) -> read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum). read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) when N < (64-7) -> read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum); read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) -> Len = X bsl N + Acc, NumBytes1 = NumBytes + 1, <<_:Len/binary, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum). merge_msgs(Prev, New, MsgName) when is_atom(MsgName) -> merge_msgs(Prev, New, MsgName, []). merge_msgs(Prev, New, MsgName, Opts) -> TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Package' -> merge_msg_Package(Prev, New, TrUserData); 'Release' -> merge_msg_Release(Prev, New, TrUserData); 'RetirementStatus' -> merge_msg_RetirementStatus(Prev, New, TrUserData); 'Dependency' -> merge_msg_Dependency(Prev, New, TrUserData) end. -compile({nowarn_unused_function,merge_msg_Package/3}). merge_msg_Package(#{} = PMsg, #{name := NFname, repository := NFrepository} = NMsg, TrUserData) -> S1 = #{name => NFname, repository => NFrepository}, case {PMsg, NMsg} of {#{releases := PFreleases}, #{releases := NFreleases}} -> S1#{releases => 'erlang_++'(PFreleases, NFreleases, TrUserData)}; {_, #{releases := NFreleases}} -> S1#{releases => NFreleases}; {#{releases := PFreleases}, _} -> S1#{releases => PFreleases}; {_, _} -> S1 end. -compile({nowarn_unused_function,merge_msg_Release/3}). merge_msg_Release(#{} = PMsg, #{version := NFversion, inner_checksum := NFinner_checksum} = NMsg, TrUserData) -> S1 = #{version => NFversion, inner_checksum => NFinner_checksum}, S2 = case {PMsg, NMsg} of {#{dependencies := PFdependencies}, #{dependencies := NFdependencies}} -> S1#{dependencies => 'erlang_++'(PFdependencies, NFdependencies, TrUserData)}; {_, #{dependencies := NFdependencies}} -> S1#{dependencies => NFdependencies}; {#{dependencies := PFdependencies}, _} -> S1#{dependencies => PFdependencies}; {_, _} -> S1 end, S3 = case {PMsg, NMsg} of {#{retired := PFretired}, #{retired := NFretired}} -> S2#{retired => merge_msg_RetirementStatus(PFretired, NFretired, TrUserData)}; {_, #{retired := NFretired}} -> S2#{retired => NFretired}; {#{retired := PFretired}, _} -> S2#{retired => PFretired}; {_, _} -> S2 end, case {PMsg, NMsg} of {_, #{outer_checksum := NFouter_checksum}} -> S3#{outer_checksum => NFouter_checksum}; {#{outer_checksum := PFouter_checksum}, _} -> S3#{outer_checksum => PFouter_checksum}; _ -> S3 end. -compile({nowarn_unused_function,merge_msg_RetirementStatus/3}). merge_msg_RetirementStatus(#{} = PMsg, #{reason := NFreason} = NMsg, _) -> S1 = #{reason => NFreason}, case {PMsg, NMsg} of {_, #{message := NFmessage}} -> S1#{message => NFmessage}; {#{message := PFmessage}, _} -> S1#{message => PFmessage}; _ -> S1 end. -compile({nowarn_unused_function,merge_msg_Dependency/3}). merge_msg_Dependency(#{} = PMsg, #{package := NFpackage, requirement := NFrequirement} = NMsg, _) -> S1 = #{package => NFpackage, requirement => NFrequirement}, S2 = case {PMsg, NMsg} of {_, #{optional := NFoptional}} -> S1#{optional => NFoptional}; {#{optional := PFoptional}, _} -> S1#{optional => PFoptional}; _ -> S1 end, S3 = case {PMsg, NMsg} of {_, #{app := NFapp}} -> S2#{app => NFapp}; {#{app := PFapp}, _} -> S2#{app => PFapp}; _ -> S2 end, case {PMsg, NMsg} of {_, #{repository := NFrepository}} -> S3#{repository => NFrepository}; {#{repository := PFrepository}, _} -> S3#{repository => PFrepository}; _ -> S3 end. verify_msg(Msg, MsgName) when is_atom(MsgName) -> verify_msg(Msg, MsgName, []). verify_msg(Msg, MsgName, Opts) -> TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Package' -> v_msg_Package(Msg, [MsgName], TrUserData); 'Release' -> v_msg_Release(Msg, [MsgName], TrUserData); 'RetirementStatus' -> v_msg_RetirementStatus(Msg, [MsgName], TrUserData); 'Dependency' -> v_msg_Dependency(Msg, [MsgName], TrUserData); _ -> mk_type_error(not_a_known_message, Msg, []) end. -compile({nowarn_unused_function,v_msg_Package/3}). v_msg_Package(#{name := F2, repository := F3} = M, Path, TrUserData) -> case M of #{releases := F1} -> if is_list(F1) -> _ = [v_msg_Release(Elem, [releases | Path], TrUserData) || Elem <- F1], ok; true -> mk_type_error({invalid_list_of, {msg, 'Release'}}, F1, [releases | Path]) end; _ -> ok end, v_type_string(F2, [name | Path], TrUserData), v_type_string(F3, [repository | Path], TrUserData), lists:foreach(fun (releases) -> ok; (name) -> ok; (repository) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_Package(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [name, repository] -- maps:keys(M), 'Package'}, M, Path); v_msg_Package(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Package'}, X, Path). -compile({nowarn_unused_function,v_msg_Release/3}). v_msg_Release(#{version := F1, inner_checksum := F2} = M, Path, TrUserData) -> v_type_string(F1, [version | Path], TrUserData), v_type_bytes(F2, [inner_checksum | Path], TrUserData), case M of #{dependencies := F3} -> if is_list(F3) -> _ = [v_msg_Dependency(Elem, [dependencies | Path], TrUserData) || Elem <- F3], ok; true -> mk_type_error({invalid_list_of, {msg, 'Dependency'}}, F3, [dependencies | Path]) end; _ -> ok end, case M of #{retired := F4} -> v_msg_RetirementStatus(F4, [retired | Path], TrUserData); _ -> ok end, case M of #{outer_checksum := F5} -> v_type_bytes(F5, [outer_checksum | Path], TrUserData); _ -> ok end, lists:foreach(fun (version) -> ok; (inner_checksum) -> ok; (dependencies) -> ok; (retired) -> ok; (outer_checksum) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_Release(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [version, inner_checksum] -- maps:keys(M), 'Release'}, M, Path); v_msg_Release(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Release'}, X, Path). -compile({nowarn_unused_function,v_msg_RetirementStatus/3}). v_msg_RetirementStatus(#{reason := F1} = M, Path, TrUserData) -> v_enum_RetirementReason(F1, [reason | Path], TrUserData), case M of #{message := F2} -> v_type_string(F2, [message | Path], TrUserData); _ -> ok end, lists:foreach(fun (reason) -> ok; (message) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_RetirementStatus(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [reason] -- maps:keys(M), 'RetirementStatus'}, M, Path); v_msg_RetirementStatus(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'RetirementStatus'}, X, Path). -compile({nowarn_unused_function,v_msg_Dependency/3}). v_msg_Dependency(#{package := F1, requirement := F2} = M, Path, TrUserData) -> v_type_string(F1, [package | Path], TrUserData), v_type_string(F2, [requirement | Path], TrUserData), case M of #{optional := F3} -> v_type_bool(F3, [optional | Path], TrUserData); _ -> ok end, case M of #{app := F4} -> v_type_string(F4, [app | Path], TrUserData); _ -> ok end, case M of #{repository := F5} -> v_type_string(F5, [repository | Path], TrUserData); _ -> ok end, lists:foreach(fun (package) -> ok; (requirement) -> ok; (optional) -> ok; (app) -> ok; (repository) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_Dependency(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [package, requirement] -- maps:keys(M), 'Dependency'}, M, Path); v_msg_Dependency(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Dependency'}, X, Path). -compile({nowarn_unused_function,v_enum_RetirementReason/3}). v_enum_RetirementReason('RETIRED_OTHER', _Path, _TrUserData) -> ok; v_enum_RetirementReason('RETIRED_INVALID', _Path, _TrUserData) -> ok; v_enum_RetirementReason('RETIRED_SECURITY', _Path, _TrUserData) -> ok; v_enum_RetirementReason('RETIRED_DEPRECATED', _Path, _TrUserData) -> ok; v_enum_RetirementReason('RETIRED_RENAMED', _Path, _TrUserData) -> ok; v_enum_RetirementReason(V, _Path, _TrUserData) when -2147483648 =< V, V =< 2147483647, is_integer(V) -> ok; v_enum_RetirementReason(X, Path, _TrUserData) -> mk_type_error({invalid_enum, 'RetirementReason'}, X, Path). -compile({nowarn_unused_function,v_type_bool/3}). v_type_bool(false, _Path, _TrUserData) -> ok; v_type_bool(true, _Path, _TrUserData) -> ok; v_type_bool(0, _Path, _TrUserData) -> ok; v_type_bool(1, _Path, _TrUserData) -> ok; v_type_bool(X, Path, _TrUserData) -> mk_type_error(bad_boolean_value, X, Path). -compile({nowarn_unused_function,v_type_string/3}). v_type_string(S, Path, _TrUserData) when is_list(S); is_binary(S) -> try unicode:characters_to_binary(S) of B when is_binary(B) -> ok; {error, _, _} -> mk_type_error(bad_unicode_string, S, Path) catch error:badarg -> mk_type_error(bad_unicode_string, S, Path) end; v_type_string(X, Path, _TrUserData) -> mk_type_error(bad_unicode_string, X, Path). -compile({nowarn_unused_function,v_type_bytes/3}). v_type_bytes(B, _Path, _TrUserData) when is_binary(B) -> ok; v_type_bytes(B, _Path, _TrUserData) when is_list(B) -> ok; v_type_bytes(X, Path, _TrUserData) -> mk_type_error(bad_binary_value, X, Path). -compile({nowarn_unused_function,mk_type_error/3}). -spec mk_type_error(_, _, list()) -> no_return(). mk_type_error(Error, ValueSeen, Path) -> Path2 = prettify_path(Path), erlang:error({gpb_type_error, {Error, [{value, ValueSeen}, {path, Path2}]}}). -compile({nowarn_unused_function,prettify_path/1}). prettify_path([]) -> top_level; prettify_path(PathR) -> string:join(lists:map(fun atom_to_list/1, lists:reverse(PathR)), "."). -compile({nowarn_unused_function,id/2}). -compile({inline,id/2}). id(X, _TrUserData) -> X. -compile({nowarn_unused_function,v_ok/3}). -compile({inline,v_ok/3}). v_ok(_Value, _Path, _TrUserData) -> ok. -compile({nowarn_unused_function,m_overwrite/3}). -compile({inline,m_overwrite/3}). m_overwrite(_Prev, New, _TrUserData) -> New. -compile({nowarn_unused_function,cons/3}). -compile({inline,cons/3}). cons(Elem, Acc, _TrUserData) -> [Elem | Acc]. -compile({nowarn_unused_function,lists_reverse/2}). -compile({inline,lists_reverse/2}). 'lists_reverse'(L, _TrUserData) -> lists:reverse(L). -compile({nowarn_unused_function,'erlang_++'/3}). -compile({inline,'erlang_++'/3}). 'erlang_++'(A, B, _TrUserData) -> A ++ B. get_msg_defs() -> [{{enum, 'RetirementReason'}, [{'RETIRED_OTHER', 0}, {'RETIRED_INVALID', 1}, {'RETIRED_SECURITY', 2}, {'RETIRED_DEPRECATED', 3}, {'RETIRED_RENAMED', 4}]}, {{msg, 'Package'}, [#{name => releases, fnum => 1, rnum => 2, type => {msg, 'Release'}, occurrence => repeated, opts => []}, #{name => name, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []}, #{name => repository, fnum => 3, rnum => 4, type => string, occurrence => required, opts => []}]}, {{msg, 'Release'}, [#{name => version, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []}, #{name => inner_checksum, fnum => 2, rnum => 3, type => bytes, occurrence => required, opts => []}, #{name => dependencies, fnum => 3, rnum => 4, type => {msg, 'Dependency'}, occurrence => repeated, opts => []}, #{name => retired, fnum => 4, rnum => 5, type => {msg, 'RetirementStatus'}, occurrence => optional, opts => []}, #{name => outer_checksum, fnum => 5, rnum => 6, type => bytes, occurrence => optional, opts => []}]}, {{msg, 'RetirementStatus'}, [#{name => reason, fnum => 1, rnum => 2, type => {enum, 'RetirementReason'}, occurrence => required, opts => []}, #{name => message, fnum => 2, rnum => 3, type => string, occurrence => optional, opts => []}]}, {{msg, 'Dependency'}, [#{name => package, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []}, #{name => requirement, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []}, #{name => optional, fnum => 3, rnum => 4, type => bool, occurrence => optional, opts => []}, #{name => app, fnum => 4, rnum => 5, type => string, occurrence => optional, opts => []}, #{name => repository, fnum => 5, rnum => 6, type => string, occurrence => optional, opts => []}]}]. get_msg_names() -> ['Package', 'Release', 'RetirementStatus', 'Dependency']. get_group_names() -> []. get_msg_or_group_names() -> ['Package', 'Release', 'RetirementStatus', 'Dependency']. get_enum_names() -> ['RetirementReason']. fetch_msg_def(MsgName) -> case find_msg_def(MsgName) of Fs when is_list(Fs) -> Fs; error -> erlang:error({no_such_msg, MsgName}) end. fetch_enum_def(EnumName) -> case find_enum_def(EnumName) of Es when is_list(Es) -> Es; error -> erlang:error({no_such_enum, EnumName}) end. find_msg_def('Package') -> [#{name => releases, fnum => 1, rnum => 2, type => {msg, 'Release'}, occurrence => repeated, opts => []}, #{name => name, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []}, #{name => repository, fnum => 3, rnum => 4, type => string, occurrence => required, opts => []}]; find_msg_def('Release') -> [#{name => version, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []}, #{name => inner_checksum, fnum => 2, rnum => 3, type => bytes, occurrence => required, opts => []}, #{name => dependencies, fnum => 3, rnum => 4, type => {msg, 'Dependency'}, occurrence => repeated, opts => []}, #{name => retired, fnum => 4, rnum => 5, type => {msg, 'RetirementStatus'}, occurrence => optional, opts => []}, #{name => outer_checksum, fnum => 5, rnum => 6, type => bytes, occurrence => optional, opts => []}]; find_msg_def('RetirementStatus') -> [#{name => reason, fnum => 1, rnum => 2, type => {enum, 'RetirementReason'}, occurrence => required, opts => []}, #{name => message, fnum => 2, rnum => 3, type => string, occurrence => optional, opts => []}]; find_msg_def('Dependency') -> [#{name => package, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []}, #{name => requirement, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []}, #{name => optional, fnum => 3, rnum => 4, type => bool, occurrence => optional, opts => []}, #{name => app, fnum => 4, rnum => 5, type => string, occurrence => optional, opts => []}, #{name => repository, fnum => 5, rnum => 6, type => string, occurrence => optional, opts => []}]; find_msg_def(_) -> error. find_enum_def('RetirementReason') -> [{'RETIRED_OTHER', 0}, {'RETIRED_INVALID', 1}, {'RETIRED_SECURITY', 2}, {'RETIRED_DEPRECATED', 3}, {'RETIRED_RENAMED', 4}]; find_enum_def(_) -> error. enum_symbol_by_value('RetirementReason', Value) -> enum_symbol_by_value_RetirementReason(Value). enum_value_by_symbol('RetirementReason', Sym) -> enum_value_by_symbol_RetirementReason(Sym). enum_symbol_by_value_RetirementReason(0) -> 'RETIRED_OTHER'; enum_symbol_by_value_RetirementReason(1) -> 'RETIRED_INVALID'; enum_symbol_by_value_RetirementReason(2) -> 'RETIRED_SECURITY'; enum_symbol_by_value_RetirementReason(3) -> 'RETIRED_DEPRECATED'; enum_symbol_by_value_RetirementReason(4) -> 'RETIRED_RENAMED'. enum_value_by_symbol_RetirementReason('RETIRED_OTHER') -> 0; enum_value_by_symbol_RetirementReason('RETIRED_INVALID') -> 1; enum_value_by_symbol_RetirementReason('RETIRED_SECURITY') -> 2; enum_value_by_symbol_RetirementReason('RETIRED_DEPRECATED') -> 3; enum_value_by_symbol_RetirementReason('RETIRED_RENAMED') -> 4. get_service_names() -> []. get_service_def(_) -> error. get_rpc_names(_) -> error. find_rpc_def(_, _) -> error. -spec fetch_rpc_def(_, _) -> no_return(). fetch_rpc_def(ServiceName, RpcName) -> erlang:error({no_such_rpc, ServiceName, RpcName}). %% Convert a a fully qualified (ie with package name) service name %% as a binary to a service name as an atom. -spec fqbin_to_service_name(_) -> no_return(). fqbin_to_service_name(X) -> error({gpb_error, {badservice, X}}). %% Convert a service name as an atom to a fully qualified %% (ie with package name) name as a binary. -spec service_name_to_fqbin(_) -> no_return(). service_name_to_fqbin(X) -> error({gpb_error, {badservice, X}}). %% Convert a a fully qualified (ie with package name) service name %% and an rpc name, both as binaries to a service name and an rpc %% name, as atoms. -spec fqbins_to_service_and_rpc_name(_, _) -> no_return(). fqbins_to_service_and_rpc_name(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). %% Convert a service name and an rpc name, both as atoms, %% to a fully qualified (ie with package name) service name and %% an rpc name as binaries. -spec service_and_rpc_name_to_fqbins(_, _) -> no_return(). service_and_rpc_name_to_fqbins(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). fqbin_to_msg_name(<<"Package">>) -> 'Package'; fqbin_to_msg_name(<<"Release">>) -> 'Release'; fqbin_to_msg_name(<<"RetirementStatus">>) -> 'RetirementStatus'; fqbin_to_msg_name(<<"Dependency">>) -> 'Dependency'; fqbin_to_msg_name(E) -> error({gpb_error, {badmsg, E}}). msg_name_to_fqbin('Package') -> <<"Package">>; msg_name_to_fqbin('Release') -> <<"Release">>; msg_name_to_fqbin('RetirementStatus') -> <<"RetirementStatus">>; msg_name_to_fqbin('Dependency') -> <<"Dependency">>; msg_name_to_fqbin(E) -> error({gpb_error, {badmsg, E}}). fqbin_to_enum_name(<<"RetirementReason">>) -> 'RetirementReason'; fqbin_to_enum_name(E) -> error({gpb_error, {badenum, E}}). enum_name_to_fqbin('RetirementReason') -> <<"RetirementReason">>; enum_name_to_fqbin(E) -> error({gpb_error, {badenum, E}}). get_package_name() -> undefined. %% Whether or not the message names %% are prepended with package name or not. uses_packages() -> false. source_basename() -> "mix_hex_pb_package.proto". %% Retrieve all proto file names, also imported ones. %% The order is top-down. The first element is always the main %% source file. The files are returned with extension, %% see get_all_proto_names/0 for a version that returns %% the basenames sans extension get_all_source_basenames() -> ["mix_hex_pb_package.proto"]. %% Retrieve all proto file names, also imported ones. %% The order is top-down. The first element is always the main %% source file. The files are returned sans .proto extension, %% to make it easier to use them with the various get_xyz_containment %% functions. get_all_proto_names() -> ["mix_hex_pb_package"]. get_msg_containment("mix_hex_pb_package") -> ['Dependency', 'Package', 'Release', 'RetirementStatus']; get_msg_containment(P) -> error({gpb_error, {badproto, P}}). get_pkg_containment("mix_hex_pb_package") -> undefined; get_pkg_containment(P) -> error({gpb_error, {badproto, P}}). get_service_containment("mix_hex_pb_package") -> []; get_service_containment(P) -> error({gpb_error, {badproto, P}}). get_rpc_containment("mix_hex_pb_package") -> []; get_rpc_containment(P) -> error({gpb_error, {badproto, P}}). get_enum_containment("mix_hex_pb_package") -> ['RetirementReason']; get_enum_containment(P) -> error({gpb_error, {badproto, P}}). get_proto_by_msg_name_as_fqbin(<<"RetirementStatus">>) -> "mix_hex_pb_package"; get_proto_by_msg_name_as_fqbin(<<"Release">>) -> "mix_hex_pb_package"; get_proto_by_msg_name_as_fqbin(<<"Package">>) -> "mix_hex_pb_package"; get_proto_by_msg_name_as_fqbin(<<"Dependency">>) -> "mix_hex_pb_package"; get_proto_by_msg_name_as_fqbin(E) -> error({gpb_error, {badmsg, E}}). -spec get_proto_by_service_name_as_fqbin(_) -> no_return(). get_proto_by_service_name_as_fqbin(E) -> error({gpb_error, {badservice, E}}). get_proto_by_enum_name_as_fqbin(<<"RetirementReason">>) -> "mix_hex_pb_package"; get_proto_by_enum_name_as_fqbin(E) -> error({gpb_error, {badenum, E}}). -spec get_protos_by_pkg_name_as_fqbin(_) -> no_return(). get_protos_by_pkg_name_as_fqbin(E) -> error({gpb_error, {badpkg, E}}). gpb_version_as_string() -> "4.17.6". gpb_version_as_list() -> [4,17,6]. gpb_version_source() -> "file". hex-2.0.6/src/mix_hex_pb_signed.erl000066400000000000000000000540201437023760000172540ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% -*- coding: utf-8 -*- %% @private %% Automatically generated, do not edit %% Generated by gpb_compile version 4.17.6 %% Version source: file -module(mix_hex_pb_signed). -export([encode_msg/2, encode_msg/3]). -export([decode_msg/2, decode_msg/3]). -export([merge_msgs/3, merge_msgs/4]). -export([verify_msg/2, verify_msg/3]). -export([get_msg_defs/0]). -export([get_msg_names/0]). -export([get_group_names/0]). -export([get_msg_or_group_names/0]). -export([get_enum_names/0]). -export([find_msg_def/1, fetch_msg_def/1]). -export([find_enum_def/1, fetch_enum_def/1]). -export([enum_symbol_by_value/2, enum_value_by_symbol/2]). -export([get_service_names/0]). -export([get_service_def/1]). -export([get_rpc_names/1]). -export([find_rpc_def/2, fetch_rpc_def/2]). -export([fqbin_to_service_name/1]). -export([service_name_to_fqbin/1]). -export([fqbins_to_service_and_rpc_name/2]). -export([service_and_rpc_name_to_fqbins/2]). -export([fqbin_to_msg_name/1]). -export([msg_name_to_fqbin/1]). -export([fqbin_to_enum_name/1]). -export([enum_name_to_fqbin/1]). -export([get_package_name/0]). -export([uses_packages/0]). -export([source_basename/0]). -export([get_all_source_basenames/0]). -export([get_all_proto_names/0]). -export([get_msg_containment/1]). -export([get_pkg_containment/1]). -export([get_service_containment/1]). -export([get_rpc_containment/1]). -export([get_enum_containment/1]). -export([get_proto_by_msg_name_as_fqbin/1]). -export([get_proto_by_service_name_as_fqbin/1]). -export([get_proto_by_enum_name_as_fqbin/1]). -export([get_protos_by_pkg_name_as_fqbin/1]). -export([gpb_version_as_string/0, gpb_version_as_list/0]). -export([gpb_version_source/0]). %% enumerated types -export_type([]). %% message types -type 'Signed'() :: #{payload => iodata(), % = 1, required signature => iodata() % = 2, optional }. -export_type(['Signed'/0]). -type '$msg_name'() :: 'Signed'. -type '$msg'() :: 'Signed'(). -export_type(['$msg_name'/0, '$msg'/0]). -spec encode_msg('$msg'(), '$msg_name'()) -> binary(). encode_msg(Msg, MsgName) when is_atom(MsgName) -> encode_msg(Msg, MsgName, []). -spec encode_msg('$msg'(), '$msg_name'(), list()) -> binary(). encode_msg(Msg, MsgName, Opts) -> verify_msg(Msg, MsgName, Opts), TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Signed' -> encode_msg_Signed(id(Msg, TrUserData), TrUserData) end. encode_msg_Signed(Msg, TrUserData) -> encode_msg_Signed(Msg, <<>>, TrUserData). encode_msg_Signed(#{payload := F1} = M, Bin, TrUserData) -> B1 = begin TrF1 = id(F1, TrUserData), e_type_bytes(TrF1, <>, TrUserData) end, case M of #{signature := F2} -> begin TrF2 = id(F2, TrUserData), e_type_bytes(TrF2, <>, TrUserData) end; _ -> B1 end. -compile({nowarn_unused_function,e_type_sint/3}). e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> e_varint(Value * 2, Bin); e_type_sint(Value, Bin, _TrUserData) -> e_varint(Value * -2 - 1, Bin). -compile({nowarn_unused_function,e_type_int32/3}). e_type_int32(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; e_type_int32(Value, Bin, _TrUserData) -> <> = <>, e_varint(N, Bin). -compile({nowarn_unused_function,e_type_int64/3}). e_type_int64(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; e_type_int64(Value, Bin, _TrUserData) -> <> = <>, e_varint(N, Bin). -compile({nowarn_unused_function,e_type_bool/3}). e_type_bool(true, Bin, _TrUserData) -> <>; e_type_bool(false, Bin, _TrUserData) -> <>; e_type_bool(1, Bin, _TrUserData) -> <>; e_type_bool(0, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_string/3}). e_type_string(S, Bin, _TrUserData) -> Utf8 = unicode:characters_to_binary(S), Bin2 = e_varint(byte_size(Utf8), Bin), <>. -compile({nowarn_unused_function,e_type_bytes/3}). e_type_bytes(Bytes, Bin, _TrUserData) when is_binary(Bytes) -> Bin2 = e_varint(byte_size(Bytes), Bin), <>; e_type_bytes(Bytes, Bin, _TrUserData) when is_list(Bytes) -> BytesBin = iolist_to_binary(Bytes), Bin2 = e_varint(byte_size(BytesBin), Bin), <>. -compile({nowarn_unused_function,e_type_fixed32/3}). e_type_fixed32(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_sfixed32/3}). e_type_sfixed32(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_fixed64/3}). e_type_fixed64(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_sfixed64/3}). e_type_sfixed64(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_float/3}). e_type_float(V, Bin, _) when is_number(V) -> <>; e_type_float(infinity, Bin, _) -> <>; e_type_float('-infinity', Bin, _) -> <>; e_type_float(nan, Bin, _) -> <>. -compile({nowarn_unused_function,e_type_double/3}). e_type_double(V, Bin, _) when is_number(V) -> <>; e_type_double(infinity, Bin, _) -> <>; e_type_double('-infinity', Bin, _) -> <>; e_type_double(nan, Bin, _) -> <>. -compile({nowarn_unused_function,e_unknown_elems/2}). e_unknown_elems([Elem | Rest], Bin) -> BinR = case Elem of {varint, FNum, N} -> BinF = e_varint(FNum bsl 3, Bin), e_varint(N, BinF); {length_delimited, FNum, Data} -> BinF = e_varint(FNum bsl 3 bor 2, Bin), BinL = e_varint(byte_size(Data), BinF), <>; {group, FNum, GroupFields} -> Bin1 = e_varint(FNum bsl 3 bor 3, Bin), Bin2 = e_unknown_elems(GroupFields, Bin1), e_varint(FNum bsl 3 bor 4, Bin2); {fixed32, FNum, V} -> BinF = e_varint(FNum bsl 3 bor 5, Bin), <>; {fixed64, FNum, V} -> BinF = e_varint(FNum bsl 3 bor 1, Bin), <> end, e_unknown_elems(Rest, BinR); e_unknown_elems([], Bin) -> Bin. -compile({nowarn_unused_function,e_varint/3}). e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin). -compile({nowarn_unused_function,e_varint/2}). e_varint(N, Bin) when N =< 127 -> <>; e_varint(N, Bin) -> Bin2 = <>, e_varint(N bsr 7, Bin2). decode_msg(Bin, MsgName) when is_binary(Bin) -> decode_msg(Bin, MsgName, []). decode_msg(Bin, MsgName, Opts) when is_binary(Bin) -> TrUserData = proplists:get_value(user_data, Opts), decode_msg_1_catch(Bin, MsgName, TrUserData). -ifdef('OTP_RELEASE'). decode_msg_1_catch(Bin, MsgName, TrUserData) -> try decode_msg_2_doit(MsgName, Bin, TrUserData) catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) end. -else. decode_msg_1_catch(Bin, MsgName, TrUserData) -> try decode_msg_2_doit(MsgName, Bin, TrUserData) catch Class:Reason -> StackTrace = erlang:get_stacktrace(), error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) end. -endif. decode_msg_2_doit('Signed', Bin, TrUserData) -> id(decode_msg_Signed(Bin, TrUserData), TrUserData). decode_msg_Signed(Bin, TrUserData) -> dfp_read_field_def_Signed(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), TrUserData). dfp_read_field_def_Signed(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Signed_payload(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Signed(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Signed_signature(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Signed(<<>>, 0, 0, _, F@_1, F@_2, _) -> S1 = #{payload => F@_1}, if F@_2 == '$undef' -> S1; true -> S1#{signature => F@_2} end; dfp_read_field_def_Signed(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_Signed(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). dg_read_field_def_Signed(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_Signed(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); dg_read_field_def_Signed(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> Key = X bsl N + Acc, case Key of 10 -> d_field_Signed_payload(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); 18 -> d_field_Signed_signature(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_Signed(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 1 -> skip_64_Signed(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 2 -> skip_length_delimited_Signed(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 3 -> skip_group_Signed(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 5 -> skip_32_Signed(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) end end; dg_read_field_def_Signed(<<>>, 0, 0, _, F@_1, F@_2, _) -> S1 = #{payload => F@_1}, if F@_2 == '$undef' -> S1; true -> S1#{signature => F@_2} end. d_field_Signed_payload(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Signed_payload(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Signed_payload(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Signed(RestF, 0, 0, F, NewFValue, F@_2, TrUserData). d_field_Signed_signature(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Signed_signature(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Signed_signature(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Signed(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). skip_varint_Signed(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_Signed(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); skip_varint_Signed(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Signed(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_length_delimited_Signed(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_Signed(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); skip_length_delimited_Signed(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_Signed(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). skip_group_Signed(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_Signed(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). skip_32_Signed(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Signed(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_64_Signed(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Signed(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). read_group(Bin, FieldNum) -> {NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum), <> = Bin, {Group, Rest}. %% Like skipping over fields, but record the total length, %% Each field is <(FieldNum bsl 3) bor FieldType> ++ %% Record the length because varints may be non-optimally encoded. %% %% Groups can be nested, but assume the same FieldNum cannot be nested %% because group field numbers are shared with the rest of the fields %% numbers. Thus we can search just for an group-end with the same %% field number. %% %% (The only time the same group field number could occur would %% be in a nested sub message, but then it would be inside a %% length-delimited entry, which we skip-read by length.) read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) when N < (32-7) -> read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum); read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) -> Key = X bsl N + Acc, TagLen1 = TagLen + 1, case {Key bsr 3, Key band 7} of {FieldNum, 4} -> % 4 = group_end {NumBytes, TagLen1}; {_, 0} -> % 0 = varint read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum); {_, 1} -> % 1 = bits64 <<_:64, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum); {_, 2} -> % 2 = length_delimited read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum); {_, 3} -> % 3 = group_start read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); {_, 4} -> % 4 = group_end read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); {_, 5} -> % 5 = bits32 <<_:32, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum) end. read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum) when N < (64-7) -> read_gr_vi(Tl, N+7, NumBytes+1, FieldNum); read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) -> read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum). read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) when N < (64-7) -> read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum); read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) -> Len = X bsl N + Acc, NumBytes1 = NumBytes + 1, <<_:Len/binary, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum). merge_msgs(Prev, New, MsgName) when is_atom(MsgName) -> merge_msgs(Prev, New, MsgName, []). merge_msgs(Prev, New, MsgName, Opts) -> TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Signed' -> merge_msg_Signed(Prev, New, TrUserData) end. -compile({nowarn_unused_function,merge_msg_Signed/3}). merge_msg_Signed(#{} = PMsg, #{payload := NFpayload} = NMsg, _) -> S1 = #{payload => NFpayload}, case {PMsg, NMsg} of {_, #{signature := NFsignature}} -> S1#{signature => NFsignature}; {#{signature := PFsignature}, _} -> S1#{signature => PFsignature}; _ -> S1 end. verify_msg(Msg, MsgName) when is_atom(MsgName) -> verify_msg(Msg, MsgName, []). verify_msg(Msg, MsgName, Opts) -> TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Signed' -> v_msg_Signed(Msg, [MsgName], TrUserData); _ -> mk_type_error(not_a_known_message, Msg, []) end. -compile({nowarn_unused_function,v_msg_Signed/3}). v_msg_Signed(#{payload := F1} = M, Path, TrUserData) -> v_type_bytes(F1, [payload | Path], TrUserData), case M of #{signature := F2} -> v_type_bytes(F2, [signature | Path], TrUserData); _ -> ok end, lists:foreach(fun (payload) -> ok; (signature) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_Signed(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [payload] -- maps:keys(M), 'Signed'}, M, Path); v_msg_Signed(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Signed'}, X, Path). -compile({nowarn_unused_function,v_type_bytes/3}). v_type_bytes(B, _Path, _TrUserData) when is_binary(B) -> ok; v_type_bytes(B, _Path, _TrUserData) when is_list(B) -> ok; v_type_bytes(X, Path, _TrUserData) -> mk_type_error(bad_binary_value, X, Path). -compile({nowarn_unused_function,mk_type_error/3}). -spec mk_type_error(_, _, list()) -> no_return(). mk_type_error(Error, ValueSeen, Path) -> Path2 = prettify_path(Path), erlang:error({gpb_type_error, {Error, [{value, ValueSeen}, {path, Path2}]}}). -compile({nowarn_unused_function,prettify_path/1}). prettify_path([]) -> top_level; prettify_path(PathR) -> string:join(lists:map(fun atom_to_list/1, lists:reverse(PathR)), "."). -compile({nowarn_unused_function,id/2}). -compile({inline,id/2}). id(X, _TrUserData) -> X. -compile({nowarn_unused_function,v_ok/3}). -compile({inline,v_ok/3}). v_ok(_Value, _Path, _TrUserData) -> ok. -compile({nowarn_unused_function,m_overwrite/3}). -compile({inline,m_overwrite/3}). m_overwrite(_Prev, New, _TrUserData) -> New. -compile({nowarn_unused_function,cons/3}). -compile({inline,cons/3}). cons(Elem, Acc, _TrUserData) -> [Elem | Acc]. -compile({nowarn_unused_function,lists_reverse/2}). -compile({inline,lists_reverse/2}). 'lists_reverse'(L, _TrUserData) -> lists:reverse(L). -compile({nowarn_unused_function,'erlang_++'/3}). -compile({inline,'erlang_++'/3}). 'erlang_++'(A, B, _TrUserData) -> A ++ B. get_msg_defs() -> [{{msg, 'Signed'}, [#{name => payload, fnum => 1, rnum => 2, type => bytes, occurrence => required, opts => []}, #{name => signature, fnum => 2, rnum => 3, type => bytes, occurrence => optional, opts => []}]}]. get_msg_names() -> ['Signed']. get_group_names() -> []. get_msg_or_group_names() -> ['Signed']. get_enum_names() -> []. fetch_msg_def(MsgName) -> case find_msg_def(MsgName) of Fs when is_list(Fs) -> Fs; error -> erlang:error({no_such_msg, MsgName}) end. -spec fetch_enum_def(_) -> no_return(). fetch_enum_def(EnumName) -> erlang:error({no_such_enum, EnumName}). find_msg_def('Signed') -> [#{name => payload, fnum => 1, rnum => 2, type => bytes, occurrence => required, opts => []}, #{name => signature, fnum => 2, rnum => 3, type => bytes, occurrence => optional, opts => []}]; find_msg_def(_) -> error. find_enum_def(_) -> error. -spec enum_symbol_by_value(_, _) -> no_return(). enum_symbol_by_value(E, V) -> erlang:error({no_enum_defs, E, V}). -spec enum_value_by_symbol(_, _) -> no_return(). enum_value_by_symbol(E, V) -> erlang:error({no_enum_defs, E, V}). get_service_names() -> []. get_service_def(_) -> error. get_rpc_names(_) -> error. find_rpc_def(_, _) -> error. -spec fetch_rpc_def(_, _) -> no_return(). fetch_rpc_def(ServiceName, RpcName) -> erlang:error({no_such_rpc, ServiceName, RpcName}). %% Convert a a fully qualified (ie with package name) service name %% as a binary to a service name as an atom. -spec fqbin_to_service_name(_) -> no_return(). fqbin_to_service_name(X) -> error({gpb_error, {badservice, X}}). %% Convert a service name as an atom to a fully qualified %% (ie with package name) name as a binary. -spec service_name_to_fqbin(_) -> no_return(). service_name_to_fqbin(X) -> error({gpb_error, {badservice, X}}). %% Convert a a fully qualified (ie with package name) service name %% and an rpc name, both as binaries to a service name and an rpc %% name, as atoms. -spec fqbins_to_service_and_rpc_name(_, _) -> no_return(). fqbins_to_service_and_rpc_name(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). %% Convert a service name and an rpc name, both as atoms, %% to a fully qualified (ie with package name) service name and %% an rpc name as binaries. -spec service_and_rpc_name_to_fqbins(_, _) -> no_return(). service_and_rpc_name_to_fqbins(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). fqbin_to_msg_name(<<"Signed">>) -> 'Signed'; fqbin_to_msg_name(E) -> error({gpb_error, {badmsg, E}}). msg_name_to_fqbin('Signed') -> <<"Signed">>; msg_name_to_fqbin(E) -> error({gpb_error, {badmsg, E}}). -spec fqbin_to_enum_name(_) -> no_return(). fqbin_to_enum_name(E) -> error({gpb_error, {badenum, E}}). -spec enum_name_to_fqbin(_) -> no_return(). enum_name_to_fqbin(E) -> error({gpb_error, {badenum, E}}). get_package_name() -> undefined. %% Whether or not the message names %% are prepended with package name or not. uses_packages() -> false. source_basename() -> "mix_hex_pb_signed.proto". %% Retrieve all proto file names, also imported ones. %% The order is top-down. The first element is always the main %% source file. The files are returned with extension, %% see get_all_proto_names/0 for a version that returns %% the basenames sans extension get_all_source_basenames() -> ["mix_hex_pb_signed.proto"]. %% Retrieve all proto file names, also imported ones. %% The order is top-down. The first element is always the main %% source file. The files are returned sans .proto extension, %% to make it easier to use them with the various get_xyz_containment %% functions. get_all_proto_names() -> ["mix_hex_pb_signed"]. get_msg_containment("mix_hex_pb_signed") -> ['Signed']; get_msg_containment(P) -> error({gpb_error, {badproto, P}}). get_pkg_containment("mix_hex_pb_signed") -> undefined; get_pkg_containment(P) -> error({gpb_error, {badproto, P}}). get_service_containment("mix_hex_pb_signed") -> []; get_service_containment(P) -> error({gpb_error, {badproto, P}}). get_rpc_containment("mix_hex_pb_signed") -> []; get_rpc_containment(P) -> error({gpb_error, {badproto, P}}). get_enum_containment("mix_hex_pb_signed") -> []; get_enum_containment(P) -> error({gpb_error, {badproto, P}}). get_proto_by_msg_name_as_fqbin(<<"Signed">>) -> "mix_hex_pb_signed"; get_proto_by_msg_name_as_fqbin(E) -> error({gpb_error, {badmsg, E}}). -spec get_proto_by_service_name_as_fqbin(_) -> no_return(). get_proto_by_service_name_as_fqbin(E) -> error({gpb_error, {badservice, E}}). -spec get_proto_by_enum_name_as_fqbin(_) -> no_return(). get_proto_by_enum_name_as_fqbin(E) -> error({gpb_error, {badenum, E}}). -spec get_protos_by_pkg_name_as_fqbin(_) -> no_return(). get_protos_by_pkg_name_as_fqbin(E) -> error({gpb_error, {badpkg, E}}). gpb_version_as_string() -> "4.17.6". gpb_version_as_list() -> [4,17,6]. gpb_version_source() -> "file". hex-2.0.6/src/mix_hex_pb_versions.erl000066400000000000000000001062071437023760000176600ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% -*- coding: utf-8 -*- %% @private %% Automatically generated, do not edit %% Generated by gpb_compile version 4.17.6 %% Version source: file -module(mix_hex_pb_versions). -export([encode_msg/2, encode_msg/3]). -export([decode_msg/2, decode_msg/3]). -export([merge_msgs/3, merge_msgs/4]). -export([verify_msg/2, verify_msg/3]). -export([get_msg_defs/0]). -export([get_msg_names/0]). -export([get_group_names/0]). -export([get_msg_or_group_names/0]). -export([get_enum_names/0]). -export([find_msg_def/1, fetch_msg_def/1]). -export([find_enum_def/1, fetch_enum_def/1]). -export([enum_symbol_by_value/2, enum_value_by_symbol/2]). -export([get_service_names/0]). -export([get_service_def/1]). -export([get_rpc_names/1]). -export([find_rpc_def/2, fetch_rpc_def/2]). -export([fqbin_to_service_name/1]). -export([service_name_to_fqbin/1]). -export([fqbins_to_service_and_rpc_name/2]). -export([service_and_rpc_name_to_fqbins/2]). -export([fqbin_to_msg_name/1]). -export([msg_name_to_fqbin/1]). -export([fqbin_to_enum_name/1]). -export([enum_name_to_fqbin/1]). -export([get_package_name/0]). -export([uses_packages/0]). -export([source_basename/0]). -export([get_all_source_basenames/0]). -export([get_all_proto_names/0]). -export([get_msg_containment/1]). -export([get_pkg_containment/1]). -export([get_service_containment/1]). -export([get_rpc_containment/1]). -export([get_enum_containment/1]). -export([get_proto_by_msg_name_as_fqbin/1]). -export([get_proto_by_service_name_as_fqbin/1]). -export([get_proto_by_enum_name_as_fqbin/1]). -export([get_protos_by_pkg_name_as_fqbin/1]). -export([gpb_version_as_string/0, gpb_version_as_list/0]). -export([gpb_version_source/0]). %% enumerated types -export_type([]). %% message types -type 'Versions'() :: #{packages => ['Package'()], % = 1, repeated repository => unicode:chardata() % = 2, required }. -type 'Package'() :: #{name => unicode:chardata(), % = 1, required versions => [unicode:chardata()], % = 2, repeated retired => [integer()] % = 3, repeated, 32 bits }. -export_type(['Versions'/0, 'Package'/0]). -type '$msg_name'() :: 'Versions' | 'Package'. -type '$msg'() :: 'Versions'() | 'Package'(). -export_type(['$msg_name'/0, '$msg'/0]). -spec encode_msg('$msg'(), '$msg_name'()) -> binary(). encode_msg(Msg, MsgName) when is_atom(MsgName) -> encode_msg(Msg, MsgName, []). -spec encode_msg('$msg'(), '$msg_name'(), list()) -> binary(). encode_msg(Msg, MsgName, Opts) -> verify_msg(Msg, MsgName, Opts), TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Versions' -> encode_msg_Versions(id(Msg, TrUserData), TrUserData); 'Package' -> encode_msg_Package(id(Msg, TrUserData), TrUserData) end. encode_msg_Versions(Msg, TrUserData) -> encode_msg_Versions(Msg, <<>>, TrUserData). encode_msg_Versions(#{repository := F2} = M, Bin, TrUserData) -> B1 = case M of #{packages := F1} -> TrF1 = id(F1, TrUserData), if TrF1 == [] -> Bin; true -> e_field_Versions_packages(TrF1, Bin, TrUserData) end; _ -> Bin end, begin TrF2 = id(F2, TrUserData), e_type_string(TrF2, <>, TrUserData) end. encode_msg_Package(Msg, TrUserData) -> encode_msg_Package(Msg, <<>>, TrUserData). encode_msg_Package(#{name := F1} = M, Bin, TrUserData) -> B1 = begin TrF1 = id(F1, TrUserData), e_type_string(TrF1, <>, TrUserData) end, B2 = case M of #{versions := F2} -> TrF2 = id(F2, TrUserData), if TrF2 == [] -> B1; true -> e_field_Package_versions(TrF2, B1, TrUserData) end; _ -> B1 end, case M of #{retired := F3} -> TrF3 = id(F3, TrUserData), if TrF3 == [] -> B2; true -> e_field_Package_retired(TrF3, B2, TrUserData) end; _ -> B2 end. e_mfield_Versions_packages(Msg, Bin, TrUserData) -> SubBin = encode_msg_Package(Msg, <<>>, TrUserData), Bin2 = e_varint(byte_size(SubBin), Bin), <>. e_field_Versions_packages([Elem | Rest], Bin, TrUserData) -> Bin2 = <>, Bin3 = e_mfield_Versions_packages(id(Elem, TrUserData), Bin2, TrUserData), e_field_Versions_packages(Rest, Bin3, TrUserData); e_field_Versions_packages([], Bin, _TrUserData) -> Bin. e_field_Package_versions([Elem | Rest], Bin, TrUserData) -> Bin2 = <>, Bin3 = e_type_string(id(Elem, TrUserData), Bin2, TrUserData), e_field_Package_versions(Rest, Bin3, TrUserData); e_field_Package_versions([], Bin, _TrUserData) -> Bin. e_field_Package_retired(Elems, Bin, TrUserData) when Elems =/= [] -> SubBin = e_pfield_Package_retired(Elems, <<>>, TrUserData), Bin2 = <>, Bin3 = e_varint(byte_size(SubBin), Bin2), <>; e_field_Package_retired([], Bin, _TrUserData) -> Bin. e_pfield_Package_retired([Value | Rest], Bin, TrUserData) -> Bin2 = e_type_int32(id(Value, TrUserData), Bin, TrUserData), e_pfield_Package_retired(Rest, Bin2, TrUserData); e_pfield_Package_retired([], Bin, _TrUserData) -> Bin. -compile({nowarn_unused_function,e_type_sint/3}). e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> e_varint(Value * 2, Bin); e_type_sint(Value, Bin, _TrUserData) -> e_varint(Value * -2 - 1, Bin). -compile({nowarn_unused_function,e_type_int32/3}). e_type_int32(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; e_type_int32(Value, Bin, _TrUserData) -> <> = <>, e_varint(N, Bin). -compile({nowarn_unused_function,e_type_int64/3}). e_type_int64(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; e_type_int64(Value, Bin, _TrUserData) -> <> = <>, e_varint(N, Bin). -compile({nowarn_unused_function,e_type_bool/3}). e_type_bool(true, Bin, _TrUserData) -> <>; e_type_bool(false, Bin, _TrUserData) -> <>; e_type_bool(1, Bin, _TrUserData) -> <>; e_type_bool(0, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_string/3}). e_type_string(S, Bin, _TrUserData) -> Utf8 = unicode:characters_to_binary(S), Bin2 = e_varint(byte_size(Utf8), Bin), <>. -compile({nowarn_unused_function,e_type_bytes/3}). e_type_bytes(Bytes, Bin, _TrUserData) when is_binary(Bytes) -> Bin2 = e_varint(byte_size(Bytes), Bin), <>; e_type_bytes(Bytes, Bin, _TrUserData) when is_list(Bytes) -> BytesBin = iolist_to_binary(Bytes), Bin2 = e_varint(byte_size(BytesBin), Bin), <>. -compile({nowarn_unused_function,e_type_fixed32/3}). e_type_fixed32(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_sfixed32/3}). e_type_sfixed32(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_fixed64/3}). e_type_fixed64(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_sfixed64/3}). e_type_sfixed64(Value, Bin, _TrUserData) -> <>. -compile({nowarn_unused_function,e_type_float/3}). e_type_float(V, Bin, _) when is_number(V) -> <>; e_type_float(infinity, Bin, _) -> <>; e_type_float('-infinity', Bin, _) -> <>; e_type_float(nan, Bin, _) -> <>. -compile({nowarn_unused_function,e_type_double/3}). e_type_double(V, Bin, _) when is_number(V) -> <>; e_type_double(infinity, Bin, _) -> <>; e_type_double('-infinity', Bin, _) -> <>; e_type_double(nan, Bin, _) -> <>. -compile({nowarn_unused_function,e_unknown_elems/2}). e_unknown_elems([Elem | Rest], Bin) -> BinR = case Elem of {varint, FNum, N} -> BinF = e_varint(FNum bsl 3, Bin), e_varint(N, BinF); {length_delimited, FNum, Data} -> BinF = e_varint(FNum bsl 3 bor 2, Bin), BinL = e_varint(byte_size(Data), BinF), <>; {group, FNum, GroupFields} -> Bin1 = e_varint(FNum bsl 3 bor 3, Bin), Bin2 = e_unknown_elems(GroupFields, Bin1), e_varint(FNum bsl 3 bor 4, Bin2); {fixed32, FNum, V} -> BinF = e_varint(FNum bsl 3 bor 5, Bin), <>; {fixed64, FNum, V} -> BinF = e_varint(FNum bsl 3 bor 1, Bin), <> end, e_unknown_elems(Rest, BinR); e_unknown_elems([], Bin) -> Bin. -compile({nowarn_unused_function,e_varint/3}). e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin). -compile({nowarn_unused_function,e_varint/2}). e_varint(N, Bin) when N =< 127 -> <>; e_varint(N, Bin) -> Bin2 = <>, e_varint(N bsr 7, Bin2). decode_msg(Bin, MsgName) when is_binary(Bin) -> decode_msg(Bin, MsgName, []). decode_msg(Bin, MsgName, Opts) when is_binary(Bin) -> TrUserData = proplists:get_value(user_data, Opts), decode_msg_1_catch(Bin, MsgName, TrUserData). -ifdef('OTP_RELEASE'). decode_msg_1_catch(Bin, MsgName, TrUserData) -> try decode_msg_2_doit(MsgName, Bin, TrUserData) catch Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) end. -else. decode_msg_1_catch(Bin, MsgName, TrUserData) -> try decode_msg_2_doit(MsgName, Bin, TrUserData) catch Class:Reason -> StackTrace = erlang:get_stacktrace(), error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) end. -endif. decode_msg_2_doit('Versions', Bin, TrUserData) -> id(decode_msg_Versions(Bin, TrUserData), TrUserData); decode_msg_2_doit('Package', Bin, TrUserData) -> id(decode_msg_Package(Bin, TrUserData), TrUserData). decode_msg_Versions(Bin, TrUserData) -> dfp_read_field_def_Versions(Bin, 0, 0, 0, id([], TrUserData), id('$undef', TrUserData), TrUserData). dfp_read_field_def_Versions(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Versions_packages(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Versions(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Versions_repository(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); dfp_read_field_def_Versions(<<>>, 0, 0, _, R1, F@_2, TrUserData) -> S1 = #{repository => F@_2}, if R1 == '$undef' -> S1; true -> S1#{packages => lists_reverse(R1, TrUserData)} end; dfp_read_field_def_Versions(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_Versions(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). dg_read_field_def_Versions(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_Versions(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); dg_read_field_def_Versions(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> Key = X bsl N + Acc, case Key of 10 -> d_field_Versions_packages(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); 18 -> d_field_Versions_repository(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_Versions(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 1 -> skip_64_Versions(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 2 -> skip_length_delimited_Versions(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 3 -> skip_group_Versions(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); 5 -> skip_32_Versions(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) end end; dg_read_field_def_Versions(<<>>, 0, 0, _, R1, F@_2, TrUserData) -> S1 = #{repository => F@_2}, if R1 == '$undef' -> S1; true -> S1#{packages => lists_reverse(R1, TrUserData)} end. d_field_Versions_packages(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Versions_packages(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Versions_packages(<<0:1, X:7, Rest/binary>>, N, Acc, F, Prev, F@_2, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_Package(Bs, TrUserData), TrUserData), Rest2} end, dfp_read_field_def_Versions(RestF, 0, 0, F, cons(NewFValue, Prev, TrUserData), F@_2, TrUserData). d_field_Versions_repository(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Versions_repository(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); d_field_Versions_repository(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Versions(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). skip_varint_Versions(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_Versions(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); skip_varint_Versions(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Versions(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_length_delimited_Versions(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_Versions(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); skip_length_delimited_Versions(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_Versions(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). skip_group_Versions(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_Versions(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). skip_32_Versions(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Versions(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). skip_64_Versions(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Versions(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). decode_msg_Package(Bin, TrUserData) -> dfp_read_field_def_Package(Bin, 0, 0, 0, id('$undef', TrUserData), id([], TrUserData), id([], TrUserData), TrUserData). dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_name(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); dfp_read_field_def_Package(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_versions(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); dfp_read_field_def_Package(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_pfield_Package_retired(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); dfp_read_field_def_Package(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_retired(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); dfp_read_field_def_Package(<<>>, 0, 0, _, F@_1, R1, R2, TrUserData) -> #{name => F@_1, versions => lists_reverse(R1, TrUserData), retired => lists_reverse(R2, TrUserData)}; dfp_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) -> Key = X bsl N + Acc, case Key of 10 -> d_field_Package_name(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); 18 -> d_field_Package_versions(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); 26 -> d_pfield_Package_retired(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); 24 -> d_field_Package_retired(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); _ -> case Key band 7 of 0 -> skip_varint_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); 1 -> skip_64_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); 2 -> skip_length_delimited_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); 3 -> skip_group_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); 5 -> skip_32_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData) end end; dg_read_field_def_Package(<<>>, 0, 0, _, F@_1, R1, R2, TrUserData) -> #{name => F@_1, versions => lists_reverse(R1, TrUserData), retired => lists_reverse(R2, TrUserData)}. d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_name(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Package(RestF, 0, 0, F, NewFValue, F@_2, F@_3, TrUserData). d_field_Package_versions(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_versions(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); d_field_Package_versions(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, Prev, F@_3, TrUserData) -> {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, cons(NewFValue, Prev, TrUserData), F@_3, TrUserData). d_field_Package_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_retired(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); d_field_Package_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, Prev, TrUserData) -> {NewFValue, RestF} = {begin <> = <<(X bsl N + Acc):32/unsigned-native>>, id(Res, TrUserData) end, Rest}, dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, F@_2, cons(NewFValue, Prev, TrUserData), TrUserData). d_pfield_Package_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_pfield_Package_retired(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); d_pfield_Package_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, E, TrUserData) -> Len = X bsl N + Acc, <> = Rest, NewSeq = d_packed_field_Package_retired(PackedBytes, 0, 0, F, E, TrUserData), dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, NewSeq, TrUserData). d_packed_field_Package_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, AccSeq, TrUserData) when N < 57 -> d_packed_field_Package_retired(Rest, N + 7, X bsl N + Acc, F, AccSeq, TrUserData); d_packed_field_Package_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, AccSeq, TrUserData) -> {NewFValue, RestF} = {begin <> = <<(X bsl N + Acc):32/unsigned-native>>, id(Res, TrUserData) end, Rest}, d_packed_field_Package_retired(RestF, 0, 0, F, [NewFValue | AccSeq], TrUserData); d_packed_field_Package_retired(<<>>, 0, 0, _, AccSeq, _) -> AccSeq. skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) -> Length = X bsl N + Acc, <<_:Length/binary, Rest2/binary>> = Rest, dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData). skip_group_Package(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) -> {_, Rest} = read_group(Bin, FNum), dfp_read_field_def_Package(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData). skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). read_group(Bin, FieldNum) -> {NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum), <> = Bin, {Group, Rest}. %% Like skipping over fields, but record the total length, %% Each field is <(FieldNum bsl 3) bor FieldType> ++ %% Record the length because varints may be non-optimally encoded. %% %% Groups can be nested, but assume the same FieldNum cannot be nested %% because group field numbers are shared with the rest of the fields %% numbers. Thus we can search just for an group-end with the same %% field number. %% %% (The only time the same group field number could occur would %% be in a nested sub message, but then it would be inside a %% length-delimited entry, which we skip-read by length.) read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) when N < (32-7) -> read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum); read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) -> Key = X bsl N + Acc, TagLen1 = TagLen + 1, case {Key bsr 3, Key band 7} of {FieldNum, 4} -> % 4 = group_end {NumBytes, TagLen1}; {_, 0} -> % 0 = varint read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum); {_, 1} -> % 1 = bits64 <<_:64, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum); {_, 2} -> % 2 = length_delimited read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum); {_, 3} -> % 3 = group_start read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); {_, 4} -> % 4 = group_end read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); {_, 5} -> % 5 = bits32 <<_:32, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum) end. read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum) when N < (64-7) -> read_gr_vi(Tl, N+7, NumBytes+1, FieldNum); read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) -> read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum). read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) when N < (64-7) -> read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum); read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) -> Len = X bsl N + Acc, NumBytes1 = NumBytes + 1, <<_:Len/binary, Tl2/binary>> = Tl, read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum). merge_msgs(Prev, New, MsgName) when is_atom(MsgName) -> merge_msgs(Prev, New, MsgName, []). merge_msgs(Prev, New, MsgName, Opts) -> TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Versions' -> merge_msg_Versions(Prev, New, TrUserData); 'Package' -> merge_msg_Package(Prev, New, TrUserData) end. -compile({nowarn_unused_function,merge_msg_Versions/3}). merge_msg_Versions(#{} = PMsg, #{repository := NFrepository} = NMsg, TrUserData) -> S1 = #{repository => NFrepository}, case {PMsg, NMsg} of {#{packages := PFpackages}, #{packages := NFpackages}} -> S1#{packages => 'erlang_++'(PFpackages, NFpackages, TrUserData)}; {_, #{packages := NFpackages}} -> S1#{packages => NFpackages}; {#{packages := PFpackages}, _} -> S1#{packages => PFpackages}; {_, _} -> S1 end. -compile({nowarn_unused_function,merge_msg_Package/3}). merge_msg_Package(#{} = PMsg, #{name := NFname} = NMsg, TrUserData) -> S1 = #{name => NFname}, S2 = case {PMsg, NMsg} of {#{versions := PFversions}, #{versions := NFversions}} -> S1#{versions => 'erlang_++'(PFversions, NFversions, TrUserData)}; {_, #{versions := NFversions}} -> S1#{versions => NFversions}; {#{versions := PFversions}, _} -> S1#{versions => PFversions}; {_, _} -> S1 end, case {PMsg, NMsg} of {#{retired := PFretired}, #{retired := NFretired}} -> S2#{retired => 'erlang_++'(PFretired, NFretired, TrUserData)}; {_, #{retired := NFretired}} -> S2#{retired => NFretired}; {#{retired := PFretired}, _} -> S2#{retired => PFretired}; {_, _} -> S2 end. verify_msg(Msg, MsgName) when is_atom(MsgName) -> verify_msg(Msg, MsgName, []). verify_msg(Msg, MsgName, Opts) -> TrUserData = proplists:get_value(user_data, Opts), case MsgName of 'Versions' -> v_msg_Versions(Msg, [MsgName], TrUserData); 'Package' -> v_msg_Package(Msg, [MsgName], TrUserData); _ -> mk_type_error(not_a_known_message, Msg, []) end. -compile({nowarn_unused_function,v_msg_Versions/3}). v_msg_Versions(#{repository := F2} = M, Path, TrUserData) -> case M of #{packages := F1} -> if is_list(F1) -> _ = [v_msg_Package(Elem, [packages | Path], TrUserData) || Elem <- F1], ok; true -> mk_type_error({invalid_list_of, {msg, 'Package'}}, F1, [packages | Path]) end; _ -> ok end, v_type_string(F2, [repository | Path], TrUserData), lists:foreach(fun (packages) -> ok; (repository) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_Versions(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [repository] -- maps:keys(M), 'Versions'}, M, Path); v_msg_Versions(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Versions'}, X, Path). -compile({nowarn_unused_function,v_msg_Package/3}). v_msg_Package(#{name := F1} = M, Path, TrUserData) -> v_type_string(F1, [name | Path], TrUserData), case M of #{versions := F2} -> if is_list(F2) -> _ = [v_type_string(Elem, [versions | Path], TrUserData) || Elem <- F2], ok; true -> mk_type_error({invalid_list_of, string}, F2, [versions | Path]) end; _ -> ok end, case M of #{retired := F3} -> if is_list(F3) -> _ = [v_type_int32(Elem, [retired | Path], TrUserData) || Elem <- F3], ok; true -> mk_type_error({invalid_list_of, int32}, F3, [retired | Path]) end; _ -> ok end, lists:foreach(fun (name) -> ok; (versions) -> ok; (retired) -> ok; (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path) end, maps:keys(M)), ok; v_msg_Package(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [name] -- maps:keys(M), 'Package'}, M, Path); v_msg_Package(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Package'}, X, Path). -compile({nowarn_unused_function,v_type_int32/3}). v_type_int32(N, _Path, _TrUserData) when -2147483648 =< N, N =< 2147483647 -> ok; v_type_int32(N, Path, _TrUserData) when is_integer(N) -> mk_type_error({value_out_of_range, int32, signed, 32}, N, Path); v_type_int32(X, Path, _TrUserData) -> mk_type_error({bad_integer, int32, signed, 32}, X, Path). -compile({nowarn_unused_function,v_type_string/3}). v_type_string(S, Path, _TrUserData) when is_list(S); is_binary(S) -> try unicode:characters_to_binary(S) of B when is_binary(B) -> ok; {error, _, _} -> mk_type_error(bad_unicode_string, S, Path) catch error:badarg -> mk_type_error(bad_unicode_string, S, Path) end; v_type_string(X, Path, _TrUserData) -> mk_type_error(bad_unicode_string, X, Path). -compile({nowarn_unused_function,mk_type_error/3}). -spec mk_type_error(_, _, list()) -> no_return(). mk_type_error(Error, ValueSeen, Path) -> Path2 = prettify_path(Path), erlang:error({gpb_type_error, {Error, [{value, ValueSeen}, {path, Path2}]}}). -compile({nowarn_unused_function,prettify_path/1}). prettify_path([]) -> top_level; prettify_path(PathR) -> string:join(lists:map(fun atom_to_list/1, lists:reverse(PathR)), "."). -compile({nowarn_unused_function,id/2}). -compile({inline,id/2}). id(X, _TrUserData) -> X. -compile({nowarn_unused_function,v_ok/3}). -compile({inline,v_ok/3}). v_ok(_Value, _Path, _TrUserData) -> ok. -compile({nowarn_unused_function,m_overwrite/3}). -compile({inline,m_overwrite/3}). m_overwrite(_Prev, New, _TrUserData) -> New. -compile({nowarn_unused_function,cons/3}). -compile({inline,cons/3}). cons(Elem, Acc, _TrUserData) -> [Elem | Acc]. -compile({nowarn_unused_function,lists_reverse/2}). -compile({inline,lists_reverse/2}). 'lists_reverse'(L, _TrUserData) -> lists:reverse(L). -compile({nowarn_unused_function,'erlang_++'/3}). -compile({inline,'erlang_++'/3}). 'erlang_++'(A, B, _TrUserData) -> A ++ B. get_msg_defs() -> [{{msg, 'Versions'}, [#{name => packages, fnum => 1, rnum => 2, type => {msg, 'Package'}, occurrence => repeated, opts => []}, #{name => repository, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []}]}, {{msg, 'Package'}, [#{name => name, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []}, #{name => versions, fnum => 2, rnum => 3, type => string, occurrence => repeated, opts => []}, #{name => retired, fnum => 3, rnum => 4, type => int32, occurrence => repeated, opts => [packed]}]}]. get_msg_names() -> ['Versions', 'Package']. get_group_names() -> []. get_msg_or_group_names() -> ['Versions', 'Package']. get_enum_names() -> []. fetch_msg_def(MsgName) -> case find_msg_def(MsgName) of Fs when is_list(Fs) -> Fs; error -> erlang:error({no_such_msg, MsgName}) end. -spec fetch_enum_def(_) -> no_return(). fetch_enum_def(EnumName) -> erlang:error({no_such_enum, EnumName}). find_msg_def('Versions') -> [#{name => packages, fnum => 1, rnum => 2, type => {msg, 'Package'}, occurrence => repeated, opts => []}, #{name => repository, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []}]; find_msg_def('Package') -> [#{name => name, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []}, #{name => versions, fnum => 2, rnum => 3, type => string, occurrence => repeated, opts => []}, #{name => retired, fnum => 3, rnum => 4, type => int32, occurrence => repeated, opts => [packed]}]; find_msg_def(_) -> error. find_enum_def(_) -> error. -spec enum_symbol_by_value(_, _) -> no_return(). enum_symbol_by_value(E, V) -> erlang:error({no_enum_defs, E, V}). -spec enum_value_by_symbol(_, _) -> no_return(). enum_value_by_symbol(E, V) -> erlang:error({no_enum_defs, E, V}). get_service_names() -> []. get_service_def(_) -> error. get_rpc_names(_) -> error. find_rpc_def(_, _) -> error. -spec fetch_rpc_def(_, _) -> no_return(). fetch_rpc_def(ServiceName, RpcName) -> erlang:error({no_such_rpc, ServiceName, RpcName}). %% Convert a a fully qualified (ie with package name) service name %% as a binary to a service name as an atom. -spec fqbin_to_service_name(_) -> no_return(). fqbin_to_service_name(X) -> error({gpb_error, {badservice, X}}). %% Convert a service name as an atom to a fully qualified %% (ie with package name) name as a binary. -spec service_name_to_fqbin(_) -> no_return(). service_name_to_fqbin(X) -> error({gpb_error, {badservice, X}}). %% Convert a a fully qualified (ie with package name) service name %% and an rpc name, both as binaries to a service name and an rpc %% name, as atoms. -spec fqbins_to_service_and_rpc_name(_, _) -> no_return(). fqbins_to_service_and_rpc_name(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). %% Convert a service name and an rpc name, both as atoms, %% to a fully qualified (ie with package name) service name and %% an rpc name as binaries. -spec service_and_rpc_name_to_fqbins(_, _) -> no_return(). service_and_rpc_name_to_fqbins(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). fqbin_to_msg_name(<<"Versions">>) -> 'Versions'; fqbin_to_msg_name(<<"Package">>) -> 'Package'; fqbin_to_msg_name(E) -> error({gpb_error, {badmsg, E}}). msg_name_to_fqbin('Versions') -> <<"Versions">>; msg_name_to_fqbin('Package') -> <<"Package">>; msg_name_to_fqbin(E) -> error({gpb_error, {badmsg, E}}). -spec fqbin_to_enum_name(_) -> no_return(). fqbin_to_enum_name(E) -> error({gpb_error, {badenum, E}}). -spec enum_name_to_fqbin(_) -> no_return(). enum_name_to_fqbin(E) -> error({gpb_error, {badenum, E}}). get_package_name() -> undefined. %% Whether or not the message names %% are prepended with package name or not. uses_packages() -> false. source_basename() -> "mix_hex_pb_versions.proto". %% Retrieve all proto file names, also imported ones. %% The order is top-down. The first element is always the main %% source file. The files are returned with extension, %% see get_all_proto_names/0 for a version that returns %% the basenames sans extension get_all_source_basenames() -> ["mix_hex_pb_versions.proto"]. %% Retrieve all proto file names, also imported ones. %% The order is top-down. The first element is always the main %% source file. The files are returned sans .proto extension, %% to make it easier to use them with the various get_xyz_containment %% functions. get_all_proto_names() -> ["mix_hex_pb_versions"]. get_msg_containment("mix_hex_pb_versions") -> ['Package', 'Versions']; get_msg_containment(P) -> error({gpb_error, {badproto, P}}). get_pkg_containment("mix_hex_pb_versions") -> undefined; get_pkg_containment(P) -> error({gpb_error, {badproto, P}}). get_service_containment("mix_hex_pb_versions") -> []; get_service_containment(P) -> error({gpb_error, {badproto, P}}). get_rpc_containment("mix_hex_pb_versions") -> []; get_rpc_containment(P) -> error({gpb_error, {badproto, P}}). get_enum_containment("mix_hex_pb_versions") -> []; get_enum_containment(P) -> error({gpb_error, {badproto, P}}). get_proto_by_msg_name_as_fqbin(<<"Versions">>) -> "mix_hex_pb_versions"; get_proto_by_msg_name_as_fqbin(<<"Package">>) -> "mix_hex_pb_versions"; get_proto_by_msg_name_as_fqbin(E) -> error({gpb_error, {badmsg, E}}). -spec get_proto_by_service_name_as_fqbin(_) -> no_return(). get_proto_by_service_name_as_fqbin(E) -> error({gpb_error, {badservice, E}}). -spec get_proto_by_enum_name_as_fqbin(_) -> no_return(). get_proto_by_enum_name_as_fqbin(E) -> error({gpb_error, {badenum, E}}). -spec get_protos_by_pkg_name_as_fqbin(_) -> no_return(). get_protos_by_pkg_name_as_fqbin(E) -> error({gpb_error, {badpkg, E}}). gpb_version_as_string() -> "4.17.6". gpb_version_as_list() -> [4,17,6]. gpb_version_source() -> "file". hex-2.0.6/src/mix_hex_registry.erl000066400000000000000000000120451437023760000171730ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% @doc %% Functions for encoding and decoding Hex registries. -module(mix_hex_registry). -export([ encode_names/1, decode_names/2, build_names/2, unpack_names/3, encode_versions/1, decode_versions/2, build_versions/2, unpack_versions/3, encode_package/1, decode_package/3, build_package/2, unpack_package/4, sign_protobuf/2, decode_signed/1, decode_and_verify_signed/2, sign/2, verify/3 ]). -include_lib("public_key/include/public_key.hrl"). -type private_key() :: #'RSAPrivateKey'{} | binary(). -type public_key() :: #'RSAPublicKey'{} | binary(). %%==================================================================== %% API functions %%==================================================================== %% @doc %% Builds names resource. build_names(Names, PrivateKey) -> Payload = encode_names(Names), zlib:gzip(sign_protobuf(Payload, PrivateKey)). %% @doc %% Unpacks names resource. unpack_names(Payload, Repository, PublicKey) -> case decode_and_verify_signed(zlib:gunzip(Payload), PublicKey) of {ok, Names} -> decode_names(Names, Repository); Other -> Other end. %% @private encode_names(Names) -> mix_hex_pb_names:encode_msg(Names, 'Names'). %% @private decode_names(Payload, no_verify) -> #{packages := Packages} = mix_hex_pb_names:decode_msg(Payload, 'Names'), {ok, Packages}; decode_names(Payload, Repository) -> case mix_hex_pb_names:decode_msg(Payload, 'Names') of #{repository := Repository, packages := Packages} -> {ok, Packages}; _ -> {error, unverified} end. %% @doc %% Builds versions resource. build_versions(Versions, PrivateKey) -> Payload = encode_versions(Versions), zlib:gzip(sign_protobuf(Payload, PrivateKey)). %% @doc %% Unpacks versions resource. unpack_versions(Payload, Repository, PublicKey) -> case decode_and_verify_signed(zlib:gunzip(Payload), PublicKey) of {ok, Versions} -> decode_versions(Versions, Repository); Other -> Other end. %% @private encode_versions(Versions) -> mix_hex_pb_versions:encode_msg(Versions, 'Versions'). %% @private decode_versions(Payload, no_verify) -> #{packages := Packages} = mix_hex_pb_versions:decode_msg(Payload, 'Versions'), {ok, Packages}; decode_versions(Payload, Repository) -> case mix_hex_pb_versions:decode_msg(Payload, 'Versions') of #{repository := Repository, packages := Packages} -> {ok, Packages}; _ -> {error, unverified} end. %% @doc %% Builds package resource. build_package(Package, PrivateKey) -> Payload = encode_package(Package), zlib:gzip(sign_protobuf(Payload, PrivateKey)). %% @doc %% Unpacks package resource. unpack_package(Payload, Repository, Name, PublicKey) -> case decode_and_verify_signed(zlib:gunzip(Payload), PublicKey) of {ok, Package} -> decode_package(Package, Repository, Name); Other -> Other end. %% @private encode_package(Package) -> mix_hex_pb_package:encode_msg(Package, 'Package'). %% @private decode_package(Payload, no_verify, no_verify) -> #{releases := Releases} = mix_hex_pb_package:decode_msg(Payload, 'Package'), {ok, Releases}; decode_package(Payload, Repository, Package) -> case mix_hex_pb_package:decode_msg(Payload, 'Package') of #{repository := Repository, name := Package, releases := Releases} -> {ok, Releases}; _ -> {error, unverified} end. %% @private sign_protobuf(Payload, PrivateKey) -> Signature = sign(Payload, PrivateKey), mix_hex_pb_signed:encode_msg(#{payload => Payload, signature => Signature}, 'Signed'). %% @private decode_signed(Signed) -> mix_hex_pb_signed:decode_msg(Signed, 'Signed'). %% @private -spec decode_and_verify_signed(binary(), public_key()) -> {ok, binary()} | {error, term()}. decode_and_verify_signed(Signed, PublicKey) -> #{payload := Payload, signature := Signature} = decode_signed(Signed), case verify(Payload, Signature, PublicKey) of true -> {ok, Payload}; false -> {error, unverified}; {error, Reason} -> {error, Reason} end. %% @private -spec sign(binary(), private_key()) -> binary(). sign(Binary, PrivateKey) -> {ok, RSAPrivateKey} = key(PrivateKey), public_key:sign(Binary, sha512, RSAPrivateKey). %% @private -spec verify(binary(), binary(), public_key()) -> boolean() | {error, term()}. verify(Binary, Signature, PublicKey) -> case key(PublicKey) of {ok, RSAPublicKey} -> public_key:verify(Binary, sha512, Signature, RSAPublicKey); {error, Reason} -> {error, Reason} end. %%==================================================================== %% Internal functions %%==================================================================== %% @private key(#'RSAPublicKey'{} = Key) -> {ok, Key}; key(#'RSAPrivateKey'{} = Key) -> {ok, Key}; key(Binary) when is_binary(Binary) -> case public_key:pem_decode(Binary) of [Entry | _] -> {ok, public_key:pem_entry_decode(Entry)}; _ -> {error, bad_key} end. hex-2.0.6/src/mix_hex_repo.erl000066400000000000000000000130201437023760000162620ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% @doc %% Repo API. -module(mix_hex_repo). -export([ get_names/1, get_versions/1, get_package/2, get_tarball/3 ]). %%==================================================================== %% API functions %%==================================================================== %% @doc %% Gets names resource from the repository. %% %% Examples: %% %% ``` %% > mix_hex_repo:get_names(mix_hex_core:default_config()). %% {ok, {200, ..., %% [ %% #{name => <<"package1">>}, %% #{name => <<"package2">>}, %% ]}} %% ''' %% @end get_names(Config) when is_map(Config) -> Verify = maps:get(repo_verify_origin, Config, true), Decoder = fun(Data) -> case Verify of true -> mix_hex_registry:decode_names(Data, repo_name(Config)); false -> mix_hex_registry:decode_names(Data, no_verify) end end, get_protobuf(Config, <<"names">>, Decoder). %% @doc %% Gets versions resource from the repository. %% %% Examples: %% %% ``` %% > mix_hex_repo:get_versions(Config). %% {ok, {200, ..., %% [ %% #{name => <<"package1">>, retired => [], %% versions => [<<"1.0.0">>]}, %% #{name => <<"package2">>, retired => [<<"0.5.0>>"], %% versions => [<<"0.5.0">>, <<"1.0.0">>]}, %% ]}} %% ''' %% @end get_versions(Config) when is_map(Config) -> Verify = maps:get(repo_verify_origin, Config, true), Decoder = fun(Data) -> case Verify of true -> mix_hex_registry:decode_versions(Data, repo_name(Config)); false -> mix_hex_registry:decode_versions(Data, no_verify) end end, get_protobuf(Config, <<"versions">>, Decoder). %% @doc %% Gets package resource from the repository. %% %% Examples: %% %% ``` %% > mix_hex_repo:get_package(mix_hex_core:default_config(), <<"package1">>). %% {ok, {200, ..., %% { %% #{checksum => ..., version => <<"0.5.0">>, dependencies => []}, %% #{checksum => ..., version => <<"1.0.0">>, dependencies => [ %% #{package => <<"package2">>, optional => true, requirement => <<"~> 0.1">>} %% ]}, %% ]}} %% ''' %% @end get_package(Config, Name) when is_binary(Name) and is_map(Config) -> Verify = maps:get(repo_verify_origin, Config, true), Decoder = fun(Data) -> case Verify of true -> mix_hex_registry:decode_package(Data, repo_name(Config), Name); false -> mix_hex_registry:decode_package(Data, no_verify, no_verify) end end, get_protobuf(Config, <<"packages/", Name/binary>>, Decoder). %% @doc %% Gets tarball from the repository. %% %% Examples: %% %% ``` %% > {ok, {200, _, Tarball}} = mix_hex_repo:get_tarball(mix_hex_core:default_config(), <<"package1">>, <<"1.0.0">>), %% > {ok, #{metadata := Metadata}} = mix_hex_tarball:unpack(Tarball, memory). %% ''' %% @end get_tarball(Config, Name, Version) -> ReqHeaders = make_headers(Config), case get(Config, tarball_url(Config, Name, Version), ReqHeaders) of {ok, {200, RespHeaders, Tarball}} -> {ok, {200, RespHeaders, Tarball}}; Other -> Other end. %%==================================================================== %% Internal functions %%==================================================================== %% @private get(Config, URI, Headers) -> mix_hex_http:request(Config, get, URI, Headers, undefined). %% @private get_protobuf(Config, Path, Decoder) -> PublicKey = maps:get(repo_public_key, Config), ReqHeaders = make_headers(Config), case get(Config, build_url(Config, Path), ReqHeaders) of {ok, {200, RespHeaders, Compressed}} -> Signed = zlib:gunzip(Compressed), case decode(Signed, PublicKey, Decoder, Config) of {ok, Decoded} -> {ok, {200, RespHeaders, Decoded}}; {error, _} = Error -> Error end; Other -> Other end. %% @private decode(Signed, PublicKey, Decoder, Config) -> Verify = maps:get(repo_verify, Config, true), case Verify of true -> case mix_hex_registry:decode_and_verify_signed(Signed, PublicKey) of {ok, Payload} -> Decoder(Payload); Other -> Other end; false -> #{payload := Payload} = mix_hex_registry:decode_signed(Signed), Decoder(Payload) end. %% @private repo_name(#{repo_organization := Name}) when is_binary(Name) -> Name; repo_name(#{repo_name := Name}) when is_binary(Name) -> Name. %% @private tarball_url(Config, Name, Version) -> Filename = tarball_filename(Name, Version), build_url(Config, <<"tarballs/", Filename/binary>>). %% @private build_url(#{repo_url := URI, repo_organization := Org}, Path) when is_binary(Org) -> <>; build_url(#{repo_url := URI, repo_organization := undefined}, Path) -> <>; build_url(Config, Path) -> build_url(Config#{repo_organization => undefined}, Path). %% @private tarball_filename(Name, Version) -> <>. %% @private make_headers(Config) -> maps:fold(fun set_header/3, #{}, Config). %% @private set_header(http_etag, ETag, Headers) when is_binary(ETag) -> maps:put(<<"if-none-match">>, ETag, Headers); set_header(repo_key, Token, Headers) when is_binary(Token) -> maps:put(<<"authorization">>, Token, Headers); set_header(_, _, Headers) -> Headers. hex-2.0.6/src/mix_hex_tarball.erl000066400000000000000000000516541437023760000167550ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %% @doc %% Functions for creating and unpacking Hex tarballs. -module(mix_hex_tarball). -export([create/2, create/3, create_docs/1, create_docs/2, unpack/2, unpack/3, unpack_docs/2, unpack_docs/3, format_checksum/1, format_error/1]). -ifdef(TEST). -export([do_decode_metadata/1, gzip/1, normalize_requirements/1]). -endif. -define(VERSION, <<"3">>). -define(BUILD_TOOL_FILES, [ {<<"mix.exs">>, <<"mix">>}, {<<"rebar.config">>, <<"rebar3">>}, {<<"rebar">>, <<"rebar3">>}, {<<"Makefile">>, <<"make">>}, {<<"Makefile.win">>, <<"make">>} ]). -include_lib("kernel/include/file.hrl"). -type checksum() :: binary(). -type contents() :: #{filename() => binary()}. -type filename() :: string(). -type files() :: [{filename(), filename() | binary()}]. -type metadata() :: map(). -type tarball() :: binary(). %%==================================================================== %% API functions %%==================================================================== %% @doc %% Creates a package tarball. %% %% Returns the binary of the tarball the "inner checksum" and "outer checksum". %% The inner checksum is deprecated in favor of the outer checksum. %% %% Examples: %% %% ``` %% > Metadata = #{<<"name">> => <<"foo">>, <<"version">> => <<"1.0.0">>}, %% > Files = [{"src/foo.erl", <<"-module(foo).">>}], %% > mix_hex_tarball:create(Metadata, Files). %% {ok, #{tarball => <<86,69,...>>, %% outer_checksum => <<40,32,...>>, %% inner_checksum => <<178,12,...>>}} %% ''' %% @end -spec create(metadata(), files(), mix_hex_core:config()) -> {ok, #{tarball => tarball(), outer_checksum => checksum(), inner_checksum => tarball()}} | {error, term()}. create(Metadata, Files, Config) -> MetadataBinary = encode_metadata(Metadata), ContentsTarball = create_memory_tarball(Files), ContentsTarballCompressed = gzip(ContentsTarball), InnerChecksum = inner_checksum(?VERSION, MetadataBinary, ContentsTarballCompressed), InnerChecksumBase16 = encode_base16(InnerChecksum), TarballMaxSize = maps:get(tarball_max_size, Config), TarballMaxUncompressedSize = maps:get(tarball_max_uncompressed_size, Config), OuterFiles = [ {"VERSION", ?VERSION}, {"CHECKSUM", InnerChecksumBase16}, {"metadata.config", MetadataBinary}, {"contents.tar.gz", ContentsTarballCompressed} ], Tarball = create_memory_tarball(OuterFiles), OuterChecksum = checksum(Tarball), UncompressedSize = byte_size(ContentsTarball), case {(byte_size(Tarball) > TarballMaxSize), (UncompressedSize > TarballMaxUncompressedSize)} of {_, true} -> {error, {tarball, {too_big_uncompressed, TarballMaxUncompressedSize}}}; {true, _} -> {error, {tarball, {too_big_compressed, TarballMaxSize}}}; {false, false} -> {ok, #{tarball => Tarball, outer_checksum => OuterChecksum, inner_checksum => InnerChecksum}} end. -spec create(metadata(), files()) -> {ok, #{tarball => tarball(), outer_checksum => checksum(), inner_checksum => tarball()}} | {error, term()}. create(Metadata, Files) -> create(Metadata, Files, mix_hex_core:default_config()). %% @doc %% Creates a docs tarball. %% %% Examples: %% %% ``` %% > Files = [{"doc/index.html", <<"Docs">>}], %% > mix_hex_tarball:create_docs(Files). %% {ok, <<86,69,...>>} %% ''' %% @end -spec create_docs(files(), mix_hex_core:config()) -> {ok, tarball()} | {error, term()}. create_docs(Files, #{tarball_max_size := TarballMaxSize, tarball_max_uncompressed_size := TarballMaxUncompressedSize}) -> UncompressedTarball = create_memory_tarball(Files), UncompressedSize = byte_size(UncompressedTarball), Tarball = gzip(UncompressedTarball), Size = byte_size(Tarball), case(Size > TarballMaxSize) or (UncompressedSize > TarballMaxUncompressedSize) of true -> {error, {tarball, too_big}}; false -> {ok, Tarball} end. -spec create_docs(files()) -> {ok, tarball()}. create_docs(Files) -> create_docs(Files, mix_hex_core:default_config()). %% @doc %% Unpacks a package tarball. %% %% Remember to verify the outer tarball checksum against the registry checksum %% returned from `mix_hex_repo:get_package(Config, Package)'. %% %% Examples: %% %% ``` %% > mix_hex_tarball:unpack(Tarball, memory). %% {ok,#{outer_checksum => <<...>>, %% contents => [{"src/foo.erl",<<"-module(foo).">>}], %% metadata => #{<<"name">> => <<"foo">>, ...}}} %% %% > mix_hex_tarball:unpack(Tarball, "path/to/unpack"). %% {ok,#{outer_checksum => <<...>>, %% metadata => #{<<"name">> => <<"foo">>, ...}}} %% ''' -spec unpack(tarball(), memory, mix_hex_core:config()) -> {ok, #{outer_checksum => checksum(), inner_checksum => checksum(), metadata => metadata(), contents => contents()}} | {error, term()}; (tarball(), filename(), mix_hex_core:config()) -> {ok, #{outer_checksum => checksum(), inner_checksum => checksum(), metadata => metadata()}} | {error, term()}. unpack(Tarball, _, #{tarball_max_size := TarballMaxSize}) when byte_size(Tarball) > TarballMaxSize -> {error, {tarball, too_big}}; unpack(Tarball, Output, _Config) -> case mix_hex_erl_tar:extract({binary, Tarball}, [memory]) of {ok, []} -> {error, {tarball, empty}}; {ok, FileList} -> OuterChecksum = crypto:hash(sha256, Tarball), do_unpack(maps:from_list(FileList), OuterChecksum, Output); {error, Reason} -> {error, {tarball, Reason}} end. %% @doc %% Unpacks a package tarball. %% %% @see unpack/3 -spec unpack(tarball(), memory) -> {ok, #{outer_checksum => checksum(), inner_checksum => checksum(), metadata => metadata(), contents => contents()}} | {error, term()}; (tarball(), filename()) -> {ok, #{outer_checksum => checksum(), inner_checksum => checksum(), metadata => metadata()}} | {error, term()}. unpack(Tarball, Output) -> unpack(Tarball, Output, mix_hex_core:default_config()). %% @doc %% Unpacks a documentation tarball. %% %% Examples: %% %% ``` %% > mix_hex_tarball:unpack_docs(Tarball, memory). %% {ok, [{"index.html", <<"">>}, ...]} %% %% > mix_hex_tarball:unpack_docs(Tarball, "path/to/unpack"). %% ok %% ''' -spec unpack_docs(tarball(), memory, mix_hex_core:config()) -> {ok, contents()} | {error, term()}; (tarball(), filename(), mix_hex_core:config()) -> ok | {error, term()}. unpack_docs(Tarball, _, #{tarball_max_size := TarballMaxSize}) when byte_size(Tarball) > TarballMaxSize -> {error, {tarball, too_big}}; unpack_docs(Tarball, Output, _Config) -> unpack_tarball(Tarball, Output). -spec unpack_docs(tarball(), memory) -> {ok, contents()} | {error, term()}; (tarball(), filename()) -> ok | {error, term()}. unpack_docs(Tarball, Output) -> unpack_docs(Tarball, Output, mix_hex_core:default_config()). %% @doc %% Returns base16-encoded representation of checksum. -spec format_checksum(checksum()) -> binary(). format_checksum(Checksum) -> encode_base16(Checksum). %% @doc %% Converts an error reason term to a human-readable error message string. -spec format_error(term()) -> string(). format_error({tarball, empty}) -> "empty tarball"; format_error({tarball, {too_big_uncompressed, Size}}) -> io_lib:format("package exceeds max uncompressed size ~w ~s", [format_byte_size(Size), "MB"]); format_error({tarball, {too_big_compressed, Size}}) -> io_lib:format("package exceeds max compressed size ~w ~s", [format_byte_size(Size), "MB"]); format_error({tarball, {missing_files, Files}}) -> io_lib:format("missing files: ~p", [Files]); format_error({tarball, {bad_version, Vsn}}) -> io_lib:format("unsupported version: ~p", [Vsn]); format_error({tarball, invalid_checksum}) -> "invalid tarball checksum"; format_error({tarball, Reason}) -> "tarball error, " ++ mix_hex_erl_tar:format_error(Reason); format_error({inner_tarball, Reason}) -> "inner tarball error, " ++ mix_hex_erl_tar:format_error(Reason); format_error({metadata, invalid_terms}) -> "error reading package metadata: invalid terms"; format_error({metadata, not_key_value}) -> "error reading package metadata: not in key-value format"; format_error({metadata, Reason}) -> "error reading package metadata" ++ mix_safe_erl_term:format_error(Reason); format_error({checksum_mismatch, ExpectedChecksum, ActualChecksum}) -> io_lib:format( "tarball checksum mismatch~n~n" ++ "Expected (base16-encoded): ~s~n" ++ "Actual (base16-encoded): ~s", [encode_base16(ExpectedChecksum), encode_base16(ActualChecksum)]). format_byte_size(Size) -> Size / 1000000. %%==================================================================== %% Internal functions %%==================================================================== %% @private inner_checksum(Version, MetadataBinary, ContentsBinary) -> Blob = <>, crypto:hash(sha256, Blob). %% @private checksum(ContentsBinary) when is_binary(ContentsBinary) -> crypto:hash(sha256, ContentsBinary). %% @private encode_metadata(Meta) -> Data = lists:map( fun(MetaPair) -> String = io_lib_pretty:print(binarify(MetaPair), [{encoding, utf8}]), unicode:characters_to_binary([String, ".\n"]) end, maps:to_list(Meta)), iolist_to_binary(Data). %% @private do_unpack(Files, OuterChecksum, Output) -> State = #{ inner_checksum => undefined, outer_checksum => OuterChecksum, contents => undefined, files => Files, metadata => undefined, output => Output }, State1 = check_files(State), State2 = check_version(State1), State3 = check_inner_checksum(State2), State4 = decode_metadata(State3), finish_unpack(State4). %% @private finish_unpack({error, _} = Error) -> Error; finish_unpack(#{metadata := Metadata, files := Files, inner_checksum := InnerChecksum, outer_checksum := OuterChecksum, output := Output}) -> _ = maps:get("VERSION", Files), ContentsBinary = maps:get("contents.tar.gz", Files), case Output of memory -> ok; _ -> filelib:ensure_dir(filename:join(Output, "*")) end, case unpack_tarball(ContentsBinary, Output) of ok -> copy_metadata_config(Output, maps:get("metadata.config", Files)), {ok, #{inner_checksum => InnerChecksum, outer_checksum => OuterChecksum, metadata => Metadata}}; {ok, Contents} -> {ok, #{inner_checksum => InnerChecksum, outer_checksum => OuterChecksum, metadata => Metadata, contents => Contents}}; {error, Reason} -> {error, {inner_tarball, Reason}} end. %% @private copy_metadata_config(Output, MetadataBinary) -> ok = file:write_file(filename:join(Output, "hex_metadata.config"), MetadataBinary). %% @private check_files(#{files := Files} = State) -> RequiredFiles = ["VERSION", "CHECKSUM", "metadata.config", "contents.tar.gz"], case diff_keys(Files, RequiredFiles, []) of ok -> State; {error, {missing_keys, Keys}} -> {error, {tarball, {missing_files, Keys}}} end. %% @private check_version({error, _} = Error) -> Error; check_version(#{files := Files} = State) -> case maps:get("VERSION", Files) of <<"3">> -> State; Version -> {error, {tarball, {bad_version, Version}}} end. %% @private % Note: This checksum is deprecated check_inner_checksum({error, _} = Error) -> Error; check_inner_checksum(#{files := Files} = State) -> ChecksumBase16 = maps:get("CHECKSUM", Files), ExpectedChecksum = decode_base16(ChecksumBase16), Version = maps:get("VERSION", Files), MetadataBinary = maps:get("metadata.config", Files), ContentsBinary = maps:get("contents.tar.gz", Files), ActualChecksum = inner_checksum(Version, MetadataBinary, ContentsBinary), if byte_size(ExpectedChecksum) /= 32 -> {error, {tarball, invalid_inner_checksum}}; ExpectedChecksum == ActualChecksum -> maps:put(inner_checksum, ExpectedChecksum, State); true -> {error, {tarball, {inner_checksum_mismatch, ExpectedChecksum, ActualChecksum}}} end. %% @private decode_metadata({error, _} = Error) -> Error; decode_metadata(#{files := #{"metadata.config" := Binary}} = State) when is_binary(Binary) -> case do_decode_metadata(Binary) of #{} = Metadata -> maps:put(metadata, normalize_metadata(Metadata), State); Other -> Other end. %% @private do_decode_metadata(Binary) when is_binary(Binary) -> {ok, String} = characters_to_list(Binary), case mix_safe_erl_term:string(String) of {ok, Tokens, _Line} -> try Terms = mix_safe_erl_term:terms(Tokens), maps:from_list(Terms) catch error:function_clause -> {error, {metadata, invalid_terms}}; error:badarg -> {error, {metadata, not_key_value}} end; {error, {_Line, mix_safe_erl_term, Reason}, _Line2} -> {error, {metadata, Reason}} end. %% @private characters_to_list(Binary) -> case unicode:characters_to_list(Binary) of List when is_list(List) -> {ok, List}; {error, _, _} -> case unicode:characters_to_list(Binary, latin1) of List when is_list(List) -> {ok, List}; Other -> Other end end. %% @private normalize_metadata(Metadata1) -> Metadata2 = maybe_update_with(<<"requirements">>, fun normalize_requirements/1, Metadata1), Metadata3 = maybe_update_with(<<"links">>, fun try_into_map/1, Metadata2), Metadata4 = maybe_update_with(<<"extra">>, fun try_into_map/1, Metadata3), guess_build_tools(Metadata4). %% @private normalize_requirements(Requirements) -> case is_list(Requirements) andalso (Requirements /= []) andalso is_list(hd(Requirements)) of true -> maps:from_list(lists:map(fun normalize_legacy_requirement/1, Requirements)); false -> try_into_map(fun normalize_normal_requirement/1, Requirements) end. %% @private normalize_normal_requirement({Name, Requirement}) -> {Name, try_into_map(Requirement)}. %% @private normalize_legacy_requirement(Requirement) -> Map = maps:from_list(Requirement), Name = maps:get(<<"name">>, Map), {Name, maps:without([<<"name">>], Map)}. %% @private guess_build_tools(#{<<"build_tools">> := BuildTools} = Metadata) when is_list(BuildTools) -> Metadata; guess_build_tools(#{<<"files">> := Filenames} = Metadata) -> BaseFiles = [Filename || Filename <- Filenames, filename:dirname(binary_to_list(Filename)) == "."], BuildTools = lists:usort([Tool || {Filename, Tool} <- ?BUILD_TOOL_FILES, lists:member(Filename, BaseFiles)]), Metadata#{<<"build_tools">> => BuildTools}; guess_build_tools(Metadata) -> Metadata. %%==================================================================== %% Tar Helpers %%==================================================================== %% @private unpack_tarball(ContentsBinary, memory) -> mix_hex_erl_tar:extract({binary, ContentsBinary}, [memory, compressed]); unpack_tarball(ContentsBinary, Output) -> filelib:ensure_dir(filename:join(Output, "*")), case mix_hex_erl_tar:extract({binary, ContentsBinary}, [{cwd, Output}, compressed]) of ok -> [try_updating_mtime(filename:join(Output, Path)) || Path <- filelib:wildcard("**", Output)], ok; Other -> Other end. %% @private %% let it silently fail for bad symlinks try_updating_mtime(Path) -> Time = calendar:universal_time(), _ = file:write_file_info(Path, #file_info{mtime=Time}, [{time, universal}]), ok. %% @private create_memory_tarball(Files) -> Path = tmp_path(), {ok, Tar} = mix_hex_erl_tar:open(Path, [write]), try add_files(Tar, Files) after ok = mix_hex_erl_tar:close(Tar) end, {ok, Tarball} = file:read_file(Path), ok = file:delete(Path), Tarball. %% @private tmp_path() -> "tmp_" ++ binary_to_list(encode_base16(crypto:strong_rand_bytes(32))). %% @private add_files(Tar, Files) when is_list(Files) -> lists:map(fun(File) -> add_file(Tar, File) end, Files). %% @private add_file(Tar, {Filename, Contents}) when is_list(Filename) and is_binary(Contents) -> ok = mix_hex_erl_tar:add(Tar, Contents, Filename, tar_opts()); add_file(Tar, Filename) when is_list(Filename) -> add_file(Tar, {Filename, Filename}); add_file(Tar, {Filename, AbsFilename}) when is_list(Filename), is_list(AbsFilename) -> {ok, FileInfo} = file:read_link_info(AbsFilename, []), case FileInfo#file_info.type of symlink -> ok = mix_hex_erl_tar:add(Tar, {Filename, AbsFilename}, tar_opts()); directory -> case file:list_dir(AbsFilename) of {ok, []} -> mix_hex_erl_tar:add(Tar, {Filename, AbsFilename}, tar_opts()); {ok, _} -> ok end; _ -> Mode = FileInfo#file_info.mode, {ok, Contents} = file:read_file(AbsFilename), ok = mix_hex_erl_tar:add(Tar, Contents, Filename, Mode, tar_opts()) end. %% @private tar_opts() -> NixEpoch = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}), Y2kEpoch = calendar:datetime_to_gregorian_seconds({{2000, 1, 1}, {0, 0, 0}}), Epoch = Y2kEpoch - NixEpoch, [{atime, Epoch}, {mtime, Epoch}, {ctime, Epoch}, {uid, 0}, {gid, 0}]. %% @private %% Reproducible gzip by not setting mtime and OS %% %% From https://tools.ietf.org/html/rfc1952 %% %% +---+---+---+---+---+---+---+---+---+---+ %% |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->) %% +---+---+---+---+---+---+---+---+---+---+ %% %% +=======================+ %% |...compressed blocks...| (more-->) %% +=======================+ %% %% +---+---+---+---+---+---+---+---+ %% | CRC32 | ISIZE | %% +---+---+---+---+---+---+---+---+ gzip(Uncompressed) -> Compressed = gzip_no_header(Uncompressed), Header = <<31, 139, 8, 0, 0, 0, 0, 0, 0, 0>>, Crc = erlang:crc32(Uncompressed), Size = byte_size(Uncompressed), Trailer = <>, iolist_to_binary([Header, Compressed, Trailer]). %% @private gzip_no_header(Uncompressed) -> Zstream = zlib:open(), try zlib:deflateInit(Zstream, default, deflated, -15, 8, default), Compressed = zlib:deflate(Zstream, Uncompressed, finish), zlib:deflateEnd(Zstream), iolist_to_binary(Compressed) after zlib:close(Zstream) end. %%==================================================================== %% Helpers %%==================================================================== %% @private binarify(Binary) when is_binary(Binary) -> Binary; binarify(Number) when is_number(Number) -> Number; binarify(Atom) when Atom == undefined orelse is_boolean(Atom) -> Atom; binarify(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8); binarify(List) when is_list(List) -> [binarify(E) || E <- List]; binarify({Key, Value}) -> {binarify(Key), binarify(Value)}; binarify(Map) when is_map(Map) -> List = maps:to_list(Map), lists:map(fun({K, V}) -> binarify({K, V}) end, List). %% @private diff_keys(Map, RequiredKeys, OptionalKeys) -> Keys = maps:keys(Map), MissingKeys = RequiredKeys -- Keys, UnknownKeys = Keys -- (RequiredKeys ++ OptionalKeys), case {MissingKeys, UnknownKeys} of {[], []} -> ok; % Server should validate this but clients should not % {_, [_ | _]} -> % {error, {unknown_keys, UnknownKeys}}; _ -> {error, {missing_keys, MissingKeys}} end. %% @private maybe_update_with(Key, Fun, Map) -> case maps:find(Key, Map) of {ok, Value} -> maps:put(Key, Fun(Value), Map); error -> Map end. %% @private try_into_map(List) -> try_into_map(fun(X) -> X end, List). %% @private try_into_map(Fun, Input) -> case is_list(Input) andalso lists:all(fun(E) -> is_tuple(E) andalso (tuple_size(E) == 2) end, Input) of true -> maps:from_list(lists:map(Fun, Input)); false -> Input end. %% @private encode_base16(Binary) -> <> = Binary, String = string:to_upper(lists:flatten(io_lib:format("~64.16.0b", [X]))), list_to_binary(String). %% Based on https://github.com/goj/base16/blob/master/src/base16.erl %% (C) 2012, Erlang Solutions Ltd. %% @private decode_base16(Base16) -> << <<(unhex(H) bsl 4 + unhex(L))>> || <> <= Base16 >>. %% @private unhex(D) when $0 =< D andalso D =< $9 -> D - $0; unhex(D) when $a =< D andalso D =< $f -> 10 + D - $a; unhex(D) when $A =< D andalso D =< $F -> 10 + D - $A. hex-2.0.6/src/mix_safe_erl_term.xrl000066400000000000000000000042661437023760000173170ustar00rootroot00000000000000%% Vendored from hex_core v0.8.2, do not edit manually %%% Author : Robert Virding %%% Purpose : Token definitions for Erlang. Definitions. D = [0-9] U = [A-Z] L = [a-z] A = ({U}|{L}|{D}|_|@) WS = ([\000-\s]) Rules. {L}{A}* : tokenize_atom(TokenChars, TokenLine). '(\\\^.|\\.|[^'])*' : tokenize_atom(escape(unquote(TokenChars, TokenLen)), TokenLine). "(\\\^.|\\.|[^"])*" : {token, {string, TokenLine, escape(unquote(TokenChars, TokenLen))}}. {D}+ : {token, {integer, TokenLine, list_to_integer(TokenChars)}}. [\#\[\]}{,+-] : {token, {list_to_atom(TokenChars), TokenLine}}. (<<|>>|=>) : {token, {list_to_atom(TokenChars), TokenLine}}. \. : {token, {dot, TokenLine}}. / : {token, {'/', TokenLine}}. {WS}+ : skip_token. Erlang code. -export([terms/1]). terms(Tokens) -> terms(Tokens, []). terms([{dot, _} = H], Buffer) -> [buffer_to_term([H|Buffer])]; terms([{dot, _} = H|T], Buffer) -> [buffer_to_term([H|Buffer])|terms(T, [])]; terms([H|T], Buffer) -> terms(T, [H|Buffer]). buffer_to_term(Buffer) -> {ok, Term} = erl_parse:parse_term(lists:reverse(Buffer)), Term. unquote(TokenChars, TokenLen) -> lists:sublist(TokenChars, 2, TokenLen - 2). tokenize_atom(TokenChars, TokenLine) -> try list_to_existing_atom(TokenChars) of Atom -> {token, {atom, TokenLine, Atom}} catch error:badarg -> {error, "illegal atom " ++ TokenChars} end. escape([$\\|Cs]) -> do_escape(Cs); escape([C|Cs]) -> [C|escape(Cs)]; escape([]) -> []. do_escape([O1,O2,O3|S]) when O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 -> [(O1*8 + O2)*8 + O3 - 73*$0|escape(S)]; do_escape([$^,C|Cs]) -> [C band 31|escape(Cs)]; do_escape([C|Cs]) when C >= $\000, C =< $\s -> escape(Cs); do_escape([C|Cs]) -> [escape_char(C)|escape(Cs)]. escape_char($n) -> $\n; %\n = LF escape_char($r) -> $\r; %\r = CR escape_char($t) -> $\t; %\t = TAB escape_char($v) -> $\v; %\v = VT escape_char($b) -> $\b; %\b = BS escape_char($f) -> $\f; %\f = FF escape_char($e) -> $\e; %\e = ESC escape_char($s) -> $\s; %\s = SPC escape_char($d) -> $\d; %\d = DEL escape_char(C) -> C. hex-2.0.6/test/000077500000000000000000000000001437023760000132645ustar00rootroot00000000000000hex-2.0.6/test/fixtures/000077500000000000000000000000001437023760000151355ustar00rootroot00000000000000hex-2.0.6/test/fixtures/certs/000077500000000000000000000000001437023760000162555ustar00rootroot00000000000000hex-2.0.6/test/fixtures/certs/amazon.der000066400000000000000000000024311437023760000202360ustar00rootroot0000000000000000N/* &O0  *H 01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1;09U 2Terms of use at https://www.verisign.com/rpa (c)101/0-U&VeriSign Class 3 Secure Server CA - G30 150327000000Z 151027235959Z0j1 0 UUS10U Washington10USeattle10U Amazon.com, Inc.10Us3.amazonaws.com0"0  *H 0 ַx`iL17ue(spUWckBE䨔Շ# dP>./[G#0l=E1['ΝY_3eY1?sTVBv\Jԓ1ɈY˻E@M*U@7ۻ`yh9cB6OuFEx٪6@~ Nlǎa|ԶNaOx<{XHn!-%'* -ګnB$Mi0e0U0s3.amazonaws.com0 U00U0U%0++0eU ^0\0Z `HE60L0#+https://d.symcb.com/cps0%+0https://d.symcb.com/rpa0U#0 D\SD~ %cؾy0+U$0"0 http://sd.symcb.com/sd.crl0W+K0I0+0http://sd.symcd.com0&+0http://sd.symcb.com/sd.crt0  *H 0n}WM>K8ʔ ;] Sf|( B1\cEN4U}^ifugE&H@t&"@簞 `^%AV P1J4c#/w*_NLzX(sq &6l:6 ː]œ%Ql͙|{*xE6˺15mz=~s;,K(HE!v!6#:c0a0Un6sS,V8LNQ0U#0n6sS,V8LNQ0U00U0  *H  D(YG+'(A/=UpD >c,[wqb mҙJGЩ0-ӻy2fGf$'q>ũlzq]Zߋ1V5UK;f$TYn0u'MU;5 tcT)>Xe  ʩmqNKߤKK_r-'/p$ZCbS78TCf YT\p=?^rVyZ]z֋!,sozJ4i3XX?bg84s4l5yTfMC ["h] k;iy g\C-1f' ]^֪x:9k-5ͯmha*z,wFsZH y}jNhjA;4;zfyYgw`JO0g'ol֯u7nNة<t齕7"1/7FV[Rӧa&hex-2.0.6/test/fixtures/certs/ca.cert.pem000066400000000000000000000035431437023760000203040ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIJAOoztPT1GhWyMA0GCSqGSIb3DQEBCwUAMDAxCzAJBgNV BAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMQ8wDQYDVQQKDAZUZXN0Q0EwHhcNMTUw NzE2MDg1MTI1WhcNMzUwNzExMDg1MTI1WjAwMQswCQYDVQQGEwJHQjEQMA4GA1UE CAwHRW5nbGFuZDEPMA0GA1UECgwGVGVzdENBMIICIjANBgkqhkiG9w0BAQEFAAOC Ag8AMIICCgKCAgEA4MdTOopb6msWPEp3ijoDFqgMWB4Pft6uE/p0URIyo4eofpfo jVIYDQ8w26YnWe6KLQPAAGzC+JDNe6ulZsbeTCC1HmOjrogwGy9hotLOoIMcBnFZ FpfYeY3Q6mCpwzVsfTxRkPUfGF3RG/4HbeCKuA1D4r9uDVoj00asK6sOR+jHZ7Qx wPA8LZH8VpH5DgZonudBQrS4ufgdgLsNedwmRMHsoBvq1DxjsBvpZ1KHaR5ldaaq y9W/FYXdkB+TXETaHzjc4mc1tbN0V5EjM14JNTQSQFRr4Bmfy8z1DeJ8xEe98fGX p5ko5TXKUfq8vQ5GIAxxvq40x1LwfXLpe5f0scdet9oBWb1knRFbv3Lz4J70VNyE uXGWMMyRvnmKELzIV2XFSVeeLbNGixGpJFKmz6S7F7Ij2XCNx35NE6qafxbZKhdr Q2SJcvL1GI5KR+QMWbhrmBhHq2Lvu7vJczPZSbzBkfmDyFH5hW9A/oUBnvmBNX+S 5lo8tGYWotN1wJnZqVaaMO2Ji6mvpnadspRuISFKmy4Fq76lhzGM0bY+elgoc4iC cQ3bJjasbDq7qjb5nYQJ3cuQCOwDXfbFkyVRbNjNmXzMe5UqvuF49EU2AuroAMu6 MTVtep89fnOA6OmpEzsPutHBLOpLlCgXSEWQlLAeniF2BSE27SPqhh46s4sCAwEA AaNjMGEwHQYDVR0OBBYEFLNuNnOQH1OJj5osVvbzOEzaTp9RMB8GA1UdIwQYMBaA FLNuNnOQH1OJj5osVvbzOEzaTp9RMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDgROsoWRLPRysnmCjiQekvPVW3/XBE Cj6cY4As8VsHsHdxYg1tp4btxO3Sma+USkcbDtCpMMCtoi2GngXTu4Z5z+qKAjJm R5oI/6JmJP3mk8InCOZxEgSKPsWp+Gx6DsFxoNb7hY/wvV1a34sfEvaaEYAxhvre 1gZ/BlY1VQ5LO55mjyRUjFlutDB1J6xNrlU7NeCy+gt0YxasVLSqlinAPqlY1mUe 7McKFe/Bvwz/f/8fyqltcU7rS/X936SQ4gVLj+/kS4lfcpMcLScvpfwecNskWrcH gkNiqvtTwDc46B2FVLxDZoCZ9Q0PkFlU51wbHPrxcJf7PYYCP170cqxWE8B5Wl2l hR2letaL5iEst7XowHMa0W+MzHqDG0o0aR7bM39Y0lg/+qy4EmKP1P1npbMaOLXA j7M0c5QQBDSSbL6KNdt5jc9U2Wbp5rBNmvqXskMKklsiaF3DzuwNyN1rO83uaZ15 vyDGGWdcQ9stMZtmJ4AKXYOhXtaqeDo5a83L/KQtrBY1za9ttopovuya6uxhKq70 eqyP6yzXAqnIyPF3RnNa20ggeX2+auT38k4eaGpB8e0GGs2+AjQ7hXpmea1ZZ3eu YErITzCMZ5rvFb4n829s1q8dgXU3n5Vun0622Km5PB+uu9vcdOm9lTfSIjEvHzeO RqxWW1LTp2EmBQ== -----END CERTIFICATE----- hex-2.0.6/test/fixtures/certs/server.der000066400000000000000000000020261437023760000202570ustar00rootroot00000000000000000  *H  001 0 UGB10U England10 U TestCA0 150716085502Z 160725085502Z011 0 UGB10U England10U foo.com0\0  *H K0HA\<̀BzVUYj h1FZpĨh4"C=mV 00 U00 `HB@03 `HB &$OpenSSL Generated Server Certificate0UGt^z|.3WZp p?0`U#Y0Wn6sS,V8LNQ42001 0 UGB10U England10 U TestCA 30U0U% 0 +0  *H  02 vb'bٔWwՂ@n )'#_(-d>"_X;I f{4HOcRi8#@Bȭf4SĨ|o@ 'o|68;mh#dpmq fgN( wHCb6l`cITKb_.6?]r N/6` hB\9 J\. [tW4f0 ڏ8*Cf.F#R+5լ԰u կbN'A|J3`fGP_ )(3u\ABquV1G|Uܫd)P!][Մ 7Qt1rx ̼݋$GyݧE1c%:6C*zjP'/mҦ acMdkḱ+NԪv=F [ lznm9{޾F-P2gwI"KDEIRȃ"Y62hex-2.0.6/test/fixtures/certs/verisign_g3.der000066400000000000000000000027601437023760000211750ustar00rootroot0000000000000000Ԡnz μRԑ0  *H 01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1:08U 1(c) 2006 VeriSign, Inc. - For authorized use only1E0CU9¬VeDOMo JԯNh.{44[I{bHtшxlSC&WX3;3 N$}dtJ4  K;c- ʶ=7H5)PxEcAO{qP(S,#= 3.0.0"}] end end hex-2.0.6/test/fixtures/ecto_sql_3_3_2/000077500000000000000000000000001437023760000176335ustar00rootroot00000000000000hex-2.0.6/test/fixtures/ecto_sql_3_3_2/mix.exs000066400000000000000000000003021437023760000211440ustar00rootroot00000000000000defmodule Ecto.SQL_3_3_2.Fixture.MixProject do use Mix.Project def project do [app: :ecto_sql, version: "3.3.2", deps: deps()] end defp deps do [{:ecto, "~> 3.3.1"}] end end hex-2.0.6/test/fixtures/ecto_sql_3_3_3/000077500000000000000000000000001437023760000176345ustar00rootroot00000000000000hex-2.0.6/test/fixtures/ecto_sql_3_3_3/mix.exs000066400000000000000000000003021437023760000211450ustar00rootroot00000000000000defmodule Ecto.SQL_3_3_2.Fixture.MixProject do use Mix.Project def project do [app: :ecto_sql, version: "3.3.3", deps: deps()] end defp deps do [{:ecto, "~> 3.3.2"}] end end hex-2.0.6/test/fixtures/ex_doc/000077500000000000000000000000001437023760000163765ustar00rootroot00000000000000hex-2.0.6/test/fixtures/ex_doc/mix.exs000066400000000000000000000001711437023760000177130ustar00rootroot00000000000000defmodule ExDoc.Fixture.MixProject do use Mix.Project def project do [app: :ex_doc, version: "0.0.1"] end end hex-2.0.6/test/fixtures/has_hex_dep/000077500000000000000000000000001437023760000174045ustar00rootroot00000000000000hex-2.0.6/test/fixtures/has_hex_dep/mix.exs000066400000000000000000000002761437023760000207270ustar00rootroot00000000000000defmodule HasHexDep.Fixture.MixProject do use Mix.Project def project do [app: :has_hex_dep, version: "0.0.1", deps: deps()] end defp deps do [{:ecto, "~> 0.1"}] end end hex-2.0.6/test/fixtures/override_with_path/000077500000000000000000000000001437023760000210235ustar00rootroot00000000000000hex-2.0.6/test/fixtures/override_with_path/mix.exs000066400000000000000000000003561437023760000223450ustar00rootroot00000000000000defmodule OverrideWithPath.Fixture.MixProject do use Mix.Project def project do [ app: :override_with_git, version: "0.1.0", deps: [{:postgrex, []}, {:ex_doc, path: "../ex_doc", override: true}] ] end end hex-2.0.6/test/fixtures/registries/000077500000000000000000000000001437023760000173155ustar00rootroot00000000000000hex-2.0.6/test/fixtures/registries/20200917.ets000066400000000000000000006727201437023760000207540ustar00rootroot00000000000000cXM bWLAhhdidZd nonode@nohost6bchddecentralized_countersdfalsehdread_concurrencydfalsehdwrite_concurrencydfalsehd compresseddfalsehdmemoryb24hdownerXd nonode@nohosthdheirdnonehdnamedElixir.Hex.Devhdsizebehdnoded nonode@nohosthd named_tabledfalsehdtypedsethdkeyposahd protectiond protectedhd major_versionahd minor_versionahd extended_infojbbWLAhhdinner_checksummhexpmmphoenix_paramsm0.2.2m 8n]ͨ րB0|z)-vgU탻MGbWLAhhd timestampmhexpmmphoenixm1.4.17hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm1.0.5hhba aha a9a0cbWLAhhddepsmhexpmmplugm1.1.1lhmhexpmmcowboymcowboym~> 1.0dtruej5bWLAhhdretiredmhexpmmphoenixm1.0.3dnil3bWLAhhdretiredmhexpmmplugm0.14.0dnilYbWLAhhdinner_checksummhexpmmplugm1.10.0m e)\TE&7䨃4vHuM6bWLAhhdretiredmhexpmmpostgrexm0.8.2dnilYbWLAhhdouter_checksummhexpmmplugm0.12.1m 4+`%`bȩ@L)^DF2bWLAhhdretiredmhexpmmmimem1.0.0dnilHbWLAhhd timestampmhexpmmpostgrexm0.13.3hhba aha a9a0ibWLAhhddepsmhexpmm phoenix_htmlm2.11.2lhmhexpmmplugmplugm~> 1.5dfalsejKbWLAhhddepsmhexpmmphoenixm1.2.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm6~> 1.4 or ~> 1.3.3 or ~> 1.2.4 or ~> 1.1.8 or ~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejdbWLAhhdouter_checksummhexpmm phoenix_htmlm 2.0.0-devm 0WyʀZPlϠG!ȪHbWLAhhd timestampmhexpmmplugm 1.2.0-rc.0hhba aha a9a0[bWLAhhdinner_checksummhexpmmphoenixm0.1.0m Hyr M{=w-[bWLAhhdinner_checksummhexpmmphoenixm1.0.0m QyՉy ecoN*5bWLAhhdretiredmhexpmmphoenixm1.1.8dnilbWLAhhddepsmhexpmmphoenixm0.14.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej9bWLAhhdretiredmhexpmm plug_cryptom1.1.2dnilbWLAhhddepsmhexpmmplugm1.9.0lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruejFbWLAhhd timestampmhexpmmdecimalm0.1.1hhba aha a9a0ebWLAhhddepsmhexpmmplugm0.6.0lhmhexpmmcowboymcowboym~> 1.0.0dtruej]bWLAhhdouter_checksummhexpmmpostgrexm0.15.1m A {ׇ lX3}dbY=[bWLAhhdinner_checksummhexpmmdecimalm1.4.0m eqjSӦEf(Ze.J3MbWLAhhd timestampmhexpmmphoenix_paramsm1.1.2hhba aha a9a0>bWLAhhdretiredmhexpmm phoenix_htmlm 2.0.0-devdnilbWLAhhddepsmhexpmmpostgrexm0.15.5lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.1dfalsehmhexpmmdecimalmdecimalm~> 1.5dfalsehmhexpmmjasonmjasonm~> 1.0dtruejbbWLAhhdouter_checksummhexpmmphoenix_paramsm1.1.1m Ym{DG:.oٙ=壈 `bWLAhhdouter_checksummhexpmm phoenix_htmlm2.0.1m Sf&]rJsu7 eUyB7~FbWLAhhd timestampmhexpmmphoenixm1.1.2hhba aha a9a04bWLAhhddepsmhexpmmphoenix_pubsubm1.1.1jXbWLAhhdouter_checksummhexpmmplugm0.4.1m Hd,dÎY7qrwܩ:LbWLAhhd timestampmhexpmm db_connectionm0.1.6hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm1.4.4dnilDbWLAhhd timestampmhexpmmplugm0.11.3hhba aha a9a0\bWLAhhdinner_checksummhexpmmpostgrexm0.5.2m b_Do`7DND+@=T[bWLAhhdinner_checksummhexpmmphoenixm1.4.9m tm t3M=<ʱud5C4Ay.ftbWLAhhddepsmhexpmmplugm1.6.1lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsejYbWLAhhdouter_checksummhexpmmjasonm1.2.1m YW`Z`A@DqoiYbWLAhhdinner_checksummhexpmmplugm1.10.2m y4\}FTTŇd8\wZabWLAhhdinner_checksummhexpmm db_connectionm2.0.3m Co,gQČy99+rabWLAhhdouter_checksummhexpmm phoenix_htmlm2.12.0m y /DGP)%kmn^cbWLAhhddepsmhexpmmplugm1.1.5lhmhexpmmcowboymcowboym~> 1.0dtruejXbWLAhhdouter_checksummhexpmmplugm1.3.2m jhZ84 cM^~LbWLAhhd timestampmhexpmm phoenix_htmlm2.13.0hhba aha a9a0\bWLAhhdouter_checksummhexpmmphoenixm0.13.1m Z. MeC9fԮZB[bWLAhhdouter_checksummhexpmmphoenixm1.5.4m NQmއh.}^0\۳5QbWLAhhd timestampmhexpmm db_connectionm 1.0.0-rc.3hhba aha a9a0]bWLAhhdouter_checksummhexpmmpostgrexm0.15.5m %Z+'03(ڢaCabWLAhhdouter_checksummhexpmm db_connectionm0.1.8m ԋj<@kU- 1&B[[bWLAhhdinner_checksummhexpmmphoenixm1.2.3m ֧>8YwDXIH]bWLAhhdouter_checksummhexpmmpostgrexm0.14.2m 6ĬA'S6ΡGCեG,I7mv_bWLAhhdinner_checksummhexpmm plug_cowboym1.0.0m .*}4 tm3_EX0=h' nz 1.0.0dtruej\bWLAhhdouter_checksummhexpmmphoenixm0.2.10m eXNil ?-_0qA $Q"[bWLAhhdouter_checksummhexpmmphoenixm0.2.7m :=ќxלFaG5=Z;@vB9ϕ[bWLAhhdinner_checksummhexpmmphoenixm1.2.5m Z_"Y^#*evH#cbWLAhhddepsmhexpmmplugm1.0.2lhmhexpmmcowboymcowboym~> 1.0dtruej[bWLAhhdinner_checksummhexpmmdecimalm1.8.0m F. _ ţB~5HZes4.]bWLAhhdouter_checksummhexpmmpostgrexm0.15.3m G7bG< b0~QOs ,( `l\bWLAhhdinner_checksummhexpmmphoenixm0.13.0m FN6"K]m/6Mݛ%bbWLAhhdinner_checksummhexpmmphoenix_pubsubm2.0.0m vq{h읒H֍G9_GbWLAhhd timestampmhexpmmphoenixm0.16.1hhba aha a9a0bbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.0.0m "FY'x@ʇa A ,W2bWLAhhdretiredmhexpmmplugm1.4.0dnilQbWLAhhd timestampmhexpmm db_connectionm 2.0.0-rc.0hhba aha a9a0KbWLAhhd timestampmhexpmm phoenix_htmlm2.4.0hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm1.5.2dnilJbWLAhhd timestampmhexpmm plug_cowboym2.1.0hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm1.3.0dnilFbWLAhhd timestampmhexpmmphoenixm1.5.4hhba aha a9a0[bWLAhhdinner_checksummhexpmmphoenixm1.5.1m eƒǐ an)4u]bWLAhhdouter_checksummhexpmmpostgrexm0.11.0m mD}$ֈ j*mJ~\Cg_CbWLAhhd timestampmhexpmmplugm0.4.3hhba aha a9a0"bWLAhhddepsmhexpmmphoenixm1.4.6lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruej[bWLAhhdinner_checksummhexpmmphoenixm0.6.1m 0Y 9cQ#hư(* q5bWLAhhdretiredmhexpmmphoenixm1.2.1dnilabWLAhhdouter_checksummhexpmm phoenix_htmlm2.11.2m /T06!lEZ n'`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.1.1m *Zbu6n4"0A(uTW70`bWLAhhdouter_checksummhexpmmphoenixm 1.3.0-rc.3m >tm~Ļsb`&x ew1bWLAhhddepsmhexpmm plug_cryptom1.1.0jbWLAhhddepsmhexpmmpostgrexm0.14.0lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.0dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsehmhexpmmjasonmjasonm~> 1.0dtruejabWLAhhdinner_checksummhexpmm db_connectionm1.1.2m (e¤qN"`-v QYɫǨFbWLAhhd timestampmhexpmmdecimalm1.9.0hhba aha a9a0jbWLAhhddepsmhexpmmphoenixm1.4.16lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejXbWLAhhdouter_checksummhexpmmmimem1.0.0m ~gG틓\Tzy,OLm}?\FbWLAhhd timestampmhexpmmphoenixm1.0.0hhba aha a9a0JbWLAhhd timestampmhexpmm plug_cowboym2.2.2hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.3.6m ?/ ߶? V.\od/uR-}XbWLAhhdinner_checksummhexpmmplugm1.1.9m r!gкgfk8邗#3(7$s5bWLAhhdretiredmhexpmmdecimalm1.3.0dnilQbWLAhhd timestampmhexpmm db_connectionm 1.0.0-rc.5hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm0.7.2m leuevoLGgұzo`bWLAhhdouter_checksummhexpmmphoenixm 1.5.0-rc.0m 7}ʋNEBt_y e%gf[bWLAhhdinner_checksummhexpmmphoenixm1.4.1m c(e|e|bLB#bWLAhhddepsmhexpmm db_connectionm0.2.0lhmhexpmmbackoffmbackoffm1.1.1dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruej\bWLAhhdouter_checksummhexpmmpostgrexm0.8.0m (Ӂnz(i$Te&HHbWLAhhd timestampmhexpmmplugm 1.5.0-rc.0hhba aha a9a0lbWLAhhddepsmhexpmmpostgrexm0.5.4lhmhexpmmdecimalmdecimalm~> 0.2.3dfalsejbbWLAhhdinner_checksummhexpmmphoenix_paramsm0.4.1m YFG=1}7ӷtXHS@bWLAhhdretiredmhexpmm db_connectionm 1.0.0-rc.2dnil8bWLAhhdretiredmhexpmmjasonm 1.0.0-rc.3dnilCbWLAhhd timestampmhexpmmplugm1.3.2hhba aha a9a07bWLAhhdretiredmhexpmmpostgrexm0.13.1dnilLbWLAhhd timestampmhexpmm db_connectionm0.2.5hhba aha a9a0:bWLAhhdretiredmhexpmm phoenix_htmlm1.3.0dnilbWLAhhddepsmhexpmmphoenixm0.15.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm>= 0.13.1 and < 2.0.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejGbWLAhhd timestampmhexpmmpostgrexm0.8.1hhba aha a9a0=bWLAhhd timestampmhexpmmpostgrexhhba aha a9a04bWLAhhddepsmhexpmmphoenix_pubsubm1.1.0jbWLAhhddepsmhexpmmphoenixm0.2.10lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.3dfalsehmhexpmmjazzmjazzm0.1.1dfalsehmhexpmmplugmplugm0.5.0dfalsejzbWLAhhdretiredmhexpmm plug_cowboym2.2.2tdmessagemBroken telemetry supportdreasondRETIRED_INVALIDJbWLAhhd timestampmhexpmm plug_cryptom1.1.2hhba aha a9a0abWLAhhdinner_checksummhexpmm db_connectionm0.2.0m JDM*sǰq̎j hKbWLAhhd timestampmhexpmm phoenix_htmlm2.0.0hhba aha a9a0\bWLAhhdouter_checksummhexpmmpostgrexm0.9.1m OEG4=zQsW0T%12HYZ\bWLAhhdinner_checksummhexpmmphoenixm0.10.0m ,~33gaTyV0A*IXUbWLAhhd registry_etagmhexpmm connectionm""cb8397ee262701f54669d854dd7531e6"&bWLAhd last_updatehhba aha a$aabWLAhhdouter_checksummhexpmm db_connectionm0.1.6m ZLVHcfċ /ن3KQlrbbWLAhhdouter_checksummhexpmmphoenix_paramsm0.4.1m Ue)2/Tyr;_,:bg$MIN`M/bWLAhhddepsmhexpmm telemetrym0.4.2jYbWLAhhdinner_checksummhexpmmplugm0.14.0m KN&ïF9VgD|Az[FbWLAhhd timestampmhexpmmphoenixm0.4.0hhba aha a9a0YbWLAhhdouter_checksummhexpmmplugm0.12.0m LeEo448W }L<NJQbWLAhhd timestampmhexpmm db_connectionm 1.0.0-rc.4hhba aha a9a02bWLAhhddepsmhexpmmdecimalm 1.9.0-rc.0j_bWLAhhdinner_checksummhexpmm plug_cowboym2.1.1m (ۥUbuwK3DbWLAhhd timestampmhexpmmplugm1.10.4hhba aha a9a09bWLAhhdretiredmhexpmm plug_cowboym2.0.1dnilFbWLAhhd timestampmhexpmmphoenixm0.1.0hhba aha a9a0lbWLAhhddepsmhexpmmpostgrexm0.5.5lhmhexpmmdecimalmdecimalm~> 0.2.3dfalsej3bWLAhhdretiredmhexpmmjasonm1.2.2dnilabWLAhhdinner_checksummhexpmm phoenix_htmlm2.11.1m wRnsd7RX͡2f&~jbWLAhhddepsmhexpmmpostgrexm0.8.0lhmhexpmmdecimalmdecimalm~> 1.0dfalsejDbWLAhhd timestampmhexpmmjasonm1.1.1hhba aha a9a0KbWLAhhd timestampmhexpmm phoenix_htmlm2.9.0hhba aha a9a0wbWLAhhddepsmhexpmm phoenix_htmlm1.3.0lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsejFbWLAhhd timestampmhexpmmphoenixm1.3.2hhba aha a9a0abWLAhhdouter_checksummhexpmm db_connectionm1.1.0m 4F7c@~ױ )KUa| bWLAhhddepsmhexpmmphoenixm0.4.1lhmhexpmmcowboymcowboym~> 1.0.0dtruehmhexpmmlinguistmlinguistm~> 0.1.2dfalsehmhexpmmplugmplugm0.7.0dfalsehmhexpmmpoisonmpoisonm~> 1.1.0dfalsej3bWLAhhdretiredmhexpmmplugm1.10.1dnil2bWLAhhdretiredmhexpmmplugm1.3.0dnildbWLAhhddepsmhexpmmplugm0.12.2lhmhexpmmcowboymcowboym~> 1.0dtruej2bWLAhhdretiredmhexpmmplugm1.8.2dnilbbWLAhhdouter_checksummhexpmmphoenix_paramsm0.2.2m FlXGִ]7LbWLAhhd timestampmhexpmm phoenix_htmlm2.10.5hhba aha a9a0]bWLAhhdouter_checksummhexpmmpostgrexm0.13.5m a3y6=p. &~ 1.0.1 or ~> 1.1 or ~> 2.1dtruehmhexpmmmimemmimem~> 1.0dfalsej2bWLAhhdretiredmhexpmmplugm0.4.3dnil;bWLAhhdretiredmhexpmm db_connectionm0.1.5dnilKbWLAhhd timestampmhexpmmdecimalm 1.9.0-rc.0hhba aha a9a0MbWLAhhd timestampmhexpmmphoenix_paramsm1.1.0hhba aha a9a0_bWLAhhdinner_checksummhexpmm plug_cowboym2.0.0m r+ 1.0dtruehmhexpmmpoisonmpoisonm~> 1.2dfalsejYbWLAhhdouter_checksummhexpmmjasonm1.0.1m QQjL Y= hv%W4 bbWLAhhdouter_checksummhexpmmphoenix_paramsm0.3.0m \߶E.F_A \<x)5bWLAhhdretiredmhexpmmphoenixm0.4.1dnilebWLAhhddepsmhexpmmplugm0.8.0lhmhexpmmcowboymcowboym~> 1.0.0dtruejDbWLAhhd timestampmhexpmmplugm1.10.1hhba aha a9a0HbWLAhhd timestampmhexpmmpostgrexm0.15.2hhba aha a9a04bWLAhhddepsmhexpmmphoenix_pubsubm2.0.0jYbWLAhhd registry_etagmhexpmmphoenix_paramsm""389651a1f33cf6831d08446192a18010"@y dƀ^bWLAhhdouter_checksummhexpmm connectionm1.0.4m JPɾ": qQ\ @&8%IbWLAhhd timestampmhexpmmjasonm 1.0.0-rc.2hhba aha a9a0bWLAhhddepsmhexpmmphoenixm0.16.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 0.14 or ~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej_bWLAhhdouter_checksummhexpmm plug_cryptom1.1.2m k`[oԜ7Lj>j(;["ֵ[bWLAhhdouter_checksummhexpmmdecimalm1.1.1m ?6"/+ 1.0.2dfalsej[bWLAhhdinner_checksummhexpmmphoenixm1.0.2m ] 2EmUah⽶GzC2fbWLAhhddepsmhexpmmplugm1.6.3lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsejXbWLAhhdinner_checksummhexpmmplugm1.2.0m IkcJI׀:gΜ෹% Y cbWLAhhddepsmhexpmmplugm1.0.1lhmhexpmmcowboymcowboym~> 1.0dtruejXbWLAhhdouter_checksummhexpmmplugm0.8.0m s1eL>:cv6-+2bWLAhhdretiredmhexpmmplugm0.7.0dnilCbWLAhhd timestampmhexpmmplugm1.0.1hhba aha a9a0bbWLAhhdouter_checksummhexpmmpostgrexm 0.14.0-rc.0m lR#E/VG{(XU7]c-bWLAhhddepsmhexpmmdecimalm1.8.0jwbWLAhhddepsmhexpmm phoenix_htmlm 2.4.0-devlhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej2bWLAhhdretiredmhexpmmplugm1.0.3dnil5bWLAhhdretiredmhexpmmphoenixm1.0.2dnil7bWLAhhdretiredmhexpmmpostgrexm0.10.0dnilabWLAhhdouter_checksummhexpmm phoenix_htmlm2.13.3m ӗ1TWm%u_U7%g[bWLAhhdinner_checksummhexpmmphoenixm0.7.1m }x3V%1,TY9 L~*;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.0dnil5bWLAhhdretiredmhexpmmphoenixm1.1.1dnilXbWLAhhdouter_checksummhexpmmplugm0.6.0m ' ]R\cbWLAhhdinner_checksummhexpmm connectionm 1.0.0-rc.1m t$H' X*;֞bYyF'CbWLAhhd timestampmhexpmmplugm1.5.0hhba aha a9a0 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej`bWLAhhdinner_checksummhexpmmphoenixm 1.2.0-rc.0m ?uF&ːIbJZ} |3ҋJbWLAhhd timestampmhexpmm plug_cryptom1.0.0hhba aha a9a0FbWLAhhd timestampmhexpmmdecimalm1.1.0hhba aha a9a0bWLAhhddepsmhexpmm db_connectionm1.1.0lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0dtruejbWLAhhddepsmhexpmmphoenixm1.0.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejbbWLAhhdinner_checksummhexpmmpostgrexm 0.13.0-rc.0m cЛ $>Rir-.+f.)9;F,bWLAhhddepsmhexpmmphoenixm 1.3.0-rc.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.2 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej6bWLAhhdretiredmhexpmmphoenixm0.13.1dnil5bWLAhhdretiredmhexpmmphoenixm1.0.5dnilfbWLAhhdouter_checksummhexpmm db_connectionm 2.0.0-rc.0m d<9 vl:0v.\ 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0dtruejFbWLAhhd timestampmhexpmmphoenixm0.3.0hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm0.8.3m L(G/1hMKKzbWLAhhddepsmhexpmmphoenixm0.8.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 0.9.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejbWLAhhddepsmhexpmmplugm1.3.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej5bWLAhhdretiredmhexpmmphoenixm0.2.4dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.1.0m UL-\^'u2˖ut(FbWLAhhd timestampmhexpmmphoenixm1.5.1hhba aha a9a0JbWLAhhd timestampmhexpmm plug_cowboym2.1.2hhba aha a9a0bWLAhhddepsmhexpmmphoenix_paramsm0.4.2lhmhexpmmdecimalmdecimalm>= 1.7.0dfalsehmhexpmmphoenixmphoenixm>= 1.3.3dfalsej5bWLAhhdretiredmhexpmmphoenixm1.0.6dnil2bWLAhhdretiredmhexpmmplugm1.4.4dnil]bWLAhhdouter_checksummhexpmmpostgrexm0.13.2m Y)'y6F"O'9 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruej5bWLAhhdretiredmhexpmmphoenixm0.6.1dnil5bWLAhhdretiredmhexpmmdecimalm0.1.2dnilCbWLAhhd timestampmhexpmmplugm1.6.0hhba aha a9a0_bWLAhhdouter_checksummhexpmm plug_cowboym2.1.1m O W[9DXm}rLs}@bWLAhhdretiredmhexpmm db_connectionm 2.0.0-rc.0dnilHbWLAhhd timestampmhexpmmpostgrexm0.13.5hhba aha a9a0ibWLAhhddepsmhexpmm phoenix_htmlm2.13.1lhmhexpmmplugmplugm~> 1.5dfalsej\bWLAhhdouter_checksummhexpmmpostgrexm0.5.5m =(s֚5J_һHx?nXԬ4! bWLAhhddepsmhexpmmpostgrexm0.15.0lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.1dfalsehmhexpmmdecimalmdecimalm~> 1.5dfalsehmhexpmmjasonmjasonm~> 1.0dtruej0bWLAhhddepsmhexpmm connectionm1.0.2jFbWLAhhd timestampmhexpmmphoenixm0.2.2hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.1.7m ֵePvEb}DزVA6bWLAhhdretiredmhexpmmpostgrexm0.8.1dnilbbWLAhhdinner_checksummhexpmmpostgrexm 0.14.0-rc.0m )Wec( y*F&N9HbWLAhhd timestampmhexpmm telemetrym0.1.0hhba aha a9a0MbWLAhhd timestampmhexpmmphoenix_pubsubm1.0.1hhba aha a9a0XbWLAhhdinner_checksummhexpmmmimem1.2.0m x+6 ӴQ@уֈ[ 4`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.8.0m V -*J= z%߻!KbWLAhhd timestampmhexpmm phoenix_htmlm2.6.1hhba aha a9a0]bWLAhhdouter_checksummhexpmm telemetrym0.4.0m |1p| 0-Ow?A`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.6.0m uXk_<Pׁ\}L͖{'[bWLAhhdinner_checksummhexpmmphoenixm0.7.2m HN!3rWDvQ b{wf;fbWLAhhddepsmhexpmmjasonm1.0.1lhmhexpmmdecimalmdecimalm~> 1.0dtruej5bWLAhhdretiredmhexpmmphoenixm1.3.2dnildbWLAhhdinner_checksummhexpmm phoenix_htmlm 2.0.0-devm 3{ۼ/"\4s9sHee[}(ebWLAhhddepsmhexpmmpostgrexm0.15.1lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.1dfalsehmhexpmmdecimalmdecimalm~> 1.5dfalsehmhexpmmjasonmjasonm~> 1.0dtruej`bWLAhhdouter_checksummhexpmmphoenixm 1.4.0-rc.2m &h (0"B}pe:8BibWLAhhddepsmhexpmmphoenixm1.4.8lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej[bWLAhhdinner_checksummhexpmmphoenixm1.3.3m _9災Dj,y|XUfabWLAhhdouter_checksummhexpmm db_connectionm2.0.2m {YCbGv `bWLAhhdinner_checksummhexpmm phoenix_htmlm1.3.0m $lGT?iM*7Pq+_?2bWLAhhdretiredmhexpmmplugm1.2.5dnilbWLAhhddepsmhexpmm db_connectionm1.1.3lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0dtruejfbWLAhhddepsmhexpmmjasonm1.1.0lhmhexpmmdecimalmdecimalm~> 1.0dtruej`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.0.0m Eg^-"t"ޟR ʻu;ɒXw\(`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.2.0m tO$w^WGwLUcՌAKbWLAhhd timestampmhexpmm phoenix_htmlm2.5.0hhba aha a9a0\bWLAhhdouter_checksummhexpmmpostgrexm0.8.4m .X%(Xf$bWLAhhddepsmhexpmmplugm1.8.0lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruej[bWLAhhdouter_checksummhexpmmdecimalm0.1.2m Jޗ֊YJ AJ'm1bWLAhhddepsmhexpmm plug_cryptom1.1.2jYbWLAhhdinner_checksummhexpmmplugm0.12.2m Af+ ^@ hpܥ{$iz\bWLAhhdouter_checksummhexpmmphoenixm1.4.14m IX%G{eeq [v+XT[bWLAhhdouter_checksummhexpmmphoenixm1.4.7m S>ke5qN4'ՠ$]myFbWLAhhd timestampmhexpmmphoenixm0.2.4hhba aha a9a0MbWLAhhd timestampmhexpmmphoenix_paramsm0.1.1hhba aha a9a0bbWLAhhdinner_checksummhexpmmphoenix_paramsm0.1.1m Nl̒uJ8}]õrt,mbWLAhhddepsmhexpmmphoenixm1.5.1lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejbbWLAhhdouter_checksummhexpmmphoenix_paramsm0.1.2m 1R? ŲG)fqm!zbXbWLAhhdinner_checksummhexpmmplugm1.2.2m Ͻ!L?퍏K͛ibWLAhhddepsmhexpmm phoenix_htmlm2.14.0lhmhexpmmplugmplugm~> 1.5dfalsej/bWLAhhddepsmhexpmm telemetrym0.3.0jXbWLAhhdinner_checksummhexpmmplugm1.4.5m {sS&,^ ]$ '=[bWLAhhdinner_checksummhexpmmdecimalm0.2.5m @[x:`&'?ԀC{Xk4NêObWLAhhd timestampmhexpmm phoenix_htmlm 2.0.0-devhhba aha a9a0`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.9.2m MI?V`1= f[0g7iqKNobbWLAhhdouter_checksummhexpmmphoenix_paramsm1.1.2m ; 왐UWo*imv_bWLAhhdouter_checksummhexpmm plug_cowboym2.2.0m NrrlgzyGMR;(Ѯ\}[[bWLAhhdinner_checksummhexpmmphoenixm1.1.3m ZK`c`o^݆ p*<,azlFbWLAhhd timestampmhexpmmphoenixm1.4.2hhba aha a9a0YbWLAhhdouter_checksummhexpmmplugm0.13.0m +oĦ%W{US1o":gL_HbWLAhhd timestampmhexpmmpostgrexm0.13.1hhba aha a9a0XbWLAhhdouter_checksummhexpmmmimem1.1.0m 3 ګVh\ã8)'( _M7bWLAhhdretiredmhexpmmpostgrexm0.13.5dnilbbWLAhhdouter_checksummhexpmmphoenix_pubsubm0.1.0m ktp\5Ikz@}9N\ҡVb9)bWLAhhddepsmhexpmmphoenixm 1.4.0-rc.1lhmhexpmmcowboymcowboym~> 1.0 or ~> 2.5dtruehmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.6.4 or ~> 1.7dfalsejYbWLAhhdouter_checksummhexpmmplugm0.12.2m ncoŸ> iv,i7n|-GbWLAhhd timestampmhexpmmphoenixm0.17.0hhba aha a9a0abWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.2m IclL^>5,uaB1?*[bWLAhhdinner_checksummhexpmmphoenixm1.4.8m -íIc$dQNzS5bWLAhhdretiredmhexpmmphoenixm1.1.9dnilFbWLAhhd timestampmhexpmmphoenixm0.7.0hhba aha a9a0abWLAhhdouter_checksummhexpmm db_connectionm0.1.0m rpOH<]+4o!HBr,M([bWLAhhdouter_checksummhexpmmdecimalm1.2.0m t"HD2HDM_dш[bWLAhhdinner_checksummhexpmmphoenixm0.6.0m wކM`p;y%N}퐉EwI XbWLAhhdinner_checksummhexpmmplugm1.7.1m er.t%O6N >XbWLAhhdinner_checksummhexpmmplugm1.2.3m P W8r^ @&sS3,Us[bWLAhhdinner_checksummhexpmmdecimalm0.2.3m r}$޿>4m\lZ$bWLAhhddepsmhexpmmplugm1.6.4lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsejbWLAhhddepsmhexpmm plug_cowboym2.2.0lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej5bWLAhhdretiredmhexpmmdecimalm1.8.1dnilCbWLAhhd timestampmhexpmmplugm1.4.3hhba aha a9a07bWLAhhdretiredmhexpmmplugm 1.5.0-rc.1dnil^bWLAhhdinner_checksummhexpmm connectionm1.0.1m X)Q:4B1ӟ,RBUYy첊V\ ibWLAhhddepsmhexpmm phoenix_htmlm2.10.1lhmhexpmmplugmplugm~> 1.0dfalsej_bWLAhhdinner_checksummhexpmm plug_cowboym2.1.0m Wh<:9Բ[NŎJnj' 0 ;bWLAhhdretiredmhexpmm db_connectionm2.2.0dnil]bWLAhhdinner_checksummhexpmmpostgrexm0.15.3m Xh|zbL͹~s񹀙ttj5bWLAhhdretiredmhexpmmdecimalm0.2.2dnil-bWLAhhddepsmhexpmmdecimalm1.0.1jMbWLAhhd timestampmhexpmmphoenix_paramsm1.1.1hhba aha a9a0bbWLAhhdinner_checksummhexpmmphoenix_paramsm1.0.1m S%*5`-a ,N6$kpabWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.4m 2I1c| p?-MmYbWLAhhdinner_checksummhexpmmplugm0.13.0m /:.Gűw υIl4KYbWLAhhdinner_checksummhexpmmplugm0.10.0m D?K/Fr"E*ScˋdbWLAhhddepsmhexpmmplugm0.11.1lhmhexpmmcowboymcowboym~> 1.0dtruejbWLAhhddepsmhexpmmplugm1.7.0lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsejYbWLAhhdinner_checksummhexpmmjasonm1.1.0m 4/thՆS\[ WRO\bWLAhhdouter_checksummhexpmmphoenixm1.4.17m :]z=vR_n{7cԮFbWLAhhd timestampmhexpmmphoenixm1.3.0hhba aha a9a0bWLAhhddepsmhexpmmphoenix_paramsm1.0.3lhmhexpmmdecimalmdecimalm>= 1.7.0dfalsehmhexpmmphoenixmphoenixm>= 1.3.3dfalsejFbWLAhhd timestampmhexpmmphoenixm0.4.1hhba aha a9a0GbWLAhhd timestampmhexpmmphoenixm1.4.11hhba aha a9a0jbWLAhhddepsmhexpmmpostgrexm0.7.0lhmhexpmmdecimalmdecimalm~> 1.0dfalsejibWLAhhddepsmhexpmm phoenix_htmlm2.12.0lhmhexpmmplugmplugm~> 1.5dfalsejbWLAhhddepsmhexpmmplugm1.4.3lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.2.0m Aگ^˸L^9sgSX9HXdbWLAhhdinner_checksummhexpmm phoenix_htmlm 2.4.0-devm 4 }hd2+6V;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.1dnilXbWLAhhdouter_checksummhexpmmplugm1.7.1m ڥ ċl2 b|uUM^7bWLAhhdretiredmhexpmmplugm 1.4.0-rc.0dnilhbWLAhhddepsmhexpmm phoenix_htmlm2.8.0lhmhexpmmplugmplugm~> 1.0dfalsej6bWLAhhdretiredmhexpmmphoenixm0.11.0dnilLbWLAhhd timestampmhexpmm phoenix_htmlm2.13.2hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.0.4m ,翈QEfss0Lӛ[QwbWLAhhddepsmhexpmm db_connectionm2.0.4lhmhexpmm connectionm connectionm~> 1.0.2dfalsejLbWLAhhd timestampmhexpmm db_connectionm1.1.1hhba aha a9a0KbWLAhhd timestampmhexpmmphoenixm 1.3.0-rc.1hhba aha a9a0KbWLAhhd timestampmhexpmm phoenix_htmlm2.5.1hhba aha a9a0bWLAhhddepsmhexpmmplugm 1.4.0-rc.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejMbWLAhhd timestampmhexpmmphoenix_pubsubm1.0.0hhba aha a9a0CbWLAhhd timestampmhexpmmplugm0.8.4hhba aha a9a0CbWLAhhd timestampmhexpmmplugm0.5.1hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.2.0m '8êBJm0ʭOh::bWLAhhdversionsmhexpmmjasonl m 1.0.0-rc.1m 1.0.0-rc.2m 1.0.0-rc.3m1.0.0m1.0.1m1.1.0m1.1.1m1.1.2m1.2.0m1.2.1m1.2.2j[bWLAhhdinner_checksummhexpmmphoenixm1.2.1m mŒ$ 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.1dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsejabWLAhhdinner_checksummhexpmm db_connectionm0.2.5m >^(D4Uh*/R%qׁ ϕ_>7bWLAhhdretiredmhexpmmpostgrexm0.15.1dnilabWLAhhdouter_checksummhexpmm db_connectionm1.1.2m U^§Y2UŸfxCFchwk0f֧GbWLAhhd timestampmhexpmmphoenixm0.14.0hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm1.4.7dnil[bWLAhhdouter_checksummhexpmmphoenixm1.4.5m kZJk9uhEA$sbWLAhhddepsmhexpmmplugm1.8.1lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruej6bWLAhhdretiredmhexpmmphoenixm1.4.15dnil-bWLAhhddepsmhexpmmdecimalm1.5.0j;bWLAhhdretiredmhexpmm db_connectionm0.2.4dnil8bWLAhhdretiredmhexpmmjasonm 1.0.0-rc.2dnil;bWLAhhd timestampmhexpmminflexhhbaaha a5abWLAhhddepsmhexpmmpostgrexm 1.0.0-rc.0lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.1dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsejbWLAhhddepsmhexpmmphoenixm1.1.4lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej[bWLAhhdouter_checksummhexpmmphoenixm0.2.1m +glXOptDt hT9ky[9{-6bWLAhhdretiredmhexpmmphoenixm1.4.14dnil7bWLAhhdretiredmhexpmmplugm 1.2.0-rc.0dnil6bWLAhhdretiredmhexpmmphoenixm0.16.0dnilabWLAhhdouter_checksummhexpmm db_connectionm2.2.0m k+ovnoj;bWLAhhdretiredmhexpmm db_connectionm2.2.2dnil[bWLAhhdinner_checksummhexpmmdecimalm2.0.0m LlWCG/By+VB֗7bWLAhhdretiredmhexpmmpostgrexm0.14.3dnilLbWLAhhd timestampmhexpmm db_connectionm2.0.4hhba aha a9a0-bWLAhhddepsmhexpmmdecimalm0.1.2jbWLAhhddepsmhexpmmplugm1.7.1lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsejXbWLAhhdinner_checksummhexpmmplugm1.0.1m N=XB.@9l t abWLAhhdinner_checksummhexpmm db_connectionm2.1.1m .Nnfx~ I((LjXbWLAhhdouter_checksummhexpmmplugm1.1.2m %XB=!UG^5EE*dT^bWLAhhdinner_checksummhexpmmjasonm 1.0.0-rc.3m RHr `D>PŕQOˣfƔ~XbWLAhhdouter_checksummhexpmmplugm1.2.5m >m?ªc`p\ѥLEuDbWLAhhd timestampmhexpmmplugm0.12.2hhba aha a9a0ibWLAhhddepsmhexpmmphoenixm1.4.7lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejXbWLAhhdouter_checksummhexpmmmimem1.4.0m uB"?p#KjGO?jzOHbWLAhhd timestampmhexpmmpostgrexm0.15.4hhba aha a9a0:bWLAhhdretiredmhexpmm phoenix_htmlm1.2.1dnil2bWLAhhdretiredmhexpmmplugm1.0.1dnil2bWLAhhdretiredmhexpmmplugm0.8.3dnilabWLAhhdinner_checksummhexpmm db_connectionm2.0.4m ָ}+Sˬ2)cve=h8[bWLAhhdouter_checksummhexpmmphoenixm1.2.1m ;f`5 nz 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0.0-beta.3dtruejMbWLAhhd timestampmhexpmmpostgrexm 0.13.0-rc.0hhba aha a9a0DbWLAhhd timestampmhexpmmjasonm1.2.1hhba aha a9a0MbWLAhhd timestampmhexpmmphoenix_pubsubm2.0.0hhba aha a9a0\bWLAhhdouter_checksummhexpmmphoenixm0.12.0m -V>dOva1MSdUC~68 HbWLAhhd timestampmhexpmmpostgrexm0.11.2hhba aha a9a0FbWLAhhd timestampmhexpmmdecimalm1.2.0hhba aha a9a0abWLAhhdinner_checksummhexpmm db_connectionm2.2.2m ;$[qbHI&0;]F Q%Θh;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.3dnilMbWLAhhd timestampmhexpmmphoenix_paramsm0.3.0hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm1.4.3hhba aha a9a0LbWLAhhd timestampmhexpmm phoenix_htmlm2.10.3hhba aha a9a06bWLAhhdretiredmhexpmmphoenixm0.16.1dnilCbWLAhhd timestampmhexpmmplugm1.6.1hhba aha a9a0\bWLAhhdouter_checksummhexpmmpostgrexm0.8.1m #K4D}C{&o 2Ui,bWLAhhddepsmhexpmmphoenixm 1.3.0-rc.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.2 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej[bWLAhhdouter_checksummhexpmmdecimalm1.4.0m vqN/q5 :=8K-zEFq#\bWLAhhdinner_checksummhexpmmphoenixm1.4.11m b÷lz>XPڧǦ K [bWLAhhdinner_checksummhexpmmphoenixm1.1.2m kl`ٛ D3x e&Qm4|}[bWLAhhdouter_checksummhexpmmphoenixm1.0.4m Y_:oTIj- {O5&foibWLAhhddepsmhexpmm db_connectionm0.1.0lhmhexpmmbackoffmbackoffm~> 1.0dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dfalsehmhexpmmsbrokermsbrokerm~> 0.7dfalsejCbWLAhhd timestampmhexpmmmimem1.1.0hhba aha a9a0IbWLAhhd timestampmhexpmm connectionm1.0.1hhba aha a9a0DbWLAhhd timestampmhexpmmjasonm1.0.0hhba aha a9a0[bWLAhhdinner_checksummhexpmmphoenixm0.4.1m Fwbp1YGױg 8Z*bWLAhhddepsmhexpmmplugm0.4.4jdbWLAhhddepsmhexpmmplugm0.11.2lhmhexpmmcowboymcowboym~> 1.0dtruej 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejbWLAhhddepsmhexpmmphoenixm1.0.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej\bWLAhhdinner_checksummhexpmmpostgrexm0.5.4m <1=wX 1.0 or ~> 2.0dtruejYbWLAhhdinner_checksummhexpmmplugm1.10.4m AѢqSgd[գ}*?9\bWLAhhdinner_checksummhexpmmphoenixm0.2.11m -bboW8v[xhDbWLAhhd timestampmhexpmmplugm1.10.0hhba aha a9a0DbWLAhhd timestampmhexpmmjasonm1.0.1hhba aha a9a0abWLAhhdinner_checksummhexpmm phoenix_htmlm2.14.0m Ƽ(_Z=,XiB{eZ5bWLAhhdretiredmhexpmmphoenixm1.1.4dnil^bWLAhhdouter_checksummhexpmm connectionm1.0.3m nH +$}Z'|X3Oir;bWLAhhdretiredmhexpmm db_connectionm2.0.6dnil7bWLAhhdretiredmhexpmm telemetrym0.2.0dnilwbWLAhhddepsmhexpmm db_connectionm2.0.3lhmhexpmm connectionm connectionm~> 1.0.2dfalsejMbWLAhhd timestampmhexpmmphoenix_paramsm1.1.3hhba aha a9a0LbWLAhhd timestampmhexpmm db_connectionm1.0.0hhba aha a9a0:bWLAhhdretiredmhexpmm phoenix_htmlm2.0.0dnil'bWLAhhddepsmhexpmmphoenixm1.3.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsejLbWLAhhd timestampmhexpmm db_connectionm0.1.2hhba aha a9a0?bWLAhhd timestampmhexpmm connectionhhba aha a9a0[bWLAhhdinner_checksummhexpmmdecimalm0.1.2m iڠV;j\åiTYjFbWLAhhd timestampmhexpmmphoenixm0.5.0hhba aha a9a0MbWLAhhd timestampmhexpmmphoenix_paramsm0.1.0hhba aha a9a0abWLAhhdouter_checksummhexpmm db_connectionm2.1.1m Zr- L=3\)^KHIZGXbWLAhhdouter_checksummhexpmmplugm1.4.1m ʕ'PpL]MLH,kO8bWLAhhdretiredmhexpmm connectionm1.0.3dnil2bWLAhhdretiredmhexpmmplugm1.5.1dnilNbWLAhhd timestampmhexpmm connectionm 1.0.0-rc.1hhba aha a9a0;bWLAhhdretiredmhexpmm db_connectionm0.1.3dnil7bWLAhhdretiredmhexpmm telemetrym0.1.0dnil]bWLAhhdouter_checksummhexpmmplugm 1.5.0-rc.0m MfO3Ш<`v3_-[bWLAhhdinner_checksummhexpmmphoenixm1.1.9m Gւ52(t,[֛A}9ytY_DbWLAhhd timestampmhexpmmplugm0.11.1hhba aha a9a0;bWLAhhdretiredmhexpmm db_connectionm0.2.3dnilXbWLAhhdouter_checksummhexpmmplugm1.7.0m ~ƫjxXoDm* JbWLAhhd timestampmhexpmm plug_cowboym2.3.0hhba aha a9a0[bWLAhhdinner_checksummhexpmmphoenixm1.5.3m @NH4X? [b0;IGbWLAhhd timestampmhexpmmphoenixm0.17.1hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.3.3m C4t~ws/[4 };`bWLAhhdinner_checksummhexpmmdecimalm 2.0.0-rc.0m ĸK%5 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej6bWLAhhdretiredmhexpmmpostgrexm0.9.0dnil;bWLAhhd timestampmhexpmmpoisonhhba aha a+a:bWLAhhdretiredmhexpmmphoenixm 1.2.0-rc.1dnilLbWLAhhd timestampmhexpmm db_connectionm2.0.5hhba aha a9a0CbWLAhhd timestampmhexpmmmimem1.2.0hhba aha a9a0bWLAhhddepsmhexpmmphoenixm0.7.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmpoisonmpoisonm~> 1.2dfalsejCbWLAhhd timestampmhexpmmplugm1.8.1hhba aha a9a0`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.2.0m ҩ7|˷D/!:P0ؠ 6bWLAhhdretiredmhexpmmphoenixm0.2.11dnilCbWLAhhd timestampmhexpmmplugm1.1.8hhba aha a9a0jbWLAhhddepsmhexpmmphoenixm1.4.10lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejbWLAhhddepsmhexpmmpostgrexm 0.13.0-rc.0lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.1dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsej[bWLAhhdouter_checksummhexpmmdecimalm0.2.5m .-h̆ lok$+FXnYGCbWLAhhd timestampmhexpmmplugm1.0.2hhba aha a9a0XbWLAhhdinner_checksummhexpmmplugm0.4.1m S?P>UjWz cc "[bWLAhhdinner_checksummhexpmmphoenixm0.2.4m Nr[+:Igʨ(4Y\ObWLAhhd registry_etagmhexpmmmimem""caa3030c95a211515c73c7c786aa1110"`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.9.3m Z!"C$/TOx0OKLC% XX*bWLAhhddepsmhexpmmmimem1.3.1jfbWLAhhdouter_checksummhexpmm db_connectionm 1.0.0-rc.2m 3ěV2igIhjl`l*>U&`bWLAhhdouter_checksummhexpmmphoenixm 1.3.0-rc.0m 5PN 1.0dtruejrbWLAhhddepsmhexpmmphoenix_paramsm0.1.1lhmhexpmmphoenixmphoenixm~> 1.3.3dfalsejkbWLAhhddepsmhexpmmjasonm 1.0.0-rc.3lhmhexpmmdecimalmdecimalm~> 1.0dtruej`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.1.2m {* 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruej:bWLAhhdretiredmhexpmm phoenix_htmlm2.1.1dnil[bWLAhhdinner_checksummhexpmmphoenixm1.4.6m 5 xj.HQxvlYbWLAhhddepsmhexpmm db_connectionm0.2.4lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruej\bWLAhhdinner_checksummhexpmmphoenixm1.4.16m ,fV|D8 3B7*Bn=:HCbWLAhhddepsmhexpmm db_connectionm0.1.7lhmhexpmmbackoffmbackoffm~> 1.0dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruej9bWLAhhdretiredmhexpmm plug_cowboym1.0.0dnil]bWLAhhdinner_checksummhexpmmpostgrexm0.14.2m fY⍒C$6ʹ*y6I$.;xKbWLAhhd timestampmhexpmm phoenix_htmlm2.2.0hhba aha a9a0bWLAhhddepsmhexpmmpostgrexm0.12.2lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.0dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsejCbWLAhhd timestampmhexpmmplugm1.3.1hhba aha a9a0rbWLAhhddepsmhexpmmphoenix_paramsm0.1.0lhmhexpmmphoenixmphoenixm~> 1.3.3dfalsej\bWLAhhdouter_checksummhexpmmphoenixm1.4.13m vZہbl{_QYb`tRv}bWLAhhddepsmhexpmm db_connectionm0.1.4lhmhexpmmbackoffmbackoffm~> 1.0dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruejGbWLAhhd timestampmhexpmmphoenixm1.4.14hhba aha a9a0CbWLAhhd timestampmhexpmmplugm1.1.9hhba aha a9a0CbWLAhhd timestampmhexpmmplugm1.7.2hhba aha a9a0dbWLAhhddepsmhexpmmplugm0.11.0lhmhexpmmcowboymcowboym~> 1.0dtruej\bWLAhhdouter_checksummhexpmmpostgrexm0.8.2m Ac#=B0YO1uдfQ]L=ߨYbWLAhhdouter_checksummhexpmmplugm0.10.0m a{9 aH5;7KC]ϖ5"Qy!qJ[bWLAhhdinner_checksummhexpmmphoenixm0.3.0m |&QP?Xߛ*, b\^G>&݌^bWLAhhdinner_checksummhexpmmjasonm 1.0.0-rc.2m *]f?v7@.FV)FbWLAhhd timestampmhexpmmphoenixm0.2.0hhba aha a9a0wbWLAhhddepsmhexpmm db_connectionm2.1.1lhmhexpmm connectionm connectionm~> 1.0.2dfalsejXbWLAhhdinner_checksummhexpmmplugm1.1.3m ,Cp~imL`Z[bWLAhhdouter_checksummhexpmmphoenixm1.3.2m Cn [N24z9Or|Ex۶bbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.1.2m Il0;.n[::75KM*Z>9bWLAhhd timestampmhexpmmmimehhba aha a9a0[bWLAhhdouter_checksummhexpmmdecimalm1.5.0m  &XUMu_]r?3ɻ9W⡭.YbWLAhhdouter_checksummhexpmmjasonm1.1.0m #aJc5o( ǫh_QЄR68lRbWLAhhd registry_etagmhexpmmphoenixm""584b1d4ed74a3b1ef299dc3546ce0746"_bWLAhhdinner_checksummhexpmm plug_cowboym2.2.0m 1{Qp"YrA z $bWLAhhddepsmhexpmmphoenixm1.0.5lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejbbWLAhhdouter_checksummhexpmmpostgrexm 0.13.0-rc.0m &[ضY H5, "_bWLAhhdinner_checksummhexpmm plug_cryptom1.1.0m HCՐbOH%oGU]ɇT.GbWLAhhd timestampmhexpmmpostgrexm0.4.2hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm0.6.2dnilFbWLAhhd timestampmhexpmmdecimalm1.7.0hhba aha a9a0;bWLAhhdretiredmhexpmm db_connectionm2.0.1dnilFbWLAhhd timestampmhexpmmdecimalm1.8.0hhba aha a9a0bbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.1.0m B.*ҞKna߄*cz;e,\bWLAhhdouter_checksummhexpmmphoenixm0.16.0m !,@X _F([bWLAhhdinner_checksummhexpmmphoenixm0.2.2m "r4|2_IijJPtT fBCbWLAhhd timestampmhexpmmphoenix_paramshhba aha a9a0;bWLAhhdretiredmhexpmm db_connectionm2.0.2dnilabWLAhhdinner_checksummhexpmm db_connectionm2.0.5m ݲga+}&MӐgBm\$I2:bWLAhhdretiredmhexpmm phoenix_htmlm2.6.0dnilCbWLAhhd timestampmhexpmmplugm1.4.2hhba aha a9a0cbWLAhhddepsmhexpmmplugm1.0.6lhmhexpmmcowboymcowboym~> 1.0dtruejbbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.0.0m ,{?\MfVI$iqr`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.1.2m gKHuE?zDFx9 7to6bbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.0.1m J/a?bsBqv˗ Ә[bWLAhhdouter_checksummhexpmmphoenixm0.2.6m xJlӐ,ϔMwYe`?fbWLAhhddepsmhexpmmjasonm1.0.0lhmhexpmmdecimalmdecimalm~> 1.0dtruej;bWLAhhdretiredmhexpmm db_connectionm2.2.1dnil3bWLAhhdretiredmhexpmmplugm0.13.1dnil`bWLAhhdinner_checksummhexpmmdecimalm 1.9.0-rc.0m cfja8{@<Lp}bbWLAhhdinner_checksummhexpmmphoenix_paramsm0.2.1m ftӓ~_2G0WY_ 9a KbWLAhhd timestampmhexpmm phoenix_htmlm1.1.0hhba aha a9a09bWLAhhdretiredmhexpmm plug_cowboym2.0.2dnilbWLAhhddepsmhexpmmplugm1.3.2lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejbWLAhhddepsmhexpmm plug_cowboym2.2.1lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej[bWLAhhdinner_checksummhexpmmphoenixm0.5.0m tlAe-8æ%Z6@*:bWLAhhdretiredmhexpmmdecimalm 2.0.0-rc.0dnilXbWLAhhdinner_checksummhexpmmplugm0.4.4m ÃnOWs˧'S/M)WWbWLAhhddepsmhexpmmphoenixm1.2.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.1dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejXbWLAhhdinner_checksummhexpmmplugm1.8.2m ڤ I9@wa\;Y t@'bWLAhhddepsmhexpmmpostgrexm 0.14.0-rc.0lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm ~> 2.0-rc.0dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsehmhexpmmjasonmjasonm~> 1.0dtruejFbWLAhhd timestampmhexpmmphoenixm1.1.1hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm1.3.4dnil[bWLAhhdouter_checksummhexpmmdecimalm1.0.1m dk+5~ kƿF|xwt;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.2dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.1dnilLbWLAhhd timestampmhexpmm db_connectionm0.1.1hhba aha a9a0LbWLAhhd timestampmhexpmm phoenix_htmlm2.10.1hhba aha a9a07bWLAhhdretiredmhexpmm telemetrym0.4.2dnil[bWLAhhdouter_checksummhexpmmdecimalm1.6.0m $@@s`I*sGHM:bJibWLAhhddepsmhexpmm plug_cowboym2.1.0lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsejFbWLAhhd timestampmhexpmmphoenixm1.2.5hhba aha a9a06bWLAhhdretiredmhexpmmpostgrexm0.4.2dnil:bWLAhhdretiredmhexpmm phoenix_htmlm2.9.1dnil_bWLAhhdouter_checksummhexpmm plug_cowboym2.2.2m #dۭ7SՈ~^Pbf17']bWLAhhdinner_checksummhexpmmpostgrexm0.13.3m wϲMDZr$3YaDo%51h+sbWLAhhddepsmhexpmm phoenix_htmlm2.0.1lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejwbWLAhhddepsmhexpmm db_connectionm2.0.1lhmhexpmm connectionm connectionm~> 1.0.2dfalsejbWLAhhddepsmhexpmmphoenixm0.2.5lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmplugmplugm0.4.4dfalsej'bWLAhhddepsmhexpmmphoenixm1.3.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.0.0m JnPp~ղi>TCHYF>!\5"bWLAhhddepsmhexpmmphoenixm1.4.2lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejGbWLAhhd timestampmhexpmmphoenixm0.2.10hhba aha a9a0\bWLAhhdouter_checksummhexpmmpostgrexm0.7.0m p/E-F.p?~) 1.0.1 or ~> 1.1 or ~> 2.1dtruehmhexpmmmimemmimem~> 1.0dfalsejbWLAhhddepsmhexpmm db_connectionm 1.0.0-rc.2lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0.0-beta.2dtruejdbWLAhhddepsmhexpmmplugm0.12.1lhmhexpmmcowboymcowboym~> 1.0dtruejCbWLAhhd timestampmhexpmmplugm0.5.2hhba aha a9a0`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.4.0m "s3f?r&Yg~?f׹KwbWLAhhddepsmhexpmm db_connectionm2.0.6lhmhexpmm connectionm connectionm~> 1.0.2dfalsejbbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.0.1m b7|Kչ .: NjYbWLAhhdouter_checksummhexpmmjasonm1.2.2m (򟞮aðvhя!y[bWLAhhdouter_checksummhexpmmphoenixm1.2.0m l@CF/l,86B"D^xQ_UnrbWLAhhddepsmhexpmmphoenix_paramsm0.2.0lhmhexpmmphoenixmphoenixm~> 1.3.3dfalsejMbWLAhhd timestampmhexpmmphoenix_paramsm1.0.1hhba aha a9a0XbWLAhhdinner_checksummhexpmmplugm1.4.1m .g} bWLAhhd timestampmhexpmm telemetryhhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm1.4.0hhba aha a9a0ibWLAhhddepsmhexpmm phoenix_htmlm2.13.2lhmhexpmmplugmplugm~> 1.5dfalsejXbWLAhhdinner_checksummhexpmmplugm1.1.4m .B n[1vMoaB+Ű.Ι\bWLAhhdinner_checksummhexpmmpostgrexm0.8.4m 4Ma W`7ℋ*Z-Ⴛ\ڧ,E5abWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.4m vٙ84*F"\h402i gFbWLAhhd timestampmhexpmmphoenixm1.1.8hhba aha a9a0MbWLAhhd timestampmhexpmmpostgrexm 0.14.0-rc.1hhba aha a9a0LbWLAhhd timestampmhexpmm phoenix_htmlm2.14.2hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm0.8.0hhba aha a9a05bWLAhhdretiredmhexpmmdecimalm1.1.2dnilKbWLAhhd timestampmhexpmmphoenixm 1.3.0-rc.3hhba aha a9a0ybWLAhhdversionsmhexpmmmimelm0.0.1m1.0.0m1.0.1m1.1.0m1.2.0m1.3.0m1.3.1m1.4.0jYc$ph-6`g^TbWLAhhddepsmhexpmmplugm1.2.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsej`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.3.0m E~<&[_^ N5bWLAhhdretiredmhexpmmphoenixm1.4.2dnilLbWLAhhd timestampmhexpmm db_connectionm0.1.0hhba aha a9a0:bWLAhhdretiredmhexpmm phoenix_htmlm2.5.1dnil'bWLAhhddepsmhexpmmphoenixm1.3.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej'bWLAhhddepsmhexpmmphoenixm1.3.4lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsejfbWLAhhddepsmhexpmmjasonm1.1.2lhmhexpmmdecimalmdecimalm~> 1.0dtruejbbWLAhhdinner_checksummhexpmmphoenix_paramsm1.0.0m LrـݨہJWU6)T:bWLAhhddepsmhexpmmplugm1.10.3lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejCbWLAhhd timestampmhexpmmplugm0.6.0hhba aha a9a05bWLAhhdretiredmhexpmmdecimalm0.1.1dnilLbWLAhhd timestampmhexpmm db_connectionm2.1.0hhba aha a9a0LbWLAhhd timestampmhexpmm phoenix_htmlm2.10.2hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.8.3m K8-ĄI**w 3N'4\bWLAhhdouter_checksummhexpmmpostgrexm0.5.4m A㔬 N]1P$LԲJyd<@abWLAhhdouter_checksummhexpmm db_connectionm0.2.4m J}g|i#q?g<8ԧCbWLAhhd timestampmhexpmmmimem1.0.0hhba aha a9a02bWLAhhdretiredmhexpmmplugm1.3.5dnil2bWLAhhdretiredmhexpmmplugm1.0.6dnil_bWLAhhdouter_checksummhexpmm plug_cowboym2.0.1m s nh4jQQ@! 1.0dtruehmhexpmmplugmplugm~> 0.9.0dfalsehmhexpmmpoisonmpoisonm~> 1.2dfalsej[bWLAhhdinner_checksummhexpmmphoenixm0.2.8m _3uDj*EЏ%e I}=cbbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.0.2m Rx^ QQXR?45bWLAhhdretiredmhexpmmphoenixm0.3.1dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.0.0m >ִZPA$<y5PτWDzi FbWLAhhd timestampmhexpmmphoenixm1.1.3hhba aha a9a0dbWLAhhddepsmhexpmmplugm0.12.0lhmhexpmmcowboymcowboym~> 1.0dtruej-bWLAhhddepsmhexpmmdecimalm1.4.0j:bWLAhhdretiredmhexpmm phoenix_htmlm2.9.3dnilbbWLAhhdouter_checksummhexpmmphoenix_paramsm0.1.1m p> ]P_eT )# 00[bWLAhhdinner_checksummhexpmmdecimalm1.8.1m ?_4( 57@)Nޅ3SoEh٬<[bWLAhhdinner_checksummhexpmmphoenixm0.2.6m '1C &Sno1lmbu Q^I2bWLAhhdretiredmhexpmmplugm1.6.1dnilCbWLAhhd timestampmhexpmmplugm0.7.0hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm1.2.4dnil 1.0dtruejFbWLAhhd timestampmhexpmmphoenixm0.2.7hhba aha a9a0jbWLAhhdversionsmhexpmm telemetrylm0.1.0m0.2.0m0.3.0m0.4.0m0.4.1m0.4.2j3bWLAhhdretiredmhexpmmplugm0.11.3dnilFbWLAhhd timestampmhexpmmphoenixm1.0.2hhba aha a9a0YbWLAhhdinner_checksummhexpmmplugm0.11.1m +.W)yyڴ8w1q.o4&\bWLAhhdouter_checksummhexpmmphoenixm0.17.1m L+bP"n tߔҋۑKbWLAhhd timestampmhexpmm phoenix_htmlm2.8.0hhba aha a9a0bWLAhhddepsmhexpmmplugm1.2.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsej[bWLAhhdouter_checksummhexpmmphoenixm1.4.2m Q8|YΥS*rUŨa,AB|F|kMKXXbWLAhhdouter_checksummhexpmmplugm1.5.1m 1-]yuCSN!nj6DbWLAhhd timestampmhexpmmplugm0.12.1hhba aha a9a02bWLAhhdretiredmhexpmmplugm1.3.2dnil\bWLAhhdouter_checksummhexpmmphoenixm0.11.0m @7#&[vnf"ď?O#y*abWLAhhdinner_checksummhexpmm db_connectionm1.1.0m /{XM َV z ڶ&3Tͳ\bWLAhhdinner_checksummhexpmmpostgrexm0.8.0m g]MJEJ`j컆E&З4X abWLAhhdinner_checksummhexpmm phoenix_htmlm2.13.2m |Έ`}+R'1OkA4W\bWLAhhdinner_checksummhexpmmpostgrexm0.9.0m 1"I#Jw<-c 'edBMe\6bWLAhhdretiredmhexpmmpostgrexm0.5.3dnilbWLAhhddepsmhexpmmphoenix_paramsm1.1.0lhmhexpmmdecimalmdecimalm>= 1.7.0dfalsehmhexpmmphoenixmphoenixm>= 1.3.3dfalsej[bWLAhhdinner_checksummhexpmmphoenixm1.1.6m {fi/Z0ڷ=b(ս*BkGCbWLAhhd timestampmhexpmmplugm1.6.2hhba aha a9a0abWLAhhdouter_checksummhexpmm db_connectionm0.1.3m _0}4ٰH>X5!qKXbWLAhhdinner_checksummhexpmmplugm1.6.4m 5aiE/k7vЙs?'G?8bWLAhhdretiredmhexpmm connectionm1.0.4dnilbWLAhhdversionsmhexpmmphoenix_pubsubl m0.0.1m0.1.0m 1.0.0-rc.0m1.0.0m1.0.1m1.0.2m1.1.0m1.1.1m1.1.2m2.0.0jCbWLAhhd timestampmhexpmmplugm1.3.5hhba aha a9a0CbWLAhhd timestampmhexpmmplugm1.3.3hhba aha a9a03bWLAhhdretiredmhexpmmplugm0.11.2dnilLbWLAhhd timestampmhexpmm db_connectionm2.1.1hhba aha a9a0GbWLAhhd timestampmhexpmmphoenixm0.10.0hhba aha a9a07bWLAhhdretiredmhexpmmpostgrexm0.15.0dnil2bWLAhhdretiredmhexpmmplugm1.1.5dnil6bWLAhhdretiredmhexpmmphoenixm0.2.10dnil2bWLAhhdretiredmhexpmmplugm1.3.4dnil5bWLAhhdretiredmhexpmmdecimalm1.4.1dnil;bWLAhhdretiredmhexpmm db_connectionm2.0.5dnilFbWLAhhd timestampmhexpmmdecimalm1.6.0hhba aha a9a0bWLAhhddepsmhexpmmphoenixm1.1.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej[bWLAhhdouter_checksummhexpmmphoenixm1.0.1m s$DeOă&x Uk4ACbWLAhhd timestampmhexpmmmimem1.3.0hhba aha a9a0abWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.5m Ot"D s*VlN3|(O XbWLAhhdinner_checksummhexpmmplugm1.1.6m '3Y8|(71'3PfXbWLAhhdouter_checksummhexpmmplugm1.0.1m Lq ۖ}|e7;dabWLAhhdouter_checksummhexpmm db_connectionm2.2.2m d*@بZo+'$%Ӄq6 MbWLAhhd timestampmhexpmmphoenix_pubsubm0.0.1hhba aha a9a07bWLAhhdretiredmhexpmmpostgrexm0.13.2dnil\bWLAhhdinner_checksummhexpmmpostgrexm0.7.0m ;k%W#Ȝ;*)>bWLAhhdretiredmhexpmm phoenix_htmlm 2.7.0-devdnilKbWLAhhd timestampmhexpmm phoenix_htmlm1.0.0hhba aha a9a0abWLAhhdinner_checksummhexpmm db_connectionm2.0.6m ]yiŵ cHzĪ_9bbWLAhhdinner_checksummhexpmmphoenix_paramsm0.4.2m mREM ms$;XbWLAhhdouter_checksummhexpmmplugm1.1.4m !&=zq(H#10rVƨTmݔ%M[bWLAhhdinner_checksummhexpmmphoenixm1.5.4m ʜ`Ic _%[ g~p?LbWLAhhd timestampmhexpmm phoenix_htmlm2.10.4hhba aha a9a0lbWLAhhddepsmhexpmmpostgrexm0.5.2lhmhexpmmdecimalmdecimalm~> 0.2.1dfalsej5bWLAhhdretiredmhexpmmdecimalm1.2.0dnil7bWLAhhdretiredmhexpmm telemetrym0.4.0dnil]bWLAhhdouter_checksummhexpmmpostgrexm0.15.4m 0euG7}ÿq|3?:=! `bWLAhhdouter_checksummhexpmm phoenix_htmlm1.4.0m jJZ:bxhk ~RsXI֟kLYbWLAhhdouter_checksummhexpmmplugm1.10.2m xGgﳹ%p^f;ō*ؚZYbWLAhhdouter_checksummhexpmmplugm0.14.0m qh5Y#oAf]h0=LbWLAhhd timestampmhexpmm db_connectionm0.2.0hhba aha a9a0[bWLAhhdinner_checksummhexpmmphoenixm1.4.5m n ? e?E 7]t5bWLAhhdretiredmhexpmmphoenixm0.2.7dnilHbWLAhhd timestampmhexpmmpostgrexm0.13.4hhba aha a9a0]bWLAhhdouter_checksummhexpmmplugm 1.5.0-rc.2m 8TUHlH̖"4jaLXbWLAhhdouter_checksummhexpmmmimem1.3.0m ^(`2j` Ɠݫ%y{ffS(3bWLAhhdretiredmhexpmmplugm0.11.0dnilXbWLAhhdouter_checksummhexpmmplugm1.4.3m zLe5"e۹zFk6LabbWLAhhdouter_checksummhexpmmphoenix_paramsm1.1.3m 7"R,ݮ80 j+>_|;bWLAhhdretiredmhexpmm phoenix_htmlm2.12.0dnil]bWLAhhdinner_checksummhexpmmpostgrexm0.15.2m -4=MԊ*5V;(Z5bWLAhhdretiredmhexpmmphoenixm1.2.5dnilFbWLAhhd timestampmhexpmmphoenixm1.2.2hhba aha a9a0abWLAhhdouter_checksummhexpmmpostgrexm 1.0.0-rc.1m SB!J1DLtz+v~O-$f|>o3\bWLAhhdouter_checksummhexpmmpostgrexm0.5.1m taj6[Vn3JMvsbWLAhhddepsmhexpmm phoenix_htmlm2.4.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejbWLAhhddepsmhexpmmplugm1.5.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.1dtruehmhexpmmmimemmimem~> 1.0dfalsej5bWLAhhdretiredmhexpmmphoenixm1.4.9dnilFbWLAhhd timestampmhexpmmphoenixm1.3.3hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm0.2.3hhba aha a9a0[bWLAhhdouter_checksummhexpmmdecimalm0.2.1m v2 T80W'u̶J2 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej\bWLAhhdouter_checksummhexpmmphoenixm0.15.0m ijLvȮB.At"u >V!:bWLAhhdretiredmhexpmm phoenix_htmlm2.3.0dnilabWLAhhdinner_checksummhexpmmpostgrexm 1.0.0-rc.1m &w%!EeFZbWLAhhddepsmhexpmmphoenixm1.5.0lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejFbWLAhhd timestampmhexpmmphoenixm1.5.0hhba aha a9a0*bWLAhhddepsmhexpmmplugm0.5.0jCbWLAhhd timestampmhexpmmplugm0.8.3hhba aha a9a02bWLAhhdretiredmhexpmmplugm1.1.9dnil\bWLAhhdinner_checksummhexpmmpostgrexm0.5.1m ]]<$Ă0g_||^bWLAhhdouter_checksummhexpmmjasonm 1.0.0-rc.3m tE;#:˛V83;jWD+lE,KbWLAhhd timestampmhexpmm phoenix_htmlm2.1.2hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm1.4.0dnilbWLAhhddepsmhexpmmphoenixm0.2.7lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.1dfalsehmhexpmmplugmplugm0.4.4dfalsej7bWLAhhdretiredmhexpmmpostgrexm0.12.2dnil\bWLAhhdouter_checksummhexpmmpostgrexm0.5.2m L~ĵT9 &VYbWLAhhdinner_checksummhexpmmplugm1.10.1m jm-XY;T ҇@/bWLAhhdversionsmhexpmm phoenix_htmll0m1.0.0m1.0.1m1.1.0m1.2.0m1.2.1m1.3.0m1.4.0m 2.0.0-devm2.0.0m2.0.1m2.1.0m2.1.1m2.1.2m2.2.0m2.3.0m2.3.1m 2.4.0-devm2.4.0m2.5.0m2.5.1m2.6.0m2.6.1m2.6.2m 2.7.0-devm2.7.0m2.8.0m2.9.0m2.9.1m2.9.2m2.9.3m2.10.0m2.10.1m2.10.2m2.10.3m2.10.4m2.10.5m2.11.0m2.11.1m2.11.2m2.12.0m2.13.0m2.13.1m2.13.2m2.13.3m2.13.4m2.14.0m2.14.1m2.14.2jCbWLAhhd timestampmhexpmmplugm1.0.4hhba aha a9a0`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.9.0m ŔEtYLjU yL{D+bWLAhhddepsmhexpmmphoenixm0.13.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.5.1 or ~> 1.6dtruejLbWLAhhd timestampmhexpmm db_connectionm2.0.6hhba aha a9a0ibWLAhhddepsmhexpmm phoenix_htmlm2.10.3lhmhexpmmplugmplugm~> 1.0dfalsej[bWLAhhdinner_checksummhexpmmphoenixm0.2.3m ^v& G prYY/ y/$~SibWLAhhddepsmhexpmm phoenix_htmlm2.14.1lhmhexpmmplugmplugm~> 1.5dfalsej;bWLAhhd timestampmhexpmmcowboyhhbaaha aaabWLAhhdouter_checksummhexpmm db_connectionm2.0.3m =yY 7uqtY**ͅI4&4bWLAhhddepsmhexpmmphoenix_pubsubm1.0.2jLbWLAhhd timestampmhexpmm db_connectionm0.2.3hhba aha a9a0DbWLAhhd timestampmhexpmmjasonm1.1.2hhba aha a9a0]bWLAhhdinner_checksummhexpmmpostgrexm0.15.1m #4pA[ڼƆ i%,o;[G/:bWLAhhdretiredmhexpmmphoenixm 1.4.0-rc.0dnil]bWLAhhdouter_checksummhexpmmpostgrexm0.13.0m H*zE\̤8@B;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.5dnilcbWLAhhddepsmhexpmmplugm1.1.6lhmhexpmmcowboymcowboym~> 1.0dtruejbbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.1.2m ig)tѕR@i8[bWLAhhdouter_checksummhexpmmdecimalm1.4.1m #{RNUV]JrV&hL{ʀ_;abWLAhhdouter_checksummhexpmm db_connectionm2.0.4m RKK eP3$#YbWLAhhdinner_checksummhexpmmjasonm1.1.1m ̸@߰o/56MH#X^abWLAhhdouter_checksummhexpmm phoenix_htmlm2.11.0m 6h+2INp#9:@7}~Ne h_)2bWLAhhdretiredmhexpmmplugm1.1.2dnilXbWLAhhdinner_checksummhexpmmmimem0.0.1m s3ާj2Ӭeěs!>&9bWLAhhddepsmhexpmmphoenix_pubsubm 1.0.0-rc.0jYbWLAhhdouter_checksummhexpmmplugm0.11.1m M}O໿Fk΍]/]/9ݸXbWLAhhdinner_checksummhexpmmplugm0.9.0m c"&Ù]!UWrƒD[bWLAhhdouter_checksummhexpmmphoenixm0.5.0m /ߌͥB( P fk.OabWLAhhdouter_checksummhexpmm db_connectionm0.2.2m 8.ߖc0 uMk6;bWLAhhdretiredmhexpmm db_connectionm1.1.1dnil`bWLAhhdouter_checksummhexpmmphoenixm 1.3.0-rc.1m v,TOƿ<~RS7=b]bWLAhhdouter_checksummhexpmmpostgrexm0.14.0m mO 1~SpR3≵u/PsbWLAhhddepsmhexpmm phoenix_htmlm2.3.1lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejGbWLAhhd timestampmhexpmmpostgrexm0.9.1hhba aha a9a0HbWLAhhd timestampmhexpmmpostgrexm0.14.3hhba aha a9a0XbWLAhhdinner_checksummhexpmmplugm1.3.0m n+?JBE(W Dk̒Dz*bWLAhhddepsmhexpmmplugm0.5.2j[bWLAhhdinner_checksummhexpmmphoenixm1.0.6m ד kK[=rEMWhFbWLAhhd timestampmhexpmmphoenixm0.2.8hhba aha a9a02bWLAhhdretiredmhexpmmplugm1.2.1dnil]bWLAhhdinner_checksummhexpmm telemetrym0.4.0m 9˄L)5sm U84[bWLAhhdinner_checksummhexpmmphoenixm1.0.4m /(L#:ߋkK2}?LJn@bWLAhhdretiredmhexpmm db_connectionm 1.0.0-rc.1dnil`bWLAhhdinner_checksummhexpmmphoenixm 1.4.0-rc.2m _ 4a KCGE(/gͮoYKbWLAhhd timestampmhexpmm phoenix_htmlm2.1.1hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.2.6m P;hQ>y4Ԇ-.rQL$"4bWLAhhddepsmhexpmmplugm1.3.4lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejabWLAhhdinner_checksummhexpmm phoenix_htmlm2.13.0m ;^lYz ?GALV,A wbWLAhhddepsmhexpmm phoenix_htmlm1.2.0lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsejbWLAhhdretiredmhexpmm plug_cryptom1.1.1tdmessagem/Wrong default value is used for salt on encryptdreasondRETIRED_INVALIDCbWLAhhd timestampmhexpmmmimem0.0.1hhba aha a9a05bWLAhhdretiredmhexpmmdecimalm0.2.5dnilbbWLAhhdinner_checksummhexpmmphoenix_paramsm0.1.0m Ka$Nt,68M2r]bWLAhhdinner_checksummhexpmmpostgrexm0.14.3m WT8ߖBxp vAwe4Z2bWLAhhdretiredmhexpmmplugm1.6.2dnil:bWLAhhdretiredmhexpmm phoenix_htmlm2.6.2dnilYbWLAhhdinner_checksummhexpmmplugm0.12.0m =o.?Eg b,?(y3ObWLAhhd timestampmhexpmm phoenix_htmlm 2.7.0-devhhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.2.1m = ;BoƳa+]>FfbWLAhhdinner_checksummhexpmm db_connectionm 1.0.0-rc.2m Ų2Qm~G=qe-gXFbWLAhhd timestampmhexpmmdecimalm1.5.0hhba aha a9a07bWLAhhdretiredmhexpmm telemetrym0.3.0dnil[bWLAhhdouter_checksummhexpmmphoenixm1.3.0m 5̑l7O2O/]eeSlwbWLAhhddepsmhexpmm db_connectionm2.1.0lhmhexpmm connectionm connectionm~> 1.0.2dfalsejXbWLAhhdinner_checksummhexpmmplugm1.0.2m 4)ȏưMq/gV@Lꗦ1:Iʨ#nbWLAhhddepsmhexpmm plug_cowboym2.1.2lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsejAbWLAhhdretiredmhexpmmphoenix_pubsubm 1.0.0-rc.0dnilYbWLAhhdouter_checksummhexpmmplugm1.10.0m B*'g; {w[-퐏2dA^J;bWLAhhdretiredmhexpmm db_connectionm0.1.0dnil5bWLAhhdretiredmhexpmmphoenixm1.1.2dnil[bWLAhhdinner_checksummhexpmmphoenixm0.4.0m *S]PoH39B;(X5uhjXbWLAhhdouter_checksummhexpmmplugm1.0.5m -Ьh80"w=-w7bWLAhhdretiredmhexpmmpostgrexm0.15.3dnil6bWLAhhdretiredmhexpmmphoenixm1.4.16dnil4bWLAhhddepsmhexpmmphoenix_pubsubm1.0.0jbWLAhhddepsmhexpmmplugm1.10.1lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruej2bWLAhhdretiredmhexpmmplugm0.8.1dnilHbWLAhhd timestampmhexpmmpostgrexm0.10.0hhba aha a9a0[bWLAhhdouter_checksummhexpmmdecimalm1.1.2m zmM8׸8P"H|h=3Q㦑]bWLAhhdinner_checksummhexpmmplugm 1.2.0-rc.0m Yqr}Ђc.4wp2bWLAhhdretiredmhexpmmplugm1.9.0dnilXbWLAhhdinner_checksummhexpmmmimem1.3.0m ^EP O`J4Ǣ QQ[bWLAhhdinner_checksummhexpmmphoenixm0.7.0m *~t@ `fNV][:;MY3bWLAhhdretiredmhexpmmjasonm1.0.0dnil`bWLAhhdouter_checksummhexpmmphoenixm 1.4.0-rc.3m SJjJDv.8[˭FOn>35abWLAhhdinner_checksummhexpmm db_connectionm0.2.2m v I<^Ο+*(mܽ4XbWLAhhdouter_checksummhexpmmplugm0.5.2m }8gD'CviD@ӋVSHbWLAhhd timestampmhexpmmpostgrexm0.11.0hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.1.5m phq=fLKΪP4@P1cM=XbWLAhhdinner_checksummhexpmmplugm1.7.2m ׷u^ }D"7.YbWLAhhdouter_checksummhexpmmplugm0.11.3m O0% Ԣq\%V#4^Ie[bWLAhhdinner_checksummhexpmmphoenixm1.1.4m e7srZVeK@nw<|1CbWLAhhd timestampmhexpmmplugm1.7.0hhba aha a9a09bWLAhhdretiredmhexpmm plug_cowboym2.0.0dnil_bWLAhhdinner_checksummhexpmm plug_cowboym2.1.2m ݵR8ÎD.'2F]|Gŀ^CbWLAhhd timestampmhexpmmplugm1.1.6hhba aha a9a0jbWLAhhddepsmhexpmmpostgrexm0.8.4lhmhexpmmdecimalmdecimalm~> 1.0dfalsejbWLAhhddepsmhexpmmpostgrexm0.15.4lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.1dfalsehmhexpmmdecimalmdecimalm~> 1.5dfalsehmhexpmmjasonmjasonm~> 1.0dtruejabWLAhhdouter_checksummhexpmm phoenix_htmlm2.11.1m LEwOJZrBx4iŢgϮ`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.7.0m h׫~~څ1m%s{q ORNwQbWLAhhd timestampmhexpmm db_connectionm 1.0.0-rc.1hhba aha a9a0IbWLAhhd timestampmhexpmmjasonm 1.0.0-rc.1hhba aha a9a0\bWLAhhdouter_checksummhexpmmphoenixm0.16.1m 8NP ޱ7|zɚ*bWLAhhddepsmhexpmmmimem1.0.0j5bWLAhhdretiredmhexpmmdecimalm0.2.0dnil_bWLAhhdinner_checksummhexpmm plug_cowboym2.0.2m `UhhHKncҺڔIxA3w*lbWLAhhddepsmhexpmmplugm1.5.1lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.3dtruehmhexpmmmimemmimem~> 1.0dfalsejXbWLAhhdinner_checksummhexpmmplugm0.5.2m |"Wž/1޹\T5 J]bWLAhhdinner_checksummhexpmm telemetrym0.4.1m 'HHD$GjA|2w(ttRbWLAhhddepsmhexpmmphoenixm1.1.9lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej2bWLAhhdretiredmhexpmmplugm1.1.7dnil[bWLAhhdouter_checksummhexpmmdecimalm1.7.0m wvPZՊOW\_`e]GbWLAhhd timestampmhexpmmpostgrexm0.8.4hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm0.8.0m dgz1R,GdSv*>0bWLAhhddepsmhexpmm connectionm1.0.0j5bWLAhhdretiredmhexpmmphoenixm1.0.0dnil]bWLAhhdouter_checksummhexpmm telemetrym0.4.1m G88.6]g`,V m)ތXHLbWLAhhd timestampmhexpmm db_connectionm2.2.2hhba aha a9a0[bWLAhhdinner_checksummhexpmmphoenixm1.1.7m 4ظ ?TL_?85ȭaUcbWLAhhddepsmhexpmmplugm0.8.3lhmhexpmmcowboymcowboym~> 1.0dtruejXbWLAhhdinner_checksummhexpmmmimem1.0.1m Ó$v}6'qbCM$zQ[bWLAhhdinner_checksummhexpmmphoenixm1.4.2m :P e; T4iM]bWLAhhdouter_checksummhexpmm telemetrym0.3.0m c}11b!1 Z6h!/r-bWLAhhddepsmhexpmmdecimalm0.2.3j[bWLAhhdouter_checksummhexpmmphoenixm0.2.3m o, B)| X0piXbWLAhhdinner_checksummhexpmmplugm1.4.2m ğ :?a`j!UFbWLAhhd timestampmhexpmmphoenixm0.2.1hhba aha a9a0bWLAhhddepsmhexpmmphoenixm1.1.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejLbWLAhhd timestampmhexpmm db_connectionm2.0.3hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm0.6.1hhba aha a9a0wbWLAhhddepsmhexpmm db_connectionm2.0.5lhmhexpmm connectionm connectionm~> 1.0.2dfalsejbbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.1.1m fhׇ$z_i̘Q6 <MbWLAhhd timestampmhexpmmphoenix_pubsubm0.1.0hhba aha a9a0_bWLAhhdinner_checksummhexpmm plug_cowboym2.0.1m טZ̆-DPf\#nQ2Az[bWLAhhdinner_checksummhexpmmphoenixm1.4.7m 弚Lu R}Zl*<awm5bWLAhhdretiredmhexpmmdecimalm1.4.0dnil5bWLAhhdretiredmhexpmmphoenixm1.0.1dnil9bWLAhhdretiredmhexpmm plug_cowboym2.1.2dnilHbWLAhhd timestampmhexpmmpostgrexm0.15.0hhba aha a9a0sbWLAhhddepsmhexpmm phoenix_htmlm2.1.2lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejWbWLAhhd registry_etagmhexpmm phoenix_htmlm""1afb92af7c2927f48535ea600645d7b3"2bWLAhhdretiredmhexpmmplugm0.9.0dnilLbWLAhhd timestampmhexpmmpostgrexm 1.0.0-rc.0hhba aha a9a0TbWLAhhd registry_etagmhexpmm telemetrym""fd930643205853c2c965911bb8aa90f7"wbWLAhhddepsmhexpmm db_connectionm2.0.0lhmhexpmm connectionm connectionm~> 1.0.2dfalsej5bWLAhhdretiredmhexpmmphoenixm1.1.6dnil[bWLAhhdouter_checksummhexpmmphoenixm0.2.0m D7܆qO6ǁ79*0]P쿺sEi9bWLAhhdretiredmhexpmm plug_cowboym2.3.0dnil[bWLAhhdinner_checksummhexpmmphoenixm1.2.2m 4[RY8ΖlL‰'JDabWLAhhdinner_checksummhexpmm db_connectionm0.1.8m 0}Ա_IU{g]qu>]`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.5.0m rJPwO`.; Sk ۩ ]-A?2bWLAhhdretiredmhexpmmplugm0.5.1dnil5bWLAhhdretiredmhexpmmdecimalm1.0.0dnilbWLAhhddepsmhexpmmphoenix_paramsm1.1.2lhmhexpmmdecimalmdecimalm~> 2.0dfalsehmhexpmmphoenixmphoenixm~> 1.3dfalsejbWLAhhddepsmhexpmmpostgrexm0.10.0lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsej;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.2dnil2bWLAhhdretiredmhexpmmplugm1.4.5dnil[bWLAhhdinner_checksummhexpmmphoenixm1.1.5m >xx*K9YΫK8u2bWLAhhdretiredmhexpmmplugm1.3.3dnilHbWLAhhd timestampmhexpmmplugm 1.5.0-rc.1hhba aha a9a0@bWLAhhdretiredmhexpmm db_connectionm 1.0.0-rc.5dnilbWLAhhddepsmhexpmm plug_cowboym2.2.2lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejLbWLAhhd timestampmhexpmm db_connectionm0.1.7hhba aha a9a0[bWLAhhdinner_checksummhexpmmdecimalm1.1.2m yie{-S{Q<Қ+HkQlBS -bWLAhhddepsmhexpmmdecimalm0.2.2j`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.0.1m wcC$f-fZ$ mK]d!8Z1xbWLAhhddepsmhexpmmphoenixm1.2.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.1dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej5bWLAhhdretiredmhexpmmphoenixm0.2.0dnil[bWLAhhdouter_checksummhexpmmdecimalm1.3.1m WVHGrn\οǫ*wwbWLAhhddepsmhexpmm phoenix_htmlm1.0.1lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsej[bWLAhhdouter_checksummhexpmmphoenixm0.2.9m x*;D4Dc~| d]KbWLAhhd timestampmhexpmmphoenixm 1.4.0-rc.0hhba aha a9a0XbWLAhhdinner_checksummhexpmmmimem1.1.0m =ǸFQ9b4;( cbWLAhhddepsmhexpmmplugm1.1.9lhmhexpmmcowboymcowboym~> 1.0dtruejXbWLAhhdinner_checksummhexpmmplugm1.4.0m '^f^Bl% $m_E;l };bWLAhhdretiredmhexpmm db_connectionm0.2.1dnilabWLAhhdinner_checksummhexpmm phoenix_htmlm2.11.0m m[\VB3x2ba~Weڡl85bWLAhhdretiredmhexpmmphoenixm1.4.5dnilXbWLAhhdinner_checksummhexpmmplugm0.8.1m $0 ;pD/L_awFҐG5bWLAhhdretiredmhexpmmphoenixm1.5.0dnilbWLAhhddepsmhexpmmplugm1.3.5lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej]bWLAhhdouter_checksummhexpmmpostgrexm0.13.4m u|I?7|U^ufX>@D{s2GbWLAhhd timestampmhexpmmpostgrexm0.8.2hhba aha a9a06bWLAhhdretiredmhexpmmpostgrexm0.5.0dnil6bWLAhhdretiredmhexpmmphoenixm1.4.13dnilXbWLAhhdinner_checksummhexpmmplugm1.0.0m ߶ 3]gN{a!<0CbWLAhhd timestampmhexpmmplugm0.8.2hhba aha a9a03bWLAhhdretiredmhexpmmjasonm1.1.0dnilFbWLAhhd timestampmhexpmmdecimalm1.1.1hhba aha a9a0\bWLAhhdinner_checksummhexpmmphoenixm1.4.12m oZ+6I\VA2dc~w39]lXbWLAhhdouter_checksummhexpmmplugm1.5.0m ͜\c~:ɿPtovͲױΓԠ.R2bWLAhhdretiredmhexpmmmimem1.0.1dnilbbWLAhhdouter_checksummhexpmmphoenix_paramsm1.1.0m ; 5(XZRܫDVǓ VabWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.3m W+w=*.@Vz? 2bWLAhhdretiredmhexpmmplugm1.1.3dnilMbWLAhhd timestampmhexpmmphoenix_paramsm0.4.2hhba aha a9a0]bWLAhhdinner_checksummhexpmmplugm 1.5.0-rc.2m ; _A2heu=fog%CbWLAhhd timestampmhexpmmmimem1.0.1hhba aha a9a0:bWLAhhdretiredmhexpmmphoenixm 1.4.0-rc.1dnilYbWLAhhdinner_checksummhexpmmplugm0.11.0m ΰ`P&o@dS52bWLAhhdretiredmhexpmmplugm0.6.0dnilLbWLAhhd timestampmhexpmm db_connectionm0.2.1hhba aha a9a0[bWLAhhdinner_checksummhexpmmdecimalm1.6.0m Mn]CpӔ42_Ӻp0Y 3bWLAhhdretiredmhexpmmplugm0.11.1dnil bWLAhhddepsmhexpmmphoenixm0.5.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmlinguistmlinguistm~> 0.1.2dfalsehmhexpmmplugmplugm~> 0.8.1dfalsehmhexpmmpoisonmpoisonm~> 1.1dfalsejIbWLAhhd timestampmhexpmm connectionm1.0.3hhba aha a9a0KbWLAhhd timestampmhexpmm phoenix_htmlm2.3.0hhba aha a9a0wbWLAhhddepsmhexpmm phoenix_htmlm1.1.0lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsejJbWLAhhd timestampmhexpmm plug_cowboym2.2.0hhba aha a9a0]bWLAhhdinner_checksummhexpmmpostgrexm0.15.5m "Y/0"uAD3/abWLAhhdouter_checksummhexpmm db_connectionm1.1.3m _  Pb_Q7y_*-PCbWLAhhd timestampmhexpmmplugm1.2.5hhba aha a9a0_bWLAhhdouter_checksummhexpmm plug_cryptom1.1.0m ͡ 3%eu|%ʮȧ-l=`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.1.0m `+&}C!kI˯E XbWLAhhdouter_checksummhexpmmmimem1.2.0m MpB `UQ`\([+bWLAhhddepsmhexpmmplugm1.7.2lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsej]bWLAhhdouter_checksummhexpmmplugm 1.5.0-rc.1m A^3\1=ݴGp 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej:bWLAhhdretiredmhexpmmphoenixm 1.3.0-rc.0dnil[bWLAhhdouter_checksummhexpmmphoenixm1.1.8m n^YF%{(l<: ]'viDXbWLAhhdouter_checksummhexpmmplugm1.3.1m b\P1Yu.e34hDJT<YbWLAhhdouter_checksummhexpmmplugm0.11.2m 0Hи#ƢJ-Pr4:bWLAhhdretiredmhexpmm phoenix_htmlm2.4.0dnil[bWLAhhdouter_checksummhexpmmphoenixm1.3.3m (& 1A E-;4sN0]J+KbWLAhhd timestampmhexpmm phoenix_htmlm2.9.1hhba aha a9a0XbWLAhhdinner_checksummhexpmmplugm1.5.0m "K%IREgpgIF [2bWLAhhdretiredmhexpmmplugm0.8.4dnilHbWLAhhd timestampmhexpmmpostgrexm0.14.2hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm0.6.1m ύK lt~/S3ۗhN1bHbWLAhhd timestampmhexpmmplugm 1.4.0-rc.0hhba aha a9a0)bWLAhhddepsmhexpmmphoenixm 1.4.0-rc.0lhmhexpmmcowboymcowboym~> 1.0 or ~> 2.3dtruehmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.6.2 or ~> 1.7dfalsejbWLAhhddepsmhexpmmphoenixm1.0.6lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejRbWLAhhd registry_etagmhexpmmdecimalm""4657f6f92e3c01945c9c9b06b6fd850e"XbWLAhhdouter_checksummhexpmmplugm0.4.3m &[ }yv6[A.qbWLAhhddepsmhexpmmphoenixm1.5.2lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejbWLAhhdversionsmhexpmm db_connectionl'm0.1.0m0.1.1m0.1.2m0.1.3m0.1.4m0.1.5m0.1.6m0.1.7m0.1.8m0.2.0m0.2.1m0.2.2m0.2.3m0.2.4m0.2.5m 1.0.0-rc.0m 1.0.0-rc.1m 1.0.0-rc.2m 1.0.0-rc.3m 1.0.0-rc.4m 1.0.0-rc.5m1.0.0m1.1.0m1.1.1m1.1.2m1.1.3m 2.0.0-rc.0m2.0.0m2.0.1m2.0.2m2.0.3m2.0.4m2.0.5m2.0.6m2.1.0m2.1.1m2.2.0m2.2.1m2.2.2jFbWLAhhd timestampmhexpmmdecimalm1.1.2hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm1.4.6m oI uqqYnb>bWLAhhddepsmhexpmmphoenixm0.2.2lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.0dfalsehmhexpmmplugmplugm0.4.2dfalsej`bWLAhhdouter_checksummhexpmmphoenixm 1.4.0-rc.1m t4<Q7lWHAw>abWLAhhdinner_checksummhexpmm db_connectionm2.1.0m ./bĐkTM " 50CyabWLAhhdinner_checksummhexpmm db_connectionm0.1.3m q&A>DgVjn" f>-bWLAhhddepsmhexpmmdecimalm1.6.0jbWLAhhddepsmhexpmm db_connectionm1.0.0lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0dtruej]bWLAhhdinner_checksummhexpmmpostgrexm0.13.0m GrYUȃ $.佝- `bWLAhhdinner_checksummhexpmm phoenix_htmlm2.1.0m ud*7kH|K~9dƀXbWLAhhdinner_checksummhexpmmplugm1.3.6m ߔKø~Y+QJ _abWLAhhdouter_checksummhexpmm db_connectionm0.1.1m @HLàkM 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejbbWLAhhdouter_checksummhexpmmphoenix_pubsubm0.0.1m SieZc6@1oW: bbWLAhhdinner_checksummhexpmmphoenix_paramsm1.1.1m AY`E_L x 5 abWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.0m .8CN҄W~`s}") .U<=mbWLAhhddepsmhexpmmphoenixm1.0.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejYbWLAhhdinner_checksummhexpmmjasonm1.0.0m |#!Aw&Zqo 1.0dtruejDbWLAhhd timestampmhexpmmplugm1.10.2hhba aha a9a0bWLAhhddepsmhexpmm plug_cowboym2.1.1lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsejrbWLAhhddepsmhexpmmphoenix_paramsm0.1.2lhmhexpmmphoenixmphoenixm~> 1.3.3dfalsej]bWLAhhdouter_checksummhexpmmpostgrexm0.12.1m ۭ{ ]EBIwbWLAhhddepsmhexpmm db_connectionm2.2.2lhmhexpmm connectionm connectionm~> 1.0.2dfalsej2bWLAhhdretiredmhexpmmplugm0.5.2dnilbWLAhhddepsmhexpmmplugm1.2.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsej\bWLAhhdouter_checksummhexpmmpostgrexm0.5.0m -8;lŜa 8j[(5bWLAhhdretiredmhexpmmphoenixm1.2.2dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.14.0dnil6bWLAhhdretiredmhexpmmphoenixm0.17.0dnil2bWLAhhdretiredmhexpmmmimem0.0.1dnil bWLAhhddepsmhexpmmphoenixm0.6.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmlinguistmlinguistm~> 0.1.3dfalsehmhexpmmplugmplugm~> 0.8.2dfalsehmhexpmmpoisonmpoisonm~> 1.2dfalsejcbWLAhhddepsmhexpmmplugm0.8.4lhmhexpmmcowboymcowboym~> 1.0dtruej`bWLAhhdinner_checksummhexpmmphoenixm 1.4.0-rc.3m >Y$z^-c㬭}GknډA)gibWLAhhddepsmhexpmm phoenix_htmlm2.10.5lhmhexpmmplugmplugm~> 1.0dfalsej[bWLAhhdouter_checksummhexpmmphoenixm1.4.0m "ڏe=;;vfÉ=B%̄K5bWLAhhdretiredmhexpmmphoenixm1.4.8dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.11.1dnil 1.0dfalsehmhexpmm db_connectionm db_connectionm ~> 1.0-rc.4dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsej~bWLAhhdretiredmhexpmmpostgrexm 1.0.0-rc.1tdmessagemSuperseded by v0.13.0-rc.0dreasondRETIRED_INVALID6bWLAhhdretiredmhexpmmphoenixm1.4.11dnilbbWLAhhdinner_checksummhexpmmphoenix_paramsm0.3.0m Kzrv-1 8@FXbWLAhhdinner_checksummhexpmmplugm1.6.2m j{һm]ݕp ΈSQ"KَLbWLAhhd timestampmhexpmm phoenix_htmlm2.13.1hhba aha a9a0KbWLAhhd timestampmhexpmm phoenix_htmlm1.0.1hhba aha a9a0abWLAhhdinner_checksummhexpmm phoenix_htmlm2.14.1m }R* G DI f[bWLAhhdouter_checksummhexpmmphoenixm1.1.0m Q>Ob S.- jbWLAhhddepsmhexpmmpostgrexm0.8.3lhmhexpmmdecimalmdecimalm~> 1.0dfalsejCbWLAhhd timestampmhexpmmplugm1.3.6hhba aha a9a0XbWLAhhdinner_checksummhexpmmplugm1.6.1m /b=P Ϙ Fi~)4XnlLbWLAhhd timestampmhexpmm phoenix_htmlm2.14.0hhba aha a9a05bWLAhhdretiredmhexpmmdecimalm0.2.3dnil bWLAhhddepsmhexpmmphoenixm0.4.0lhmhexpmmcowboymcowboym~> 1.0.0dtruehmhexpmmlinguistmlinguistm~> 0.1.2dfalsehmhexpmmplugmplugm0.7.0dfalsehmhexpmmpoisonmpoisonm~> 1.0.1dfalsej1bWLAhhddepsmhexpmm plug_cryptom1.0.0j2bWLAhhdretiredmhexpmmplugm1.2.6dnil^bWLAhhdinner_checksummhexpmm connectionm1.0.3m 1EAk$I5N2!F|:b[5T6WGbWLAhhd timestampmhexpmmphoenixm0.13.0hhba aha a9a0bbWLAhhdinner_checksummhexpmmpostgrexm 0.14.0-rc.1m %P_Y wD;AcL-bWLAhhddepsmhexpmmdecimalm1.1.2jhbWLAhhddepsmhexpmm phoenix_htmlm2.9.1lhmhexpmmplugmplugm~> 1.0dfalsejHbWLAhhd timestampmhexpmmpostgrexm0.13.2hhba aha a9a0fbWLAhhddepsmhexpmmjasonm1.2.0lhmhexpmmdecimalmdecimalm~> 1.0dtruej4bWLAhhddepsmhexpmmphoenix_pubsubm1.1.2j2bWLAhhdretiredmhexpmmplugm1.4.3dnil6bWLAhhdretiredmhexpmmpostgrexm0.5.5dnil9bWLAhhdretiredmhexpmm plug_cryptom1.1.0dnilLbWLAhhd timestampmhexpmm db_connectionm0.1.3hhba aha a9a0 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruej`bWLAhhdouter_checksummhexpmmdecimalm 1.9.0-rc.0m fuEsW\^KE0|dX< G\bWLAhhdinner_checksummhexpmmpostgrexm0.5.0m '59t.γ pbӴ#SN #bWLAhhddepsmhexpmmpostgrexm0.13.5lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.1dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsejbWLAhhddepsmhexpmmplugm1.2.5lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsej;bWLAhhdretiredmhexpmm phoenix_htmlm2.11.2dnilLbWLAhhd timestampmhexpmm db_connectionm2.2.1hhba aha a9a0cbWLAhhddepsmhexpmmplugm1.0.4lhmhexpmmcowboymcowboym~> 1.0dtruej]bWLAhhdouter_checksummhexpmmpostgrexm0.10.0m fOzg#rpzLv^`&3WabWLAhhdouter_checksummhexpmm db_connectionm0.1.4m Jq]53cC t. 8O݁O/bWLAhhddepsmhexpmm telemetrym0.4.0jcbWLAhhddepsmhexpmmplugm1.1.3lhmhexpmmcowboymcowboym~> 1.0dtruejbWLAhhddepsmhexpmmphoenixm0.10.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm ~> 0.11.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.4.2dtruejIbWLAhhd timestampmhexpmm connectionm1.0.2hhba aha a9a0[bWLAhhdinner_checksummhexpmmdecimalm1.3.1m { 0.13 or ~> 1.0dfalsejFbWLAhhd timestampmhexpmmphoenixm1.1.7hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm0.7.1dnilbWLAhhddepsmhexpmmplugm1.2.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsej;bWLAhhdretiredmhexpmm db_connectionm2.0.3dnil[bWLAhhdouter_checksummhexpmmphoenixm1.1.7m MRVA1,OO'kT)1\bWLAhhdinner_checksummhexpmmpostgrexm0.8.2m u?. {'f1&A37 +bWLAhhddepsmhexpmmphoenixm0.17.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej5bWLAhhdretiredmhexpmmphoenixm1.1.0dnilsbWLAhhddepsmhexpmm phoenix_htmlm2.2.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.9.0m ne7WuG5FD))%cA:k .3[bWLAhhdouter_checksummhexpmmphoenixm1.4.1m [t=] xU&MbWLAhhddepsmhexpmmphoenixm0.2.0lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmmplugmplugm0.4.2dfalsejXbWLAhhdinner_checksummhexpmmplugm1.8.1m py9pߠ~L֫X qL:GbWLAhhd timestampmhexpmmphoenixm1.4.13hhba aha a9a0XbWLAhhdouter_checksummhexpmmmimem1.3.1m lvj  1Lc KζE8du*bWLAhhddepsmhexpmmmimem1.4.0jYbWLAhhdinner_checksummhexpmmjasonm1.2.2m CpѪΐi\Vx?RKbWLAhhd timestampmhexpmmphoenixm 1.5.0-rc.0hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm0.3.1hhba aha a9a03bWLAhhdretiredmhexpmmplugm1.10.0dnilbWLAhhddepsmhexpmmplugm1.3.6lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej2bWLAhhdretiredmhexpmmplugm0.4.2dnilFbWLAhhd timestampmhexpmmphoenixm0.2.6hhba aha a9a0XbWLAhhdouter_checksummhexpmmplugm1.7.2m ޘ%o֭ ͈k=e~`k5bWLAhhdretiredmhexpmmdecimalm1.0.1dnil%bWLAhhddepsmhexpmmphoenixm 1.2.0-rc.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm ~> 1.0.0-rcdfalsehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej[bWLAhhdouter_checksummhexpmmdecimalm1.8.1m zabWLAhhdouter_checksummhexpmm phoenix_htmlm2.14.2m X%] |/l\ғpE/;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.4dnilbWLAhhddepsmhexpmmpostgrexm0.15.2lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.1dfalsehmhexpmmdecimalmdecimalm~> 1.5dfalsehmhexpmmjasonmjasonm~> 1.0dtruejbWLAhhddepsmhexpmmplugm1.10.2lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej[bWLAhhdouter_checksummhexpmmphoenixm1.1.3m Wv pwd6Bf&Ͱp`R J^bWLAhhdouter_checksummhexpmm connectionm1.0.2m l ʬZ~AkڵJK8fa 3bWLAhhdretiredmhexpmmplugm1.10.2dnil2bWLAhhdretiredmhexpmmplugm1.2.0dnilHbWLAhhd timestampmhexpmmpostgrexm0.14.0hhba aha a9a0abWLAhhdinner_checksummhexpmm db_connectionm1.1.1m F[\6uɠR`2L9FbWLAhhd timestampmhexpmmphoenixm0.2.9hhba aha a9a0-bWLAhhddepsmhexpmmdecimalm0.1.1jibWLAhhddepsmhexpmm phoenix_htmlm2.10.2lhmhexpmmplugmplugm~> 1.0dfalsejbWLAhhddepsmhexpmm db_connectionm1.1.1lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0dtruejGbWLAhhd timestampmhexpmmpostgrexm0.6.0hhba aha a9a0abWLAhhdouter_checksummhexpmm phoenix_htmlm2.14.0m 0xmra838aQoI?XbWLAhhdouter_checksummhexpmmplugm1.6.3m o/J-s09+ %UpwJ`Qi"bWLAhhddepsmhexpmmphoenixm1.4.1lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruej]bWLAhhdouter_checksummhexpmm telemetrym0.1.0m <1bhxAO\"BMPCD$5bWLAhhdretiredmhexpmmphoenixm1.1.7dnilbWLAhhddepsmhexpmmplugm1.2.6lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsejCbWLAhhd timestampmhexpmmmimem1.3.1hhba aha a9a06bWLAhhdretiredmhexpmmphoenixm0.13.0dnil2bWLAhhdretiredmhexpmmplugm1.1.8dnil3bWLAhhdretiredmhexpmmplugm0.13.0dnil\bWLAhhdinner_checksummhexpmmphoenixm0.16.0m I~TY$G$nc; aZ%w~(8S]bWLAhhdinner_checksummhexpmmplugm 1.5.0-rc.0m f!T`B sU-m(LabWLAhhdinner_checksummhexpmm db_connectionm0.1.5m ^/ :af@<э|Ot*\5cbWLAhhddepsmhexpmmplugm1.1.7lhmhexpmmcowboymcowboym~> 1.0dtruejibWLAhhddepsmhexpmm phoenix_htmlm2.13.3lhmhexpmmplugmplugm~> 1.5dfalsejFbWLAhhd timestampmhexpmmphoenixm1.4.1hhba aha a9a02bWLAhhdretiredmhexpmmmimem1.3.1dnil\bWLAhhdinner_checksummhexpmmphoenixm1.4.15m \90j3RβV)bX+Y(-bWLAhhddepsmhexpmmdecimalm1.2.0jabWLAhhdouter_checksummhexpmm phoenix_htmlm2.13.2m 4gddے*yz#$`bWLAhhdinner_checksummhexpmmphoenixm 1.3.0-rc.1m KH#L^Xeu7bWLAhhddepsmhexpmmphoenixm1.1.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejabWLAhhdinner_checksummhexpmm db_connectionm2.0.1m ELlnB% Ə& S2 lk bWLAhhddepsmhexpmmphoenixm0.6.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmlinguistmlinguistm~> 0.1.4dfalsehmhexpmmplugmplugm~> 0.8.4dfalsehmhexpmmpoisonmpoisonm~> 1.2dfalsej6bWLAhhdretiredmhexpmmphoenixm0.17.1dnilXbWLAhhdouter_checksummhexpmmplugm1.8.1m LX:fɵA~mS>c-bWLAhhddepsmhexpmmdecimalm1.9.0jCbWLAhhd timestampmhexpmmplugm1.1.4hhba aha a9a0wbWLAhhddepsmhexpmm phoenix_htmlm 2.0.0-devlhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej2bWLAhhdretiredmhexpmmmimem1.4.0dnil5bWLAhhdretiredmhexpmmphoenixm0.2.1dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.0dnilLbWLAhhd timestampmhexpmm db_connectionm1.1.2hhba aha a9a0IbWLAhhd timestampmhexpmm connectionm1.0.0hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm1.5.1dnilCbWLAhhd timestampmhexpmmplugm1.3.0hhba aha a9a0bbWLAhhdinner_checksummhexpmmphoenix_paramsm0.4.0m UtM;uX`zQ|Y Ԑ[bWLAhhdinner_checksummhexpmmdecimalm1.1.1m [g1ͬoyo(]nVnvKbWLAhhd timestampmhexpmm phoenix_htmlm2.6.2hhba aha a9a0bWLAhhddepsmhexpmm plug_cowboym2.0.1lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsej 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej]bWLAhhdouter_checksummhexpmmpostgrexm0.13.1m pEXN 䂺1h{z;SEibWLAhhddepsmhexpmm phoenix_htmlm2.10.4lhmhexpmmplugmplugm~> 1.0dfalsejLbWLAhhd timestampmhexpmm phoenix_htmlm2.14.1hhba aha a9a0hbWLAhhddepsmhexpmm phoenix_htmlm2.6.2lhmhexpmmplugmplugm~> 1.0dfalsejXbWLAhhdouter_checksummhexpmmplugm1.2.3m e”ynw^:݃mrH/-PXbWLAhhdouter_checksummhexpmmplugm1.6.1m s?2IC/;bWLAhhdretiredmhexpmm db_connectionm0.1.4dnil[bWLAhhdouter_checksummhexpmmphoenixm1.5.2m 0G#g5ng* 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejfbWLAhhdouter_checksummhexpmm db_connectionm 1.0.0-rc.1m 3w'+HTnC?T45bWLAhhdretiredmhexpmmphoenixm0.2.5dnil[bWLAhhdouter_checksummhexpmmdecimalm0.2.0m &EQ{-D; Mʝ4$ibWLAhhddepsmhexpmm phoenix_htmlm2.13.0lhmhexpmmplugmplugm~> 1.5dfalsej[bWLAhhdinner_checksummhexpmmphoenixm1.1.8m %J&RG ʩB).A-6T\abWLAhhdouter_checksummhexpmm phoenix_htmlm2.13.4m 򕜸'YuRRL clM_bWLAhhdouter_checksummhexpmm plug_cowboym2.0.0m ?IbЙ$m|/.j) ns:tcbWLAhhddepsmhexpmmplugm1.0.3lhmhexpmmcowboymcowboym~> 1.0dtruej3bWLAhhdretiredmhexpmmplugm0.10.0dnil:bWLAhhdretiredmhexpmm phoenix_htmlm2.1.0dnil2bWLAhhdretiredmhexpmmplugm1.2.2dnil5bWLAhhdretiredmhexpmmphoenixm1.2.3dnil5bWLAhhdretiredmhexpmmphoenixm1.2.0dnilbbWLAhhdouter_checksummhexpmmphoenix_pubsubm2.0.0m -O&wKPYuCSPqCbWLAhhd timestampmhexpmmplugm1.0.5hhba aha a9a0bWLAhhddepsmhexpmm db_connectionm 1.0.0-rc.5lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0.0-beta.3dtruej;bWLAhhdretiredmhexpmm db_connectionm0.1.2dnil_bWLAhhdouter_checksummhexpmm plug_cowboym1.0.0m BzD$eE"c2u@JaabWLAhhdinner_checksummhexpmm db_connectionm0.1.4m YUjMxG'*ZZ.8>`bWLAhhdouter_checksummhexpmmphoenixm 1.3.0-rc.2m ap RŸo ,nE4ns,ND7bWLAhhdretiredmhexpmmpostgrexm0.14.1dnil[bWLAhhdouter_checksummhexpmmdecimalm0.2.3m tVX7aCVh`ZV1ւubbWLAhhdinner_checksummhexpmmphoenix_paramsm1.1.2m Tp}%Շz_BF!:ȷryGbWLAhhd timestampmhexpmmphoenixm0.13.1hhba aha a9a0dbWLAhhddepsmhexpmmplugm0.11.3lhmhexpmmcowboymcowboym~> 1.0dtruej]bWLAhhdouter_checksummhexpmmpostgrexm0.11.1m mGOd,@d[w#vO(-[`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.2.0m QR«`ǭ}10R~2*NЇlvbWLAhhddepsmhexpmm db_connectionm0.1.3lhmhexpmmbackoffmbackoffm~> 1.0dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruejXbWLAhhdinner_checksummhexpmmmimem1.0.0m 0's;;]ȶbˁw1TJV6bWLAhhdretiredmhexpmmpostgrexm0.9.1dnilabWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.2m u"cLoМ ֭r*1XbWLAhhdouter_checksummhexpmmplugm0.5.3m E}A[; 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.1dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsejbbWLAhhdouter_checksummhexpmmphoenix_paramsm0.2.1m k<#jwDIdNgFO7wbWLAhhddepsmhexpmm db_connectionm2.0.2lhmhexpmm connectionm connectionm~> 1.0.2dfalsej`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.1.0m tD/}"/Gv"{>_vP]1LbWLAhhd timestampmhexpmm phoenix_htmlm2.10.0hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm0.2.5m ~sؒv `1 l,h˕PybѶ1hbWLAhhddepsmhexpmm phoenix_htmlm2.9.2lhmhexpmmplugmplugm~> 1.0dfalsejFbWLAhhd timestampmhexpmmphoenixm1.1.6hhba aha a9a07bWLAhhdretiredmhexpmmpostgrexm0.15.5dnilabWLAhhdinner_checksummhexpmm phoenix_htmlm2.13.3m )/%_LToS`·к38g[bWLAhhdinner_checksummhexpmmphoenixm1.0.3m wafnQ+èzh $\XbWLAhhdinner_checksummhexpmmplugm0.5.3m ͢Q:ID+Y1g%8RM[bWLAhhdinner_checksummhexpmmdecimalm0.2.1m U%qs]A27MXbWLAhhdouter_checksummhexpmmplugm1.2.2m ^Dl]R&~,23~rbWLAhhddepsmhexpmmphoenix_paramsm0.3.0lhmhexpmmphoenixmphoenixm>= 1.3.3dfalsejwbWLAhhddepsmhexpmm phoenix_htmlm1.2.1lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsejabWLAhhdinner_checksummhexpmm phoenix_htmlm2.11.2m h% 'W [ۓH]doL1f3bWLAhhdretiredmhexpmmplugm0.12.2dnilabWLAhhdouter_checksummhexpmmpostgrexm 1.0.0-rc.0m Tm؆!8"s9ĒW݂ZIhlabWLAhhdouter_checksummhexpmm db_connectionm0.1.7m 2{m2FвIjyl{kMMzXbWLAhhdouter_checksummhexpmmmimem0.0.1m $ ߽#C8Fd7S;:L5C' XbWLAhhdinner_checksummhexpmmplugm1.1.5m VEpAZrS!'Z˒7Bn'XbWLAhhd registry_etagmhexpmm db_connectionm""84fb07dffdadbc16b002d1285963d731"bWLAhhddepsmhexpmmplugm 1.2.0-rc.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsej[bWLAhhdinner_checksummhexpmmphoenixm0.9.0m cmHZ^j:x:_h[EMbWLAhhd timestampmhexpmmphoenix_paramsm0.4.0hhba aha a9a0YbWLAhhdinner_checksummhexpmmplugm0.11.2m Җ\7İԩ _e_O`*Z[bWLAhhdinner_checksummhexpmmdecimalm1.9.0m 12q$,QK =M`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.0.0m ϲ aq|Ǿoqd$6DbWLAhhd timestampmhexpmmplugm0.10.0hhba aha a9a0DC\bWLAhhdouter_checksummhexpmmphoenixm0.14.0m حTx&y/ݝ985bWLAhhdretiredmhexpmmphoenixm0.1.0dnil-bWLAhhddepsmhexpmmdecimalm2.0.0jDbWLAhhd timestampmhexpmmjasonm1.2.2hhba aha a9a0GbWLAhhd timestampmhexpmmphoenixm0.2.11hhba aha a9a0rbWLAhhddepsmhexpmmphoenix_paramsm0.2.2lhmhexpmmphoenixmphoenixm>= 1.3.3dfalsej`bWLAhhdinner_checksummhexpmmphoenixm 1.4.0-rc.0m k]MvF/x[bcjfj8{.ޤ[bWLAhhdouter_checksummhexpmmphoenixm1.2.4m ]ͤr GM(\rn\qV[XbWLAhhdinner_checksummhexpmmplugm1.0.6m dpBcOfXeyu6LCelIXbWLAhhdouter_checksummhexpmmplugm0.7.0m \ꬽVSOy#M96s-vyXg;bWLAhhdretiredmhexpmm db_connectionm0.1.8dnilLbWLAhhd timestampmhexpmm phoenix_htmlm2.12.0hhba aha a9a0JbWLAhhd timestampmhexpmm plug_cowboym2.0.1hhba aha a9a0_bWLAhhdouter_checksummhexpmm plug_cryptom1.1.1m &Mo A i_bWLAhhdinner_checksummhexpmm plug_cowboym2.2.1m 2'2*G<..4 UP^[bWLAhhdouter_checksummhexpmmphoenixm0.3.1m YHy7^6aM+VSN%'bWLAhhddepsmhexpmmphoenixm1.3.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsejMbWLAhhd timestampmhexpmmphoenix_paramsm0.4.1hhba aha a9a0hbWLAhhddepsmhexpmm phoenix_htmlm2.7.0lhmhexpmmplugmplugm~> 1.0dfalsejYbWLAhhdouter_checksummhexpmmplugm1.10.4m #?=.Vaeh`w{g1H-NwFbWLAhhd timestampmhexpmmdecimalm1.0.1hhba aha a9a0-bWLAhhddepsmhexpmmdecimalm1.1.1jbbWLAhhdinner_checksummhexpmmphoenix_paramsm1.0.3m vs8kW1`mM٭2/.+۪|bWLAhhddepsmhexpmm db_connectionm 2.0.0-rc.0lhmhexpmm connectionm connectionm~> 1.0.2dfalsej\bWLAhhdinner_checksummhexpmmphoenixm1.4.13m g'֛QqT`OJ?a46VKbWLAhhd timestampmhexpmm phoenix_htmlm1.4.0hhba aha a9a0bWLAhhddepsmhexpmm plug_cowboym2.3.0lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej:bWLAhhdretiredmhexpmm phoenix_htmlm2.0.1dnilXbWLAhhdouter_checksummhexpmmplugm0.4.2m Anۅm 4 u4\bWLAhhdinner_checksummhexpmmpostgrexm0.4.2m gt\Fl0={ 5bWLAhhdretiredmhexpmmphoenixm0.4.0dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.9.2m 7` Co񚮘dbw:[.`5bWLAhhdretiredmhexpmmphoenixm0.3.0dnilXbWLAhhdouter_checksummhexpmmplugm1.3.5m X̡(9D/q*tmRHbWLAhhd timestampmhexpmmpostgrexm0.12.2hhba aha a9a0DbWLAhhd timestampmhexpmmplugm0.14.0hhba aha a9a0KbWLAhhddepsmhexpmmphoenixm1.2.4lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm6~> 1.4 or ~> 1.3.3 or ~> 1.2.4 or ~> 1.1.8 or ~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejFbWLAhhd timestampmhexpmmphoenixm1.1.9hhba aha a9a0]bWLAhhdinner_checksummhexpmmpostgrexm0.14.1m c$}JZֹW-Aj&;͊.ICbWLAhhd timestampmhexpmmplugm1.1.2hhba aha a9a0]bWLAhhdinner_checksummhexpmmplugm 1.5.0-rc.1m r>%f-k,\a$B/9&]bWLAhhdouter_checksummhexpmmpostgrexm0.14.3m M-vM!56FgbWLAhhddepsmhexpmm db_connectionm0.1.2lhmhexpmmbackoffmbackoffm~> 1.0dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruej[bWLAhhdouter_checksummhexpmmphoenixm1.0.3m e^c hwK>r6)Bdڙ2bWLAhhdretiredmhexpmmplugm1.6.0dnilcbWLAhhddepsmhexpmmplugm0.9.0lhmhexpmmcowboymcowboym~> 1.0dtruej\bWLAhhdinner_checksummhexpmmphoenixm0.11.0m `3dLڜ,\O,pO@CbWLAhhd timestampmhexpmmplugm1.8.3hhba aha a9a0]bWLAhhdinner_checksummhexpmmpostgrexm0.15.4m ]i%y5"j5F#^bWLAhhddepsmhexpmmphoenixm0.2.8lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.1dfalsehmhexpmmplugmplugm0.4.4dfalsej*bWLAhhddepsmhexpmmplugm0.4.3j4bWLAhhddepsmhexpmmphoenix_pubsubm0.0.1jbWLAhhddepsmhexpmmpostgrexm0.14.3lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.0dfalsehmhexpmmdecimalmdecimalm~> 1.5dfalsehmhexpmmjasonmjasonm~> 1.0dtruejbWLAhhddepsmhexpmmphoenix_paramsm0.4.1lhmhexpmmdecimalmdecimalm>= 1.7.0dfalsehmhexpmmphoenixmphoenixm>= 1.3.3dfalsej0bWLAhhddepsmhexpmm connectionm1.0.1jXbWLAhhdinner_checksummhexpmmplugm1.2.4m e)Do=."'vu=HϾ:bWLAhhdretiredmhexpmmdecimalm 1.9.0-rc.0dnil-bWLAhhddepsmhexpmmdecimalm1.1.0j`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.6.2m J^X OLiP>0[(D9%>`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.6.2m i{1HT]hBrX5p- _2,\bWLAhhdinner_checksummhexpmmpostgrexm0.8.1m O羸7u;:N_QⰏYbWLAhhd registry_etagmhexpmmphoenix_pubsubm""9c40253b1ea746f7a666b077918a909f"[bWLAhhdinner_checksummhexpmmphoenixm1.5.0m YόsJ0W6eIaij ĮB2bWLAhhddepsmhexpmmdecimalm 2.0.0-rc.0j[bWLAhhdouter_checksummhexpmmphoenixm1.5.0m ƕr9K}bc%P;K Ծ609PbWLAhhd registry_etagmhexpmmjasonm""c7ccb0b0d3701498a0a717862ef103b1"sbWLAhhddepsmhexpmm phoenix_htmlm2.5.1lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejKbWLAhhd timestampmhexpmm phoenix_htmlm2.1.0hhba aha a9a0bWLAhhddepsmhexpmm db_connectionm 1.0.0-rc.0lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0.0-beta.2dtruejabWLAhhdinner_checksummhexpmm db_connectionm0.1.2m ~r ~i`%&Sy!Lm<5bWLAhhdretiredmhexpmmdecimalm1.3.1dnilzbWLAhhdretiredmhexpmm plug_cowboym2.2.0tdmessagemBroken telemetry supportdreasondRETIRED_INVALIDJbWLAhhd timestampmhexpmm plug_cryptom1.1.1hhba aha a9a0abWLAhhdouter_checksummhexpmm db_connectionm0.2.0m ?MQ%u* j*gbWLAhhddepsmhexpmmplugm1.6.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsejXbWLAhhdouter_checksummhexpmmplugm1.9.0m ** d4h.I?]MjƼ_#PabWLAhhdouter_checksummhexpmm phoenix_htmlm2.14.1m SmR7[2A z:, _wc$abWLAhhdinner_checksummhexpmm db_connectionm2.0.2m D Q ܠFE@5CH(ʤ3bWLAhhddepsmhexpmm db_connectionm 1.0.0-rc.3lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0.0-beta.3dtruej"bWLAhhddepsmhexpmmphoenixm1.4.4lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejFbWLAhhd timestampmhexpmmphoenixm1.2.0hhba aha a9a0]bWLAhhdinner_checksummhexpmmpostgrexm0.13.2m +ƥEj'L ]'HA^]u]NabWLAhhdinner_checksummhexpmm db_connectionm1.1.3m ;FwyYVXf·]M~WZa6bWLAhhdretiredmhexpmmphoenixm0.15.0dnilFbWLAhhd timestampmhexpmmphoenixm1.0.6hhba aha a9a0]bWLAhhdinner_checksummhexpmmpostgrexm0.14.0m Vc93=5"w&퉂q2YbWLAhhdinner_checksummhexpmmplugm0.12.1m X"!崫*x/ӡ~(#LbWLAhhd timestampmhexpmm db_connectionm0.1.8hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm0.5.0dnil[bWLAhhdouter_checksummhexpmmdecimalm1.8.0m RiNn`PsLfXO[}1xfcXbWLAhhdouter_checksummhexpmmplugm1.6.0m vΛ6ѝ\U^/À.HXbWLAhhdinner_checksummhexpmmplugm1.1.2m ~$ZVɭ\1L>m ٛHE `bWLAhhdinner_checksummhexpmm phoenix_htmlm2.6.1m }S= zn$Ÿf0I["7 R}\bWLAhhdouter_checksummhexpmmphoenixm1.4.16m l2S'7A<u%Wm\$bWLAhhddepsmhexpmmphoenixm0.2.9lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.1dfalsehmhexpmmplugmplugm0.5.0dfalsejAbWLAhhd timestampmhexpmm phoenix_htmlhhba aha a9a09bWLAhhdretiredmhexpmm plug_cowboym2.1.3dnildbWLAhhdouter_checksummhexpmm phoenix_htmlm 2.7.0-devm OhnV.m%VH;Dyd Z_bWLAhhdinner_checksummhexpmm plug_cowboym2.3.0m P\<Pj7WP2f#ݩ`bWLAhhdouter_checksummhexpmmphoenixm 1.2.0-rc.1m _ʨul! ifʂA,]bWLAhhdouter_checksummhexpmm telemetrym0.4.2m -j m{XRr.+#b {*abWLAhhdinner_checksummhexpmmpostgrexm 1.0.0-rc.0m OOnUа|k-=mS,}=KB 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejXbWLAhhdinner_checksummhexpmmplugm1.9.0m |N&"3Gs$Ë{F}Y$:ZJXbWLAhhdouter_checksummhexpmmplugm1.3.4m bˠ*^MujXR:bWLAhhddepsmhexpmmphoenixm0.13.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.5.1 or ~> 1.6dtruej*bWLAhhddepsmhexpmmplugm0.5.1jKbWLAhhd timestampmhexpmmdecimalm 2.0.0-rc.0hhba aha a9a0 1.0.2dfalsejLbWLAhhd timestampmhexpmm db_connectionm0.2.2hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm1.1.0hhba aha a9a03bWLAhhdretiredmhexpmmplugm1.10.4dnilbWLAhhddepsmhexpmm plug_cowboym2.1.3lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsej:bWLAhhdretiredmhexpmm phoenix_htmlm1.4.0dnilCbWLAhhd timestampmhexpmmplugm1.9.0hhba aha a9a0/bWLAhhddepsmhexpmm telemetrym0.4.1j[bWLAhhdouter_checksummhexpmmphoenixm0.1.0m uW X  Tb~ n?p*fbWLAhhdouter_checksummhexpmm db_connectionm 1.0.0-rc.4m b|M,7LHXpS%ҫШ!FbWLAhhd timestampmhexpmmdecimalm2.0.0hhba aha a9a0KbWLAhhd timestampmhexpmmphoenixm 1.4.0-rc.3hhba aha a9a0HbWLAhhd timestampmhexpmm telemetrym0.4.0hhba aha a9a0 1.0dtruej[bWLAhhdouter_checksummhexpmmdecimalm0.2.2m 䑳ƑfZz hӨuR?/ ,.7}.KbWLAhhd timestampmhexpmmphoenixm 1.3.0-rc.0hhba aha a9a09bWLAhhdretiredmhexpmm plug_cryptom1.0.0dnil:bWLAhhdretiredmhexpmmphoenixm 1.4.0-rc.2dnil2bWLAhhdretiredmhexpmmplugm1.0.0dnilbbWLAhhdouter_checksummhexpmmphoenix_paramsm0.1.0m njΚliC"B0 CEHʺ2bWLAhhdretiredmhexpmmplugm1.6.4dnil\bWLAhhdouter_checksummhexpmmphoenixm1.4.10m %jס@)p6=|pnd"t:bWLAhhdretiredmhexpmm phoenix_htmlm1.1.0dnil`bWLAhhdinner_checksummhexpmmphoenixm 1.3.0-rc.2m SJ%h܂o8Bs E"(ت`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.3.0m (&M"$& $bn 2q>/2bWLAhhdretiredmhexpmmmimem1.1.0dnil]bWLAhhdinner_checksummhexpmm telemetrym0.2.0m [@ʣ޳-|OUomk\7L#fw!a1wFbWLAhhd timestampmhexpmmphoenixm1.4.7hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm1.0.1hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm1.4.3dnil7bWLAhhdretiredmhexpmmpostgrexm0.13.3dnil'bWLAhhddepsmhexpmmphoenixm 1.4.0-rc.2lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejbWLAhhddepsmhexpmmphoenixm0.17.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej\bWLAhhdouter_checksummhexpmmphoenixm0.17.0m ,}ce1::lyw)1yDbWLAhhd timestampmhexpmmplugm0.11.2hhba aha a9a0fbWLAhhdouter_checksummhexpmm db_connectionm 1.0.0-rc.5m c˝([eͱbWXfXX?Λ@bWLAhhdretiredmhexpmm db_connectionm 1.0.0-rc.0dnil:bWLAhhdretiredmhexpmm phoenix_htmlm2.3.1dnilKbWLAhhd timestampmhexpmm phoenix_htmlm1.3.0hhba aha a9a0HbWLAhhd timestampmhexpmmpostgrexm0.15.3hhba aha a9a0`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.5.0m D7zp6 . .cKkXfbWLAhhdouter_checksummhexpmm db_connectionm 1.0.0-rc.0m NHtQ9T{;1Em;bWLAhhdretiredmhexpmm db_connectionm2.0.4dnilXbWLAhhdouter_checksummhexpmmplugm0.4.4m 1-W3SXd#_Y:bWLAhhddepsmhexpmm db_connectionm0.2.3lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruejbWLAhhddepsmhexpmmpostgrexm0.13.1lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.1dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsejLbWLAhhd timestampmhexpmm db_connectionm2.2.0hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm0.6.0m \&9&)!cigN{Ezx9@bWLAhhd timestampmhexpmm plug_cryptohhba aha a9a0CbWLAhhd timestampmhexpmmplugm1.3.4hhba aha a9a0FbWLAhhd timestampmhexpmmdecimalm1.8.1hhba aha a9a0abWLAhhdinner_checksummhexpmm db_connectionm0.1.7m !@֥{;wvhqB\ՎՃ*bWLAhhddepsmhexpmmplugm1.4.4lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejXbWLAhhdouter_checksummhexpmmplugm0.9.0m '&PrUv1}V$K8MzTJ abWLAhhdinner_checksummhexpmm db_connectionm0.1.6m f _`==o_Frp 49ӣp\bWLAhhdouter_checksummhexpmmpostgrexm0.5.3m inޤh/ U(w@M9 `bWLAhhdouter_checksummhexpmm phoenix_htmlm2.5.1m |] ^7d"> Q)`XbWLAhhdinner_checksummhexpmmplugm1.4.3m #mw{f*o6jIIJ\bWLAhhdouter_checksummhexpmmphoenixm0.13.0m 2W@ 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej/bWLAhhddepsmhexpmm telemetrym0.1.0j7bWLAhhdretiredmhexpmmpostgrexm0.12.0dnilKbWLAhhd timestampmhexpmmphoenixm 1.2.0-rc.0hhba aha a9a0:bWLAhhdretiredmhexpmm phoenix_htmlm1.2.0dnilbWLAhhddepsmhexpmmphoenix_paramsm1.0.0lhmhexpmmdecimalmdecimalm>= 1.7.0dfalsehmhexpmmphoenixmphoenixm>= 1.3.3dfalsejabWLAhhdinner_checksummhexpmm phoenix_htmlm2.13.4m =nFd$JI' P*}mء[O_bWLAhhdinner_checksummhexpmm plug_cowboym2.1.3m 8>k߂aa2D\ܶ3abWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.0m iFM|S“4'QA8 JMbWLAhhd timestampmhexpmmphoenix_pubsubm1.1.2hhba aha a9a0_bWLAhhdinner_checksummhexpmm plug_cryptom1.0.0m 4?$b')ԥ- }MJbWLAhhd timestampmhexpmm plug_cowboym2.2.1hhba aha a9a0bbWLAhhdouter_checksummhexpmmphoenix_paramsm0.2.0m l: CpsmՊ`Git>L5bWLAhhdretiredmhexpmmphoenixm0.2.9dnilVbWLAhhdversionsmhexpmmphoenixlcm0.1.0m0.2.0m0.2.1m0.2.2m0.2.3m0.2.4m0.2.5m0.2.6m0.2.7m0.2.8m0.2.9m0.2.10m0.2.11m0.3.0m0.3.1m0.4.0m0.4.1m0.5.0m0.6.0m0.6.1m0.6.2m0.7.0m0.7.1m0.7.2m0.8.0m0.9.0m0.10.0m0.11.0m0.12.0m0.13.0m0.13.1m0.14.0m0.15.0m0.16.0m0.16.1m0.17.0m0.17.1m1.0.0m1.0.1m1.0.2m1.0.3m1.0.4m1.0.5m1.0.6m1.1.0m1.1.1m1.1.2m1.1.3m1.1.4m1.1.5m1.1.6m1.1.7m1.1.8m1.1.9m 1.2.0-rc.0m 1.2.0-rc.1m1.2.0m1.2.1m1.2.2m1.2.3m1.2.4m1.2.5m 1.3.0-rc.0m 1.3.0-rc.1m 1.3.0-rc.2m 1.3.0-rc.3m1.3.0m1.3.1m1.3.2m1.3.3m1.3.4m 1.4.0-rc.0m 1.4.0-rc.1m 1.4.0-rc.2m 1.4.0-rc.3m1.4.0m1.4.1m1.4.2m1.4.3m1.4.4m1.4.5m1.4.6m1.4.7m1.4.8m1.4.9m1.4.10m1.4.11m1.4.12m1.4.13m1.4.14m1.4.15m1.4.16m1.4.17m 1.5.0-rc.0m1.5.0m1.5.1m1.5.2m1.5.3m1.5.4jbWLAhhddepsmhexpmmpostgrexm0.13.4lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.1dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.7.0m . D4 .C jYg|Yh5T8ՒB GbWLAhhd timestampmhexpmmphoenixm1.4.12hhba aha a9a0bWLAhhddepsmhexpmmphoenixm1.1.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej 1.0dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruejgbWLAhhdinner_checksummhexpmmphoenix_pubsubm 1.0.0-rc.0m \S+@L?1+ xHXbWLAhhdinner_checksummhexpmmplugm0.5.1m X)],{/xL5_RxP)7bWLAhhdretiredmhexpmmpostgrexm0.11.2dnilbWLAhhddepsmhexpmmphoenixm1.5.4lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejFbWLAhhd timestampmhexpmmphoenixm1.5.2hhba aha a9a0[bWLAhhdinner_checksummhexpmmphoenixm1.2.4m ArG^!j^AuH 9 .c[bWLAhhddepsmhexpmmplugm1.6.2lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsejabWLAhhdinner_checksummhexpmm db_connectionm0.2.3m q 0.2.0dfalsejIbWLAhhd timestampmhexpmmjasonm 1.0.0-rc.3hhba aha a9a0abWLAhhdouter_checksummhexpmm db_connectionm2.0.6m h~YY'4 *Em-0f;a[bWLAhhdinner_checksummhexpmmphoenixm0.2.1m e/4QDU(R=7qPDdJ zkXbWLAhhdinner_checksummhexpmmmimem1.4.0m PfIDp(aF}/sQ̨/H5і|G5bWLAhhdretiredmhexpmmphoenixm0.9.0dnil7bWLAhhdretiredmhexpmm telemetrym0.4.1dnilbWLAhhddepsmhexpmm db_connectionm0.2.2lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruejbbWLAhhdinner_checksummhexpmmphoenix_paramsm1.1.0m L|a0ys~+a#oEo6W,-@5bWLAhhdretiredmhexpmmphoenixm1.0.4dnilFbWLAhhd timestampmhexpmmdecimalm0.2.0hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm1.0.2m VBSkeѠOU~9V#wk`RgzbWLAhhdretiredmhexpmm plug_cowboym2.2.1tdmessagemBroken telemetry supportdreasondRETIRED_INVALID2bWLAhhdretiredmhexpmmplugm1.6.3dnil 1.0.1 or ~> 1.1 or ~> 2.1dtruehmhexpmmmimemmimem~> 1.0dfalsejCbWLAhhd timestampmhexpmmplugm0.9.0hhba aha a9a0\bWLAhhdouter_checksummhexpmmpostgrexm0.8.3m @LMP'`Rۄ+O:Oy`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.0.1m /+P3)׾Jabʶ$§O5o\bWLAhhdinner_checksummhexpmmphoenixm0.17.1m xG.rgk.W%Y49+kY-bWLAhhddepsmhexpmmdecimalm0.2.5j:bWLAhhdretiredmhexpmmphoenixm 1.4.0-rc.3dnilbWLAhhddepsmhexpmmphoenixm0.2.6lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.1dfalsehmhexpmmplugmplugm0.4.4dfalsejCbWLAhhd timestampmhexpmmplugm1.4.1hhba aha a9a0XbWLAhhdinner_checksummhexpmmplugm1.2.5m |؋f4Bf w{їabWLAhhdouter_checksummhexpmm db_connectionm2.0.1m שZwysJAܿ)2I0Ű\1bWLAhhddepsmhexpmmplugm1.4.1lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej]bWLAhhdouter_checksummhexpmmplugm 1.2.0-rc.0m ~Ie -JizŅkwiC iXbWLAhhdinner_checksummhexpmmplugm0.7.0m ;\W/ppe5ȖL{dhbbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.1.1m ؐmQayܪ2DV'ŇVxul5bWLAhhdretiredmhexpmmphoenixm1.1.5dnil 1.0dfalsehmhexpmm db_connectionm db_connectionm ~> 1.0-rc.4dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsej8bWLAhhdretiredmhexpmm connectionm1.0.1dnil[bWLAhhdinner_checksummhexpmmphoenixm0.2.7m A_y~rtw(P3T[i(VlbWLAhhddepsmhexpmmpostgrexm0.4.2lhmhexpmmdecimalmdecimalm~> 0.1.2dfalsej]bWLAhhdouter_checksummhexpmm telemetrym0.2.0m Nqy]YL?C i .x@#2bWLAhhddepsmhexpmmphoenixm1.1.8lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej1bWLAhhddepsmhexpmm plug_cryptom1.1.1j3bWLAhhdretiredmhexpmmplugm0.12.1dnilJbWLAhhd timestampmhexpmm plug_cowboym2.0.0hhba aha a9a0*bWLAhhddepsmhexpmmplugm0.4.2j[bWLAhhdouter_checksummhexpmmphoenixm1.5.1m '+8(y̮og鷐=hx^=#1RbbWLAhhdinner_checksummhexpmmphoenix_pubsubm0.0.1m |ļ[kY`dF>NSKt7bWLAhhdretiredmhexpmmpostgrexm0.14.2dnil]bWLAhhdouter_checksummhexpmmpostgrexm0.13.3m s)S*q',=u9 ODbWLAhhd timestampmhexpmmplugm1.10.3hhba aha a9a0\bWLAhhdinner_checksummhexpmmpostgrexm0.8.3m rQZi񏃡Sb>L%JEmʪ(h2HbWLAhhd timestampmhexpmmpostgrexm0.12.1hhba aha a9a0abWLAhhdinner_checksummhexpmm db_connectionm2.2.1m rT@g*bJƓfbWLAhhddepsmhexpmmplugm1.10.0lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruej^bWLAhhdouter_checksummhexpmmjasonm 1.0.0-rc.2m wv3ԉ ĘDo$2bWLAhhdretiredmhexpmmplugm1.2.3dnilabWLAhhdouter_checksummhexpmm db_connectionm2.0.5m x PCw tއ JPNϟ zFYfOsbWLAhhddepsmhexpmm phoenix_htmlm2.1.1lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejXbWLAhhdinner_checksummhexpmmplugm0.8.2m 9[-!2bA&~YezA`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.4.0m ;ݙ\_^$HENf ^wQ52bWLAhhdretiredmhexpmmplugm0.4.4dnil;bWLAhhdretiredmhexpmm db_connectionm0.2.0dnil6bWLAhhdretiredmhexpmmphoenixm0.10.0dnil\bWLAhhdinner_checksummhexpmmphoenixm1.4.10m aJTUb)M"7-(#4ez$(UbbWLAhhdinner_checksummhexpmmphoenix_pubsubm0.1.0m zڏAI+Y@W<5y5^bWLAhhdouter_checksummhexpmmjasonm 1.0.0-rc.1m Iл;_,n4%G):bWLAhhdretiredmhexpmmphoenixm 1.3.0-rc.2dnilQbWLAhhd timestampmhexpmm db_connectionm 1.0.0-rc.2hhba aha a9a0FbWLAhhd timestampmhexpmmdecimalm1.0.0hhba aha a9a0FbWLAhhd timestampmhexpmmdecimalm1.3.0hhba aha a9a0MbWLAhhd timestampmhexpmmphoenix_paramsm0.2.2hhba aha a9a0[bWLAhhdinner_checksummhexpmmphoenixm1.4.3m Jd7,4rK֑Rv7]g}bWLAhhddepsmhexpmmphoenixm0.16.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 0.14 or ~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej5bWLAhhdretiredmhexpmmphoenixm1.3.3dnilGbWLAhhd timestampmhexpmmpostgrexm0.5.1hhba aha a9a0[bWLAhhdinner_checksummhexpmmphoenixm0.6.2m {*NP<`]Ksƫj4[bWLAhhdinner_checksummhexpmmdecimalm0.2.0m [.ٙ)b9*O^GLzb}FVbWLAhhd registry_etagmhexpmm plug_cowboym""d9ec1d3801c046c701fa55c601b67a33"@bWLAhhdretiredmhexpmm db_connectionm 1.0.0-rc.4dnilYbWLAhhdinner_checksummhexpmmjasonm1.2.1m (%/F>Kˍ spD5bWLAhhdretiredmhexpmmphoenixm1.5.4dnilXbWLAhhdouter_checksummhexpmmplugm1.2.4m @<*< 0!Ǝ +D(;P}_bWLAhhdinner_checksummhexpmm plug_cryptom1.1.1m K`*BЄq'I5 FfbWLAhhdinner_checksummhexpmm db_connectionm 2.0.0-rc.0m $Fo'~PxMeR:ҿ}/ibWLAhhddepsmhexpmm phoenix_htmlm2.11.0lhmhexpmmplugmplugm~> 1.5dfalsejFbWLAhhd timestampmhexpmmphoenixm1.4.6hhba aha a9a0_bWLAhhdouter_checksummhexpmm plug_cowboym2.1.2m }r%ΆZ#~mopAt %k>c"p[bWLAhhdinner_checksummhexpmmdecimalm1.5.0m C:6C=P)e<7of[CיchHehYbWLAhhdouter_checksummhexpmmplugm1.10.3m z*3jDKʻ8l s9\bWLAhhdinner_checksummhexpmmphoenixm1.4.17m |ު}`݌"ChI@;8[bWLAhhdinner_checksummhexpmmphoenixm0.8.0m ҡ:l $,I 2aEӰ|K[bWLAhhdouter_checksummhexpmmdecimalm0.1.1m ZA57/P,#n^}[WBx;bWLAhhdretiredmhexpmm db_connectionm0.1.7dnil7bWLAhhdretiredmhexpmmplugm 1.5.0-rc.2dnilXbWLAhhdouter_checksummhexpmmplugm1.4.2m P@`%ܧDd[͑Z1"? [GbWLAhhd timestampmhexpmmphoenixm0.11.0hhba aha a9a0wbWLAhhddepsmhexpmm phoenix_htmlm1.4.0lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsej5bWLAhhdretiredmhexpmmdecimalm1.1.0dnilbWLAhhddepsmhexpmmpostgrexm0.13.0lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.1dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsejbWLAhhddepsmhexpmmpostgrexm0.11.0lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 0.2dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsej-bWLAhhddepsmhexpmmdecimalm1.3.1j\bWLAhhdinner_checksummhexpmmphoenixm0.17.0m fFznM[|q]TM8^_r,wXbWLAhhdinner_checksummhexpmmplugm1.5.1m [϶5^LG0?l)ҧoASe]bWLAhhdouter_checksummhexpmmpostgrexm0.15.2m u.ȃe. b 3#yi>q2bWLAhhdretiredmhexpmmplugm1.2.4dnilDbWLAhhd timestampmhexpmmjasonm1.1.0hhba aha a9a0bWLAhhddepsmhexpmmphoenixm0.12.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm ~> 0.12.1dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.5.1dtruejbWLAhhddepsmhexpmmphoenixm1.0.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejLbWLAhhd timestampmhexpmm db_connectionm2.0.2hhba aha a9a02bWLAhhdretiredmhexpmmplugm1.3.1dniljbWLAhhddepsmhexpmmphoenixm1.4.14lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejXbWLAhhdinner_checksummhexpmmplugm1.1.1m UWlٹUh e<>h|,{\{]bWLAhhdinner_checksummhexpmmpostgrexm0.15.0m SI>B/y\:B{Lc8bWLAhhdretiredmhexpmm connectionm1.0.0dnilFbWLAhhd timestampmhexpmmphoenixm1.2.3hhba aha a9a0XbWLAhhdinner_checksummhexpmmplugm1.6.3m C3{*/c5i~LSH,^XbWLAhhdouter_checksummhexpmmplugm0.8.4m "5 3T[ۼ~`2p2(5_bWLAhhdversionsmhexpmmpluglYm0.4.1m0.4.2m0.4.3m0.4.4m0.5.0m0.5.1m0.5.2m0.5.3m0.6.0m0.7.0m0.8.0m0.8.1m0.8.2m0.8.3m0.8.4m0.9.0m0.10.0m0.11.0m0.11.1m0.11.2m0.11.3m0.12.0m0.12.1m0.12.2m0.13.0m0.13.1m0.14.0m1.0.0m1.0.1m1.0.2m1.0.3m1.0.4m1.0.5m1.0.6m1.1.0m1.1.1m1.1.2m1.1.3m1.1.4m1.1.5m1.1.6m1.1.7m1.1.8m1.1.9m 1.2.0-rc.0m1.2.0m1.2.1m1.2.2m1.2.3m1.2.4m1.2.5m1.2.6m1.3.0m1.3.1m1.3.2m1.3.3m1.3.4m1.3.5m1.3.6m 1.4.0-rc.0m1.4.0m1.4.1m1.4.2m1.4.3m1.4.4m1.4.5m 1.5.0-rc.0m 1.5.0-rc.1m 1.5.0-rc.2m1.5.0m1.5.1m1.6.0m1.6.1m1.6.2m1.6.3m1.6.4m1.7.0m1.7.1m1.7.2m1.8.0m1.8.1m1.8.2m1.8.3m1.9.0m1.10.0m1.10.1m1.10.2m1.10.3m1.10.4jFbWLAhhd timestampmhexpmmphoenixm1.3.4hhba aha a9a0XbWLAhhdinner_checksummhexpmmplugm1.8.0m &٬'(&+x )oCwabWLAhhdinner_checksummhexpmm db_connectionm0.1.1m T@EWB*tQ]!-Ι)`bWLAhhdouter_checksummhexpmmphoenixm 1.2.0-rc.0m ߒҏ&=b Oֵ> #iZn`ZSakP[bWLAhhdouter_checksummhexpmmphoenixm0.4.1m 'Y Kj]MunLT܋YgYbWLAhhdinner_checksummhexpmmplugm0.11.3m v;X5!6חtwI`+?WJcbWLAhhddepsmhexpmmplugm1.0.5lhmhexpmmcowboymcowboym~> 1.0dtruejabWLAhhdinner_checksummhexpmm phoenix_htmlm2.12.0m KfUd=6UFֵSL+Fv">bWLAhhdretiredmhexpmm phoenix_htmlm 2.4.0-devdnildbWLAhhddepsmhexpmmplugm0.14.0lhmhexpmmcowboymcowboym~> 1.0dtruej]bWLAhhdinner_checksummhexpmm telemetrym0.3.0m <Gqc <"f" :*:jguJs;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.4dnil8bWLAhhdretiredmhexpmm connectionm1.0.2dnilbWLAhhddepsmhexpmmpostgrexm0.11.1lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 0.2dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsej'bWLAhhddepsmhexpmmpostgrexm 0.14.0-rc.1lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm ~> 2.0-rc.0dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsehmhexpmmjasonmjasonm~> 1.0dtruejYbWLAhhdouter_checksummhexpmmjasonm1.1.1m cEϬ2^4gry:42•%#LRbWLAhhd timestampmhexpmmphoenix_pubsubm 1.0.0-rc.0hhba aha a9a0HbWLAhhd timestampmhexpmm telemetrym0.2.0hhba aha a9a0CbWLAhhd timestampmhexpmmplugm1.2.0hhba aha a9a0abWLAhhdinner_checksummhexpmm db_connectionm2.0.0m ⌇5)U]dV=4 M^6bWLAhhdretiredmhexpmmpostgrexm0.5.4dnil[bWLAhhdinner_checksummhexpmmdecimalm1.2.0m F)`q(.W{Gkkh'}M dcRiK [bWLAhhdinner_checksummhexpmmphoenixm0.2.9m (N76eVҫbnK;L}dbbWLAhhdouter_checksummhexpmmphoenix_paramsm0.4.2m '͓aoD&ZŶz`)}tkKbWLAhhddepsmhexpmmphoenixm0.11.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm ~> 0.11.3dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.4.2dtruejHbWLAhhd timestampmhexpmmplugm 1.5.0-rc.2hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm1.1.9m 1gxف 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruejDbWLAhhd timestampmhexpmmplugm0.13.0hhba aha a9a0YbWLAhhdinner_checksummhexpmmplugm1.10.3m ξv7u9jܠiN4n?Bƒ_bWLAhhdouter_checksummhexpmm plug_cowboym2.0.2m DSݢiu| Mq 1bWLAhhddepsmhexpmmplugm1.4.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej\bWLAhhdouter_checksummhexpmmphoenixm1.4.15m dv#f mW7JܻiI5bWLAhhdretiredmhexpmmphoenixm0.2.3dnilfbWLAhhdouter_checksummhexpmm db_connectionm 1.0.0-rc.3m )Xω+IOW10KT@%2B 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.1dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej2bWLAhhdretiredmhexpmmplugm1.4.1dnil]bWLAhhdinner_checksummhexpmmpostgrexm0.11.0m ۙt*Wml'E- 6`B,bWLAhhddepsmhexpmmphoenixm 1.3.0-rc.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.2 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsejMbWLAhhd timestampmhexpmmphoenix_paramsm0.2.1hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm0.7.1hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm1.0.0m s/L!p_1iRV䒥W[bWLAhhdouter_checksummhexpmmphoenixm1.4.8m 9e" MrJgjt--*bWLAhhddepsmhexpmmmimem1.2.0jcbWLAhhddepsmhexpmmplugm1.0.0lhmhexpmmcowboymcowboym~> 1.0dtruej]bWLAhhdouter_checksummhexpmmpostgrexm0.12.2m YwB(N)0*$}bbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.0.2m o6L]kӨ4lVˮft2bWLAhhdretiredmhexpmmplugm1.1.6dnil5bWLAhhdretiredmhexpmmphoenixm0.7.0dnilCbWLAhhd timestampmhexpmmplugm1.2.3hhba aha a9a0bWLAhhddepsmhexpmmplugm1.3.3lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejbWLAhhddepsmhexpmmpostgrexm0.11.2lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm ~> 1.0-rcdfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsej3bWLAhhdretiredmhexpmmjasonm1.0.1dnil6bWLAhhdretiredmhexpmmpostgrexm0.8.3dnil\bWLAhhdouter_checksummhexpmmpostgrexm0.9.0m MjOe7@U(;8Om!gy?@$`bWLAhhdouter_checksummhexpmmdecimalm 2.0.0-rc.0m %^,>8W$d. 0.13 or ~> 1.0dfalsejbbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.1.0m ^%/dcfa-PSYD2bWLAhhdretiredmhexpmmplugm1.7.2dnil[bWLAhhdouter_checksummhexpmmdecimalm1.9.0m 45h֒>u[] o}`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.6.0m =cEGw=v2ztUi7bWLAhhdretiredmhexpmmpostgrexm0.14.0dnil:bWLAhhdretiredmhexpmm phoenix_htmlm2.7.0dnilKbWLAhhd timestampmhexpmm phoenix_htmlm2.3.1hhba aha a9a02bWLAhhdretiredmhexpmmplugm1.4.2dnil[bWLAhhdouter_checksummhexpmmphoenixm1.1.2m dƼmd/(VYZ#D_bWLAhhdinner_checksummhexpmm plug_cryptom1.1.2m чW,mq6)%򵀡VB0';bWLAhhdretiredmhexpmm db_connectionm0.2.2dnil3bWLAhhdretiredmhexpmmjasonm1.2.0dnil_bWLAhhdouter_checksummhexpmm plug_cowboym2.1.0m lѽM?G}gaSՍ@CzF2[bWLAhhdouter_checksummhexpmmphoenixm1.2.2m vLJUԾ=er*b+Qb: ڨ`( ylbWLAhhddepsmhexpmm phoenix_htmlm 2.7.0-devlhmhexpmmplugmplugm~> 1.0dfalsejbWLAhhddepsmhexpmmpostgrexm0.14.2lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.0dfalsehmhexpmmdecimalmdecimalm~> 1.5dfalsehmhexpmmjasonmjasonm~> 1.0dtruejfbWLAhhdinner_checksummhexpmm db_connectionm 1.0.0-rc.5m zhf|/uƜ*F7 [bWLAhhdinner_checksummhexpmmdecimalm0.2.2m b^BJ;@>ҜLz:K sbWLAhhddepsmhexpmm phoenix_htmlm2.5.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej5bWLAhhdretiredmhexpmmphoenixm0.8.0dnil]bWLAhhdinner_checksummhexpmmplugm 1.4.0-rc.0m Solm$a63;3r~[ YbWLAhhdinner_checksummhexpmmjasonm1.2.0m 4-$!-?]HCv 8yY8H:bWLAhhdretiredmhexpmm phoenix_htmlm2.5.0dnil[bWLAhhdinner_checksummhexpmmphoenixm1.4.4m ],4C 6Wq9wrh2N[bWLAhhdouter_checksummhexpmmphoenixm1.3.1m e+a!= ETsyFML2hX2([bWLAhhdinner_checksummhexpmmphoenixm0.2.0m lE$ KMb™ua@Eh4 0.13 or ~> 1.0dfalsejDbWLAhhdversionsmhexpmmdecimallm0.1.1m0.1.2m0.2.0m0.2.1m0.2.2m0.2.3m0.2.4m0.2.5m1.0.0m1.0.1m1.1.0m1.1.1m1.1.2m1.2.0m1.3.0m1.3.1m1.4.0m1.4.1m1.5.0m1.6.0m1.7.0m1.8.0m1.8.1m 1.9.0-rc.0m1.9.0m 2.0.0-rc.0m2.0.0jVbWLAhhddepsmhexpmmphoenixm 1.2.0-rc.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsehmhexpmmphoenix_pubsubmphoenix_pubsubm ~> 1.0.0-rcdfalsehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejcbWLAhhddepsmhexpmmplugm1.1.4lhmhexpmmcowboymcowboym~> 1.0dtruej;bWLAhhdretiredmhexpmm db_connectionm1.1.0dnilcbWLAhhdouter_checksummhexpmm connectionm 1.0.0-rc.1m Z{ax:`Np!rjH0bWLAhhddepsmhexpmm connectionm1.0.3jCbWLAhhd timestampmhexpmmmimem1.4.0hhba aha a9a0CbWLAhhd timestampmhexpmmplugm1.1.0hhba aha a9a0-bWLAhhddepsmhexpmmdecimalm1.7.0j[bWLAhhdinner_checksummhexpmmphoenixm1.0.5m E)PQ!jflW1)dXbWLAhhdinner_checksummhexpmmplugm1.0.3m LQp\!Svx$XbWLAhhdinner_checksummhexpmmplugm0.5.0m r"cuM>͖ x7ɮ4|)uR#vt`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.8.0m wu`֫{%ɯ)dNH"Θ ]bWLAhhdinner_checksummhexpmmpostgrexm0.13.4m 1TQچjEm1Щ#nZA[bWLAhhdouter_checksummhexpmmphoenixm0.4.0m 碆B~@9YUOb*bXbWLAhhdinner_checksummhexpmmplugm1.0.5m $W .:ѵȫ2RU)wJbWLAhhddepsmhexpmm plug_cowboym2.0.0lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsejXbWLAhhdouter_checksummhexpmmplugm1.0.0m YC1S [(R-7Vc bWLAhhddepsmhexpmm plug_cowboym1.0.0lhmhexpmmcowboymcowboym~> 1.0dfalsehmhexpmmplugmplugm~> 1.7dfalsej[bWLAhhdinner_checksummhexpmmphoenixm0.3.1m wg!m m~!SPbJXig0a+2bWLAhhdretiredmhexpmmplugm1.7.0dnil]bWLAhhdinner_checksummhexpmmpostgrexm0.10.0m XimaѩtRqM"M2Տ-XbWLAhhdinner_checksummhexpmmplugm0.8.0m aC-N`|~<>&ҸEX.ędbWLAhhddepsmhexpmmplugm0.10.0lhmhexpmmcowboymcowboym~> 1.0dtruejbWLAhhddepsmhexpmmphoenix_paramsm1.1.1lhmhexpmmdecimalmdecimalm>= 1.7.0dfalsehmhexpmmphoenixmphoenixm>= 1.3.3dfalsejbWLAhhddepsmhexpmmphoenixm0.2.11lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.4dfalsehmhexpmmjazzmjazzm0.1.2dfalsehmhexpmmplugmplugm0.5.1dfalsej5bWLAhhdretiredmhexpmmdecimalm1.1.1dnil[bWLAhhdouter_checksummhexpmmdecimalm2.0.0m 4fnUި}7b2j# DwabWLAhhdouter_checksummhexpmm db_connectionm2.0.0m jE//<ьήVv HbWLAhhd timestampmhexpmm telemetrym0.3.0hhba aha a9a05bWLAhhdretiredmhexpmmphoenixm0.7.2dnil bWLAhhddepsmhexpmmphoenixm0.6.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmlinguistmlinguistm~> 0.1.4dfalsehmhexpmmplugmplugm~> 0.8.4dfalsehmhexpmmpoisonmpoisonm~> 1.2dfalsejCbWLAhhd timestampmhexpmmplugm1.8.2hhba aha a9a0\bWLAhhdinner_checksummhexpmmphoenixm0.2.10m !/I7תck[%NS ^bWLAhhdouter_checksummhexpmm connectionm1.0.1m B KK{41ヺs[bWLAhhdinner_checksummhexpmmphoenixm1.3.0m LJzo PgA]$>ʼnCbWLAhhd timestampmhexpmmplugm1.4.0hhba aha a9a0LbWLAhhd timestampmhexpmm db_connectionm2.0.0hhba aha a9a0`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.5.1m cSE\&m'BipgB_XbWLAhhdinner_checksummhexpmmplugm1.3.2m غ.,}i!YdU Uac-GbWLAhhd timestampmhexpmmpostgrexm0.5.3hhba aha a9a0;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.3dniljbWLAhhddepsmhexpmmpostgrexm0.8.1lhmhexpmmdecimalmdecimalm~> 1.0dfalsej 0.2.1dfalsejVbWLAhhd registry_etagmhexpmm plug_cryptom""2e69c8aae7f0030e224e283fdf6117dc"XbWLAhhdouter_checksummhexpmmplugm1.1.8m -nOWz?~iW6F1؀,J[bWLAhhdinner_checksummhexpmmdecimalm1.0.0m 4") h_S)3rm"K^5bWLAhhdretiredmhexpmmphoenixm1.5.3dnilDbWLAhhd timestampmhexpmmplugm0.11.0hhba aha a9a0ibWLAhhddepsmhexpmm phoenix_htmlm2.13.4lhmhexpmmplugmplugm~> 1.5dfalsejGbWLAhhd timestampmhexpmmpostgrexm0.5.5hhba aha a9a0`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.0.1m ߲8MςÝzffSpo&jbWLAhhddepsmhexpmmpostgrexm0.9.0lhmhexpmmdecimalmdecimalm~> 1.0dfalsej\bWLAhhdinner_checksummhexpmmphoenixm0.14.0m q;{;  )=oR b/HbWLAhhd timestampmhexpmmpostgrexm0.11.1hhba aha a9a0jbWLAhhddepsmhexpmmphoenixm1.4.13lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.1dfalsehmhexpmmdecimalmdecimalm~> 1.5dfalsehmhexpmmjasonmjasonm~> 1.0dtruejHbWLAhhd timestampmhexpmmpostgrexm0.15.5hhba aha a9a0KbWLAhhd timestampmhexpmm phoenix_htmlm2.6.0hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm0.9.0hhba aha a9a0CbWLAhhd timestampmhexpmmplugm0.8.0hhba aha a9a06bWLAhhdretiredmhexpmmpostgrexm0.7.0dnilFbWLAhhd timestampmhexpmmdecimalm0.2.4hhba aha a9a0XbWLAhhdouter_checksummhexpmmmimem1.0.1m ^m r,)G FbWLAhhd timestampmhexpmmphoenixm1.4.4hhba aha a9a02bWLAhhdretiredmhexpmmplugm0.5.0dniljbWLAhhddepsmhexpmmphoenixm1.4.11lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej!5Ù~ 0bWLAhhddepsmhexpmm connectionm1.0.4j`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.3.1m ?in`"yԡ_n}fo0-BLbWLAhhd timestampmhexpmmpostgrexm 1.0.0-rc.1hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm1.1.4m We#ΒB;C?DpQ YzebWLAhhddepsmhexpmmplugm0.8.1lhmhexpmmcowboymcowboym~> 1.0.0dtruej"bWLAhhddepsmhexpmmphoenixm1.4.0lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejObWLAhhd timestampmhexpmm phoenix_htmlm 2.4.0-devhhba aha a9a0`bWLAhhdinner_checksummhexpmmphoenixm 1.3.0-rc.0m Ni!{19n}o⾊шùG2bWLAhhdretiredmhexpmmplugm1.3.6dnilbbWLAhhdouter_checksummhexpmmpostgrexm 0.14.0-rc.1m =8HMܦBϕwO5r"iYbWLAhhdouter_checksummhexpmmjasonm1.2.0m gGWyL:>N;|cNNJYu.LbWLAhhd timestampmhexpmm phoenix_htmlm2.11.0hhba aha a9a0bWLAhhddepsmhexpmmphoenixm1.5.3lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej]bWLAhhdinner_checksummhexpmmpostgrexm0.12.2m ׄHx3\8)c%&XcbWLAhhddepsmhexpmmplugm1.1.0lhmhexpmmcowboymcowboym~> 1.0dtruej7bWLAhhdretiredmhexpmmpostgrexm0.11.0dnilMbWLAhhd timestampmhexpmmphoenix_pubsubm1.0.2hhba aha a9a0XbWLAhhdinner_checksummhexpmmplugm1.2.1m ܇ Te N+o>&t'ibWLAhhddepsmhexpmm phoenix_htmlm2.11.1lhmhexpmmplugmplugm~> 1.5dfalsej5bWLAhhddepsmhexpmm connectionm 1.0.0-rc.1j2bWLAhhdretiredmhexpmmplugm1.0.2dnilabWLAhhdouter_checksummhexpmm phoenix_htmlm2.13.1m BϩNޖ3@ٜ4]Om鲳BdǡdGbWLAhhd timestampmhexpmmphoenixm0.12.0hhba aha a9a0]bWLAhhdinner_checksummhexpmmpostgrexm0.11.2m U5<\mn%VӞ'FmߴB<4ibWLAhhddepsmhexpmm phoenix_htmlm2.10.0lhmhexpmmplugmplugm~> 1.0dfalsejFbWLAhhd timestampmhexpmmphoenixm1.4.9hhba aha a9a0\bWLAhhdinner_checksummhexpmmpostgrexm0.5.5m d : .υ!ȗ6!̫bWLAhhddepsmhexpmm db_connectionm0.1.1lhmhexpmmbackoffmbackoffm~> 1.0dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruejXbWLAhhdinner_checksummhexpmmplugm1.6.0m 8Lb->$rE[QTKwSo\bWLAhhdinner_checksummhexpmmpostgrexm0.5.3m i'Jz5 APp@l/s+OlbWLAhhddepsmhexpmmpostgrexm0.6.0lhmhexpmmdecimalmdecimalm~> 0.2.3dfalsej[bWLAhhdouter_checksummhexpmmdecimalm1.0.0m T ! oC d0'${ՓBt[bWLAhhdouter_checksummhexpmmphoenixm1.0.6m 7.zUH}c[u뷃ܞ^6mü SbWLAhhd registry_etagmhexpmmpostgrexm""35d9bc39d21b39e549bb40de95a08cda"bWLAhhddepsmhexpmmphoenix_paramsm0.4.0lhmhexpmmdecimalmdecimalm>= 1.7.0dfalsehmhexpmmphoenixmphoenixm>= 1.3.3dfalsej'bWLAhhddepsmhexpmmphoenixm 1.4.0-rc.3lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejbWLAhhddepsmhexpmmphoenixm0.2.3lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.0dfalsehmhexpmmplugmplugm0.4.3dfalsej 1.8dfalsehmhexpmmphoenixmphoenixm~> 1.3dfalsej[bWLAhhdinner_checksummhexpmmphoenixm1.2.0m ޹%OLSLߘ )|b]Wb|;f]bWLAhhdinner_checksummhexpmm telemetrym0.4.2m (ɒE^s"M;kb_#:sPXps/EbWLAhhddepsmhexpmmphoenixm1.2.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.1dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejFbWLAhhd timestampmhexpmmphoenixm0.7.2hhba aha a9a0XbWLAhhdinner_checksummhexpmmmimem1.3.1m 01u \w=R=sxM<HbWLAhhd timestampmhexpmmpostgrexm0.14.1hhba aha a9a0jbWLAhhddepsmhexpmmpostgrexm0.8.2lhmhexpmmdecimalmdecimalm~> 1.0dfalsej5bWLAhhdretiredmhexpmmdecimalm1.7.0dnil_bWLAhhdouter_checksummhexpmm plug_cowboym2.2.1m ;C$F (nz b䎷#YTh ]޶XbWLAhhdouter_checksummhexpmmplugm1.6.2m q<W&a +UlALu{XbWLAhhdouter_checksummhexpmmplugm0.8.1m Pߙ%5s}_ݡD/TD][bWLAhhdinner_checksummhexpmmdecimalm0.1.1m }VRqtgNpjY$[bWLAhhdouter_checksummhexpmmphoenixm0.7.1m 7R8CIY<+h Aa&G3bWLAhhdretiredmhexpmmjasonm1.1.1dnilFbWLAhhd timestampmhexpmmphoenixm0.6.0hhba aha a9a0dbWLAhhddepsmhexpmmplugm0.13.1lhmhexpmmcowboymcowboym~> 1.0dtruejbWLAhhdversionsmhexpmmphoenix_paramslm0.1.0m0.1.1m0.1.2m0.2.0m0.2.1m0.2.2m0.3.0m0.4.0m0.4.1m0.4.2m1.0.0m1.0.1m1.0.3m1.1.0m1.1.1m1.1.2m1.1.3j-bWLAhhddepsmhexpmmdecimalm0.2.1j77Myd kFbWLAhhd timestampmhexpmmdecimalm0.1.2hhba aha a9a0:bWLAhhdretiredmhexpmm phoenix_htmlm2.2.0dnil2bWLAhhdretiredmhexpmmmimem1.2.0dnil]bWLAhhdouter_checksummhexpmmpostgrexm0.15.0m ,O|]_ "I6XsL5+bWLAhhddepsmhexpmm plug_cowboym2.0.2lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsejdbWLAhhdouter_checksummhexpmm phoenix_htmlm 2.4.0-devm 0a/@/։ꠦ=;Aj:bWLAhhdretiredmhexpmm phoenix_htmlm1.0.1dnilbWLAhhddepsmhexpmmplugm1.4.5lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejBbWLAhhd timestampmhexpmm db_connectionhhba aha a9a0abWLAhhdinner_checksummhexpmm db_connectionm0.1.0m ҇4gMbzYw|} bGbWLAhhd timestampmhexpmmpostgrexm0.7.0hhba aha a9a0:bWLAhhdretiredmhexpmmphoenixm 1.5.0-rc.0dnilpbWLAhhdversionsmhexpmm connectionlm 1.0.0-rc.1m1.0.0m1.0.1m1.0.2m1.0.3m1.0.4j 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm,~> 1.3.3 or ~> 1.2.4 or ~> 1.1.8 or ~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejJbWLAhhd timestampmhexpmm plug_cowboym2.0.2hhba aha a9a0YbWLAhhdinner_checksummhexpmmjasonm1.0.1m d6K<p3T]s.g]bWLAhhdinner_checksummhexpmmpostgrexm0.11.1m XѪVBsbETϸ7rkjJXbWLAhhdinner_checksummhexpmmplugm0.6.0m b#C(lm6 t{-abWLAhhdouter_checksummhexpmm db_connectionm1.1.1m oxZ#L2* ?~1rF5DQbWLAhhd timestampmhexpmm db_connectionm 1.0.0-rc.0hhba aha a9a0CbWLAhhd timestampmhexpmmplugm0.4.1hhba aha a9a0,bWLAhhddepsmhexpmmphoenixm 1.3.0-rc.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.2 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsejLbWLAhhd timestampmhexpmm phoenix_htmlm2.11.2hhba aha a9a06bWLAhhdretiredmhexpmmphoenixm1.4.10dnilXbWLAhhdouter_checksummhexpmmplugm1.4.0m p>PPSm mɆEkbWLAhhddepsmhexpmmjasonm 1.0.0-rc.1lhmhexpmmdecimalmdecimalm~> 1.0dtruej[bWLAhhdinner_checksummhexpmmphoenixm1.4.0m Vs_>;1IԴ6fb{abWLAhhdinner_checksummhexpmm db_connectionm1.0.0m c>R TjfM4# KYl!Y,֤ abWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.5m O82cηF|IUTu yQ`^E3bWLAhhdretiredmhexpmmplugm0.12.0dnilKbWLAhhd timestampmhexpmmphoenixm 1.3.0-rc.2hhba aha a9a0CbWLAhhd timestampmhexpmmplugm0.8.1hhba aha a9a0CbWLAhhd timestampmhexpmmplugm1.8.0hhba aha a9a0CbWLAhhd timestampmhexpmmplugm1.0.0hhba aha a9a02bWLAhhdretiredmhexpmmplugm1.1.4dnilfbWLAhhddepsmhexpmmjasonm1.1.1lhmhexpmmdecimalmdecimalm~> 1.0dtruej^bWLAhhdinner_checksummhexpmm connectionm1.0.4m "w>f%Jaj}YvfbWLAhhddepsmhexpmmjasonm1.2.1lhmhexpmmdecimalmdecimalm~> 1.0dtruej=bWLAhhdretiredmhexpmm connectionm 1.0.0-rc.1dnilabWLAhhdouter_checksummhexpmm db_connectionm2.1.0m MނBƗg`z" [XbWLAhhdinner_checksummhexpmmplugm1.8.3m ym.aNL Be ZhDxsbWLAhhddepsmhexpmm phoenix_htmlm2.1.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejXbWLAhhdouter_checksummhexpmmplugm1.1.1m  E!/&uW><fJ]pqbWLAhhddepsmhexpmmphoenixm0.3.0lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.4dfalsehmhexpmmjazzmjazzm0.1.2dfalsehmhexpmmplugmplugm0.5.1dfalsejrbWLAhhddepsmhexpmmphoenix_paramsm0.2.1lhmhexpmmphoenixmphoenixm>= 1.3.3dfalsejXbWLAhhdouter_checksummhexpmmplugm1.1.0m iijK'%.? -ޙ/قKabWLAhhdouter_checksummhexpmm db_connectionm0.2.5m C[oչ6rd߸i^$Zp/abWLAhhdouter_checksummhexpmm db_connectionm2.2.1m +-?@ND;}efCTk+RQy!¦abWLAhhdouter_checksummhexpmm db_connectionm0.2.1m #4@xkLtƳ6@F-gbWLAhhdouter_checksummhexpmmphoenix_pubsubm 1.0.0-rc.0m v\f_vM^Z"q9ۏ ;W_[bWLAhhdouter_checksummhexpmmphoenixm1.1.1m Iu꿣 CMMbK[bWLAhhdinner_checksummhexpmmphoenixm1.0.1m .ٝrl#H[;'r9p؂3bWLAhhddepsmhexpmmphoenixm0.2.4lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmplugmplugm0.4.3dfalsejibWLAhhddepsmhexpmm phoenix_htmlm2.14.2lhmhexpmmplugmplugm~> 1.5dfalsejKbWLAhhd timestampmhexpmmphoenixm 1.2.0-rc.1hhba aha a9a0[bWLAhhdouter_checksummhexpmmphoenixm0.7.0m $y|6; w'Px`j1TELbWLAhhd timestampmhexpmm db_connectionm0.1.5hhba aha a9a0@bWLAhhd timestampmhexpmm plug_cowboyhhba aha a9a0IbWLAhhd timestampmhexpmm connectionm1.0.4hhba aha a9a04bWLAhhddepsmhexpmmphoenix_pubsubm0.1.0jabWLAhhdouter_checksummhexpmm db_connectionm0.2.3m haԂBfAUEW,+JI oabWLAhhdinner_checksummhexpmm db_connectionm0.2.4m Q\?{ffCx6mC(TXbWLAhhdouter_checksummhexpmmplugm1.8.0m L [8Ɵ*x}kTot$XbWLAhhdinner_checksummhexpmmplugm1.1.8m ۋmyRDjp2CXbWLAhhdinner_checksummhexpmmplugm0.8.3m ˯eF[q|C8S>!VTObWLAhhd registry_etagmhexpmmplugm""a35d954d250109e64532cce56060f54b"~bWLAhhdretiredmhexpmmpostgrexm 1.0.0-rc.0tdmessagemSuperseded by v0.13.0-rc.0dreasondRETIRED_INVALIDYbWLAhhdouter_checksummhexpmmplugm1.10.1m R%1EII*,]bWLAhhdinner_checksummhexpmmpostgrexm0.13.5m =)6>CzKm$+bbWLAhhdouter_checksummhexpmmphoenix_paramsm0.4.0m W؟}tE+qǹnԾXp&/'p`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.2.1m N ĪI,"sin ]}FbWLAhhd timestampmhexpmmphoenixm1.5.3hhba aha a9a0bWLAhhddepsmhexpmm db_connectionm0.1.8lhmhexpmmbackoffmbackoffm1.1.1dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruejXbWLAhhdversionsmhexpmm plug_cryptolm1.0.0m1.1.0m1.1.1m1.1.2jabWLAhhdouter_checksummhexpmm db_connectionm0.1.5m uXһ >>ʃjGmoۢMc8bWLAhhdretiredmhexpmmjasonm 1.0.0-rc.1dnil[bWLAhhdinner_checksummhexpmmphoenixm1.3.2m *QpkNn~ˊ,q痍\sxbWLAhhdversionsmhexpmm plug_cowboyl m1.0.0m2.0.0m2.0.1m2.0.2m2.1.0m2.1.1m2.1.2m2.1.3m2.2.0m2.2.1m2.2.2m2.3.0jGbWLAhhd timestampmhexpmmpostgrexm0.5.4hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm0.2.5hhba aha a9a0GbWLAhhd timestampmhexpmmpostgrexm0.5.0hhba aha a9a0`bWLAhhdinner_checksummhexpmmphoenixm 1.5.0-rc.0m 8;njxPZh>"Ξǣ,[bWLAhhdouter_checksummhexpmmphoenixm1.2.3m ̷ĨK/c?W?8%it<€3bWLAhhdretiredmhexpmmplugm1.10.3dnil;bWLAhhdretiredmhexpmm db_connectionm2.1.1dnilhbWLAhhddepsmhexpmm phoenix_htmlm2.9.0lhmhexpmmplugmplugm~> 1.0dfalsej\bWLAhhdinner_checksummhexpmmphoenixm0.15.0m JRlá=z^J@"!KlbWLAhhddepsmhexpmmpostgrexm0.5.3lhmhexpmmdecimalmdecimalm~> 0.2.3dfalsejhbWLAhhddepsmhexpmm phoenix_htmlm2.6.1lhmhexpmmplugmplugm~> 1.0dfalsejabWLAhhdinner_checksummhexpmm db_connectionm0.2.1m CaC,ʔ'-ŀҁ L^bWLAhhdinner_checksummhexpmmjasonm 1.0.0-rc.1m BNnn|+dcXah=S`F%XbWLAhhdouter_checksummhexpmmplugm0.5.1m '#ryNP9Xjk_C.j/[bWLAhhdinner_checksummhexpmmdecimalm1.7.0m 0ֵ,TfcsYPߞf S_~Ū2bWLAhhdretiredmhexpmmplugm0.5.3dnilbWLAhhddepsmhexpmmpostgrexm0.13.2lhmhexpmm connectionm connectionm~> 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 1.1dfalsehmhexpmmdecimalmdecimalm~> 1.0dfalsej\bWLAhhdouter_checksummhexpmmphoenixm1.4.12m X3mw1*=o4%F0[bWLAhhdouter_checksummhexpmmphoenixm1.4.9m 3&oUu xOՔ_tz읰.cbWLAhhddepsmhexpmmplugm0.8.2lhmhexpmmcowboymcowboym~> 1.0dtruej^bWLAhhdinner_checksummhexpmm connectionm1.0.2m mAAfL.ĸu0iG(/0xjbWLAhhddepsmhexpmmpostgrexm0.9.1lhmhexpmmdecimalmdecimalm~> 1.0dfalsej[bWLAhhdouter_checksummhexpmmphoenixm1.4.3m ܨwg*Khb+l0Bňi1X[bWLAhhdinner_checksummhexpmmphoenixm1.5.2m {]lNvA I/jIgGbWLAhhd timestampmhexpmmphoenixm1.4.16hhba aha a9a0/bWLAhhddepsmhexpmm telemetrym0.2.0jFbWLAhhd timestampmhexpmmphoenixm1.3.1hhba aha a9a0]bWLAhhdouter_checksummhexpmmpostgrexm0.11.2m <$<ʎ sk{aJFQ$uBSXbWLAhhdinner_checksummhexpmmplugm1.1.7m @MMerFL/YH"[fbWLAhhdinner_checksummhexpmm db_connectionm 1.0.0-rc.0m ޽OLk;L l9c-ĵGbWLAhhd timestampmhexpmmpostgrexm0.5.2hhba aha a9a0bWLAhhddepsmhexpmmphoenix_paramsm1.0.1lhmhexpmmdecimalmdecimalm>= 1.7.0dfalsehmhexpmmphoenixmphoenixm>= 1.3.3dfalsej6bWLAhhdretiredmhexpmmpostgrexm0.8.0dnil[bWLAhhdinner_checksummhexpmmdecimalm1.4.1m Ps""|* ږ[ pebWLAhhddepsmhexpmmplugm0.5.3lhmhexpmmcowboymcowboym~> 1.0.0dtruejLbWLAhhd timestampmhexpmm phoenix_htmlm2.11.1hhba aha a9a02bWLAhhdretiredmhexpmmplugm0.4.1dnil5bWLAhhdretiredmhexpmmdecimalm1.8.0dnilCbWLAhhd timestampmhexpmmplugm1.1.1hhba aha a9a0[bWLAhhdinner_checksummhexpmmdecimalm0.2.4m qt6Dh2A?k't*PgLICVFbWLAhhd timestampmhexpmmdecimalm0.2.2hhba aha a9a0abWLAhhdinner_checksummhexpmm db_connectionm2.2.0m #與`$^EАUˇj슶ޢBL$AN8XbWLAhhdouter_checksummhexpmmplugm1.0.6m mK-7e ͦS'5bWLAhhdretiredmhexpmmphoenixm0.2.2dnil 1.0dfalsehmhexpmm db_connectionm db_connectionm~> 2.0dfalsehmhexpmmdecimalmdecimalm~> 1.5dfalsehmhexpmmjasonmjasonm~> 1.0dtruejhbWLAhhddepsmhexpmm phoenix_htmlm2.9.3lhmhexpmmplugmplugm~> 1.0dfalsej_bWLAhhdouter_checksummhexpmm plug_cryptom1.0.0m sh/AL]oi;tNXwY7bWLAhhdretiredmhexpmmplugm 1.5.0-rc.0dnilbWLAhhddepsmhexpmmphoenixm0.9.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm ~> 0.10.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.4.2dtruejXbWLAhhdouter_checksummhexpmmplugm1.1.3m 0c倉w<\zQY/OZ~N3oCbWLAhhd timestampmhexpmmplugm1.0.3hhba aha a9a0GbWLAhhd timestampmhexpmmpostgrexm0.8.3hhba aha a9a0`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.3.1m 7i8x }6JyHhk2bWLAhhdretiredmhexpmmplugm1.8.3dnil2bWLAhhdretiredmhexpmmplugm1.0.4dnil5bWLAhhdretiredmhexpmmdecimalm1.9.0dnilbWLAhhddepsmhexpmm db_connectionm0.1.6lhmhexpmmbackoffmbackoffm~> 1.0dfalsehmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruej[bWLAhhdouter_checksummhexpmmphoenixm0.3.0m syeݞ 5aREx#7vK"wbWLAhhddepsmhexpmm phoenix_htmlm1.0.0lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsej_bWLAhhdinner_checksummhexpmm plug_cowboym2.2.2m z ]盒2ĔvLȐ6bWLAhhdretiredmhexpmmphoenixm0.12.0dnil5bWLAhhdretiredmhexpmmdecimalm0.2.4dnilbWLAhhddepsmhexpmmphoenixm1.1.6lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej2bWLAhhdretiredmhexpmmplugm1.1.1dnilCbWLAhhd timestampmhexpmmplugm1.6.4hhba aha a9a0^bWLAhhdinner_checksummhexpmm connectionm1.0.0m ʀdtMu;L_o&Ii)ږGbWLAhhd timestampmhexpmmphoenixm1.4.15hhba aha a9a0FbWLAhhd timestampmhexpmmdecimalm0.2.3hhba aha a9a0MbWLAhhd timestampmhexpmmpostgrexm 0.14.0-rc.0hhba aha a9a0FbWLAhhd timestampmhexpmmphoenixm1.4.8hhba aha a9a0YbWLAhhdouter_checksummhexpmmplugm0.11.0m "89fأXI?J\sT68EhGCbWLAhhd timestampmhexpmmplugm0.4.2hhba aha a9a0bbWLAhhdinner_checksummhexpmmphoenix_paramsm1.1.3m 2{kJkf c}u1{ j`bWLAhhdinner_checksummhexpmmphoenixm 1.3.0-rc.3m 7 9 5r}F!Yj 0DXbWLAhhdouter_checksummhexpmmplugm1.0.2m A› Nm~Q@LÅDyS]bWLAhhdinner_checksummhexpmmpostgrexm0.12.1m /F:D/B~;΁ |2bWLAhhdretiredmhexpmmplugm0.8.0dnilbWLAhhddepsmhexpmm db_connectionm 1.0.0-rc.1lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 1.0.0-beta.2dtruejCbWLAhhd timestampmhexpmmphoenix_pubsubhhba aha a9a0FbWLAhhd timestampmhexpmmdecimalm1.4.1hhba aha a9a0bWLAhhddepsmhexpmmplugm1.2.4lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsej`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.9.1m pqm e=EFxenX".Hi6DX?VV5E6M^^AE@uUEh5bWLAhhdretiredmhexpmmdecimalm0.2.1dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.2.1m Sg%pXyOdoa⸻9tlbWLAhhddepsmhexpmm db_connectionm0.2.1lhmhexpmm connectionm connectionm~> 1.0.2dfalsehmhexpmmpoolboympoolboym~> 1.5dtruehmhexpmmsbrokermsbrokerm~> 0.7dtruejCbWLAhhd timestampmhexpmmplugm1.7.1hhba aha a9a0MbWLAhhd timestampmhexpmmphoenix_paramsm0.2.0hhba aha a9a0hex-2.0.6/test/fixtures/registries/20210915.ets000066400000000000000000006750631437023760000207560ustar00rootroot00000000000000cXM bWLAhhdidZd nonode@nohost?6Ώhddecentralized_countersdfalsehdread_concurrencydfalsehdwrite_concurrencydfalsehd compresseddfalsehdmemoryb5hdownerXd nonode@nohost hdheirdnonehdnamedElixir.Hex.Devhdsizebhdnoded nonode@nohosthd named_tabledfalsehdtypedsethdkeyposahd protectiond protectedhd major_versionahd minor_versionahd extended_infoj 1.0dfalsejCbWLAhhd timestampmhexpmmplugm0.4.2hhbaahaa4a5bWLAhhdretiredmhexpmmphoenixm1.0.2dnil5bWLAhhdretiredmhexpmmdecimalm1.5.0dnilXbWLAhhdouter_checksummhexpmmplugm0.8.1m Pߙ%5s}_ݡD/TD]_bWLAhhdinner_checksummhexpmm plug_cowboym2.4.1m wP'.TWIP_Zc )5bWLAhhdretiredmhexpmmphoenixm0.2.2dnilHbWLAhhd timestampmhexpmm telemetrym0.4.1hhbaahaa4a5bWLAhhdretiredmhexpmmphoenixm1.5.6dnilCbWLAhhd timestampmhexpmmplugm1.1.2hhbaahaa4asbWLAhhddepsmhexpmm phoenix_htmlm2.5.1lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejCbWLAhhd timestampmhexpmmmimem1.3.1hhbaahaaa.XbWLAhhdinner_checksummhexpmmplugm1.0.1m N=XB.@9l t hbWLAhhddepsmhexpmm phoenix_htmlm2.8.0lhmhexpmmplugmplugm~> 1.0dfalsej[bWLAhhdinner_checksummhexpmmdecimalm1.1.2m yie{-S{Q<Қ+HkQlBS [bWLAhhdouter_checksummhexpmmphoenixm0.4.1m 'Y Kj]MunLT܋Yg[bWLAhhdouter_checksummhexpmmdecimalm1.8.0m RiNn`PsLfXO[}1xfcAbWLAhhd timestampmhexpmm phoenix_htmlhhba a ha aa bbWLAhhdinner_checksummhexpmmphoenix_pubsubm2.0.0m vq{h읒H֍G9_CbWLAhhd timestampmhexpmmplugm1.6.0hhbaahaa4a:bWLAhhdretiredmhexpmmphoenixm 1.3.0-rc.0dnil 1.0dtruej+bWLAhhddepsmhexpmmranchm1.7.1j>bWLAhhdretiredmhexpmmcowboy_telemetrym0.2.0dnilZbWLAhhdinner_checksummhexpmmcowlibm2.2.0m ^7L%L021得bU5bWLAhhdretiredmhexpmmdecimalm1.4.1dnilCbWLAhhd timestampmhexpmmplugm1.0.2hhbaahaa4a2bWLAhhdretiredmhexpmmmimem1.2.0dnilKbWLAhhd timestampmhexpmm phoenix_htmlm1.3.0hhba a ha aa CbWLAhhd timestampmhexpmmplugm0.8.4hhbaahaa4asbWLAhhddepsmhexpmm phoenix_htmlm2.2.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej3bWLAhhdretiredmhexpmmjasonm1.0.0dnil^bWLAhhdouter_checksummhexpmmranchm 2.0.0-rc.1m P77_5#(!ݡRPibWLAhhddepsmhexpmm phoenix_htmlm2.11.0lhmhexpmmplugmplugm~> 1.5dfalsej9bWLAhhdretiredmhexpmm plug_cryptom1.1.2dnilYbWLAhhdouter_checksummhexpmmplugm1.11.1m #RNOX|;9.%4( N:YbWLAhhdouter_checksummhexpmmranchm2.0.0m H@b<-:|/SLTQؤ*YbWLAhhdinner_checksummhexpmmplugm0.11.2m Җ\7İԩ _e_O`*ZHbWLAhhd timestampmhexpmmplugm 1.4.0-rc.0hhbaahaa4adbWLAhhddepsmhexpmmplugm0.13.1lhmhexpmmcowboymcowboym~> 1.0dtruej5bWLAhhdretiredmhexpmmphoenixm1.2.3dnilObWLAhhd timestampmhexpmm phoenix_htmlm 2.0.0-devhhba a ha aa fbWLAhhddepsmhexpmmjasonm1.1.2lhmhexpmmdecimalmdecimalm~> 1.0dtruejXbWLAhhdinner_checksummhexpmmplugm1.6.0m 8Lb->$rE[QTKwSoabWLAhhdouter_checksummhexpmm phoenix_htmlm2.14.2m X%] |/l\ғpE/5bWLAhhdretiredmhexpmmphoenixm1.0.5dnilDbWLAhhd timestampmhexpmmranchm1.6.1hhba a ha aa +bWLAhhddepsmhexpmmranchm1.2.1jFbWLAhhd timestampmhexpmmphoenixm1.3.3hhba a ha aa [bWLAhhdouter_checksummhexpmmdecimalm0.2.0m &EQ{-D; Mʝ4$JbWLAhhd timestampmhexpmm plug_cowboym2.2.2hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm0.2.9m x*;D4Dc~| d]`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.3.0m 'կ z9X>b+Qb: ڨ`( y_bWLAhhdouter_checksummhexpmm plug_cowboym2.5.2m nt``@"svIb5D5bWLAhhdretiredmhexpmmdecimalm2.0.0dnil6bWLAhhdretiredmhexpmmphoenixm0.17.0dnil\bWLAhhdouter_checksummhexpmmphoenixm0.16.0m !,@X _F(bWLAhhddepsmhexpmmplugm1.5.1lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.3dtruehmhexpmmmimemmimem~> 1.0dfalsejabWLAhhdinner_checksummhexpmm phoenix_htmlm2.12.0m KfUd=6UFֵSL+Fv"[bWLAhhdinner_checksummhexpmmphoenixm0.9.0m cmHZ^j:x:_h[E-bWLAhhddepsmhexpmmdecimalm0.2.3jEbWLAhhd timestampmhexpmmcowlibm2.8.0hhbaahaaa.XbWLAhhdinner_checksummhexpmmplugm0.6.0m b#C(lm6 t{-`bWLAhhdinner_checksummhexpmmdecimalm 1.9.0-rc.0m cfja8{@<Lp}2bWLAhhdretiredmhexpmmplugm1.1.7dnil2bWLAhhdretiredmhexpmmplugm1.0.2dnil-bWLAhhddepsmhexpmmdecimalm1.9.0j:bWLAhhdretiredmhexpmm phoenix_htmlm2.0.0dnilDbWLAhhd timestampmhexpmmplugm0.11.0hhbaahaa4aZbWLAhhdouter_checksummhexpmmcowlibm1.0.0m MV~ϓ9t51aM=ZtkbWLAhhddepsmhexpmmjasonm 1.0.0-rc.1lhmhexpmmdecimalmdecimalm~> 1.0dtruejXbWLAhhdinner_checksummhexpmmplugm1.2.0m IkcJI׀:gΜ෹% Y :bWLAhhdretiredmhexpmm phoenix_htmlm2.4.0dnil3bWLAhhdretiredmhexpmmplugm1.10.1dnilwbWLAhhddepsmhexpmm phoenix_htmlm1.4.0lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsej1bWLAhhddepsmhexpmm plug_cryptom1.1.0jbWLAhhddepsmhexpmmplugm1.6.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsejYbWLAhhdouter_checksummhexpmmplugm0.11.2m 0Hи#ƢJ-Pr4YbWLAhhdinner_checksummhexpmmranchm1.6.2m m 2.7dfalsehmhexpmmcowboy_telemetrymcowboy_telemetrym~> 0.3dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej5bWLAhhdretiredmhexpmmdecimalm1.0.0dnil3bWLAhhdretiredmhexpmmranchm1.6.2dnil[bWLAhhdouter_checksummhexpmmphoenixm1.5.6m Ӛ0kj')\y,po竻=3mSyV5bWLAhhdretiredmhexpmmphoenixm1.4.1dnil9bWLAhhdretiredmhexpmm plug_cowboym2.1.3dnilZbWLAhhdouter_checksummhexpmmpoisonm1.0.2m 0AX55cfWLbWLAhhd timestampmhexpmm phoenix_htmlm2.10.5hhba a ha aa ,bWLAhhddepsmhexpmmpoisonm1.2.1j5bWLAhhdretiredmhexpmmphoenixm1.0.4dnil4bWLAhhddepsmhexpmmphoenix_pubsubm1.1.2jbWLAhhddepsmhexpmmphoenixm1.5.5lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejZbWLAhhdouter_checksummhexpmmcowlibm2.3.0m ֕sTht]MwN؛XbWLAhhdinner_checksummhexpmmplugm1.1.8m ۋmyRDjp2C4bWLAhhdretiredmhexpmmcowlibm2.2.0dnil[bWLAhhdinner_checksummhexpmmphoenixm1.1.9m Gւ52(t,[֛A}9ytY_[bWLAhhdouter_checksummhexpmmdecimalm0.2.4m eBB:QN.cGJ9@5"5bWLAhhdretiredmhexpmmdecimalm0.1.2dnilbWLAhhddepsmhexpmmplugm1.6.3lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsej2bWLAhhdretiredmhexpmmplugm1.3.2dnilCbWLAhhd timestampmhexpmmplugm1.6.1hhbaahaa4a[bWLAhhdouter_checksummhexpmmdecimalm1.3.0m B 0 1.0.0dfalsehmhexpmmranchmranchm~> 1.0dfalsej`bWLAhhdouter_checksummhexpmmphoenixm 1.4.0-rc.2m &h (0"B}pe:8BibWLAhhddepsmhexpmm phoenix_htmlm2.10.0lhmhexpmmplugmplugm~> 1.0dfalsejFbWLAhhd timestampmhexpmmphoenixm1.1.4hhba a ha aa &bWLAhd last_updatehhba ahaaabWLAhhddepsmhexpmmcowboy_telemetrym0.4.0lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmm telemetrym telemetrym~> 1.0dfalsejbbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.1.0m B.*ҞKna߄*cz;e,MbWLAhhd timestampmhexpmmphoenix_pubsubm1.0.1hhba a ha aa ibWLAhhddepsmhexpmm phoenix_htmlm2.13.4lhmhexpmmplugmplugm~> 1.5dfalsejbWLAhhddepsmhexpmmcowboym2.4.0lhmhexpmmcowlibmcowlibm~> 2.3.0dfalsehmhexpmmranchmranchm~> 1.5.0dfalsejCbWLAhhd timestampmhexpmmplugm0.5.2hhbaahaa4aXbWLAhhdinner_checksummhexpmmplugm1.2.5m |؋f4Bf w{ї[bWLAhhdinner_checksummhexpmmdecimalm0.2.5m @[x:`&'?ԀC{Xk4NêYbWLAhhdouter_checksummhexpmmplugm1.11.0m -c?\/iuhܻ,t0vCbWLAhhd timestampmhexpmmmimem1.0.1hhbaahaaa.4bWLAhhdretiredmhexpmmcowboym1.1.0dnil-bWLAhhddepsmhexpmmdecimalm1.0.0jJbWLAhhd timestampmhexpmm plug_cryptom1.1.1hhbaahaaa.[bWLAhhdouter_checksummhexpmmdecimalm1.1.0m  }9 ,SHmga8-k!bWLAhhdversionsmhexpmmpoisonlm1.0.0m1.0.1m1.0.2m1.0.3m1.1.0m1.1.1m1.2.0m1.2.1m1.3.0m1.3.1m1.4.0m1.5.0m1.5.1m1.5.2m2.0.0m2.0.1m2.1.0m2.2.0m3.0.0m3.1.0m4.0.0m4.0.1m5.0.0j2bWLAhhdretiredmhexpmmplugm1.2.2dnil2bWLAhhdretiredmhexpmmplugm0.5.3dnil-bWLAhhddepsmhexpmmdecimalm1.5.0j[bWLAhhdinner_checksummhexpmmphoenixm1.0.6m ד kK[=rEMWhbWLAhhddepsmhexpmmplugm 1.5.0-rc.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.1dtruehmhexpmmmimemmimem~> 1.0dfalsejXbWLAhhdouter_checksummhexpmmplugm1.1.1m  E!/&uW><fJ]pqabWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.1m H%[6id~^d hh\bWLAhhdouter_checksummhexpmmphoenixm0.12.0m -V>dOva1MSdUC~68 dbWLAhhddepsmhexpmmplugm0.10.0lhmhexpmmcowboymcowboym~> 1.0dtruejXbWLAhhdouter_checksummhexpmmmimem1.5.0m ULU"I=-:ޝ 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejCbWLAhhd timestampmhexpmmmimem1.5.0hhbaahaaa.bWLAhhdversionsmhexpmmmimel m0.0.1m1.0.0m1.0.1m1.1.0m1.2.0m1.3.0m1.3.1m1.4.0m1.5.0m1.6.0m2.0.0m2.0.1j4bWLAhhdretiredmhexpmmcowlibm2.5.1dnilVbWLAhhd registry_etagmhexpmm plug_cowboym""bb2b114bf8e3996487c6fc8358247b5e"2bWLAhhdretiredmhexpmmplugm1.3.6dnil2bWLAhhdretiredmhexpmmplugm0.9.0dnil:bWLAhhdretiredmhexpmm phoenix_htmlm2.6.2dnilDbWLAhhd timestampmhexpmmplugm1.12.1hhbaahaa4a2bWLAhhdretiredmhexpmmplugm1.7.0dnil[bWLAhhdouter_checksummhexpmmdecimalm2.0.0m 4fnUި}7b2j# DwbWLAhhddepsmhexpmmcowboym1.0.2lhmhexpmmcowlibmcowlibm~> 1.0.0dfalsehmhexpmmranchmranchm~> 1.0dfalsejdbWLAhhdinner_checksummhexpmmcowboy_telemetrym0.1.0m i{8:JX:iCB"S'wC5bWLAhhdretiredmhexpmmphoenixm0.7.0dnilZbWLAhhdouter_checksummhexpmmcowboym2.9.0m ,rKNI|crS T\g5bWLAhhdretiredmhexpmmphoenixm1.4.0dnil:bWLAhhd timestampmhexpmmranchhhba a ha aa YbWLAhhdinner_checksummhexpmmplugm1.12.1m dVx`'ۜb=ۖMl5}4bWLAhhdretiredmhexpmmcowboym2.2.1dnilZbWLAhhdouter_checksummhexpmmcowboym1.1.1m VrnE|5@ ECLyBSXZ866bWLAhhdretiredmhexpmmphoenixm1.5.12dnil,bWLAhhddepsmhexpmmcowlibm2.2.1j,bWLAhhddepsmhexpmmpoisonm1.0.3j4bWLAhhdretiredmhexpmmcowlibm2.4.0dnilFbWLAhhd timestampmhexpmmphoenixm0.6.2hhba a ha aa \bWLAhhdouter_checksummhexpmmphoenixm0.2.11m I0BDaT>@y dƀ:bWLAhhdretiredmhexpmm phoenix_htmlm1.0.1dnil3bWLAhhdretiredmhexpmmplugm0.14.0dnil-bWLAhhddepsmhexpmmdecimalm1.2.0jXbWLAhhdouter_checksummhexpmmmimem0.0.1m $ ߽#C8Fd7S;:L5C' :bWLAhhdretiredmhexpmmphoenixm 1.3.0-rc.1dnilXbWLAhhdouter_checksummhexpmmplugm1.7.2m ޘ%o֭ ͈k=e~`k2bWLAhhdretiredmhexpmmmimem1.3.0dnil2bWLAhhdretiredmhexpmmplugm0.8.3dnil\bWLAhhdinner_checksummhexpmmphoenixm0.2.10m !/I7תck[%NS \bWLAhhdouter_checksummhexpmmphoenixm1.4.11m 7#os3s^oB~Xᤲ"bWLAhhddepsmhexpmmphoenixm1.4.1lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruej5bWLAhhdretiredmhexpmmphoenixm1.2.0dnilXbWLAhhdinner_checksummhexpmmplugm1.8.0m &٬'(&+x )oCw[bWLAhhdinner_checksummhexpmmphoenixm1.0.3m wafnQ+èzh $\CbWLAhhd timestampmhexpmmplugm1.0.3hhbaahaa4aZbWLAhhdinner_checksummhexpmmcowboym2.2.1m Cj"*uPQB`j2<[bWLAhhdouter_checksummhexpmmphoenixm1.5.0m ƕr9K}bc%P;K Ծ609bWLAhhddepsmhexpmmplugm1.11.0lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejZbWLAhhdinner_checksummhexpmmcowlibm1.0.2m v,:S o!s 7}=~߄bbWLAhhdversionsmhexpmm phoenix_htmll5m1.0.0m1.0.1m1.1.0m1.2.0m1.2.1m1.3.0m1.4.0m 2.0.0-devm2.0.0m2.0.1m2.1.0m2.1.1m2.1.2m2.2.0m2.3.0m2.3.1m 2.4.0-devm2.4.0m2.5.0m2.5.1m2.6.0m2.6.1m2.6.2m 2.7.0-devm2.7.0m2.8.0m2.9.0m2.9.1m2.9.2m2.9.3m2.10.0m2.10.1m2.10.2m2.10.3m2.10.4m2.10.5m2.11.0m2.11.1m2.11.2m2.12.0m2.13.0m2.13.1m2.13.2m2.13.3m2.13.4m2.14.0m2.14.1m2.14.2m2.14.3m3.0.0m3.0.1m3.0.2m3.0.3jjbWLAhhddepsmhexpmmphoenixm1.4.11lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej:bWLAhhdretiredmhexpmmphoenixm 1.3.0-rc.3dnil[bWLAhhdinner_checksummhexpmmphoenixm0.3.1m wg!m m~!SPbJXig0a+_bWLAhhdouter_checksummhexpmm plug_cryptom1.1.0m ͡ 3%eu|%ʮȧ-l=^bWLAhhdouter_checksummhexpmmjasonm 1.0.0-rc.2m wv3ԉ ĘDo$*bWLAhhddepsmhexpmmplugm0.5.0j9bWLAhhdretiredmhexpmm plug_cryptom1.1.0dnilXbWLAhhdinner_checksummhexpmmplugm1.4.3m #mw{f*o6jIIJ1bWLAhhddepsmhexpmm plug_cryptom1.1.2jwbWLAhhddepsmhexpmm phoenix_htmlm 2.0.0-devlhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej,bWLAhhddepsmhexpmmcowlibm1.1.0j:bWLAhhdretiredmhexpmmphoenixm 1.2.0-rc.0dnil4bWLAhhdretiredmhexpmmpoisonm5.0.0dnilFbWLAhhd timestampmhexpmmphoenixm1.1.7hhba a ha aa ZbWLAhhdouter_checksummhexpmmcowboym2.3.0m Pq&'0CQ[W#h0Cg c,bWLAhhddepsmhexpmmcowlibm2.2.0j`bWLAhhdouter_checksummhexpmmphoenixm 1.4.0-rc.0m a0>Yc$ph-6`g^TbWLAhhddepsmhexpmmcowboym1.1.1lhmhexpmmcowlibmcowlibm~> 1.0.2dfalsehmhexpmmranchmranchm~> 1.3.1dfalsej`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.6.2m i{1HT]hBrX5p- _2,EbWLAhhd timestampmhexpmmcowboym1.0.0hhbaahaaa.5bWLAhhdretiredmhexpmmphoenixm1.1.8dnil[bWLAhhdouter_checksummhexpmmphoenixm0.2.8m YyT%#E*i| nfq;Ѝނ2bWLAhhdretiredmhexpmmplugm1.1.5dnil[bWLAhhdouter_checksummhexpmmphoenixm1.1.0m Q>Ob S.- bWLAhhddepsmhexpmmcowboym2.6.2lhmhexpmmcowlibmcowlibm~> 2.7.2dfalsehmhexpmmranchmranchm~> 1.7.1dfalsejZbWLAhhdouter_checksummhexpmmcowboym1.0.0m D:FܧY^11 _+h_bWLAhhdinner_checksummhexpmm plug_cowboym2.5.2m bL`Y~,#'#~9k䘈EbWLAhhd timestampmhexpmmpoisonm1.0.2hhba a ha a.a\bWLAhhdinner_checksummhexpmmphoenixm1.4.16m ,fV|D8 3B7*Bn=:HC5bWLAhhdretiredmhexpmmdecimalm1.8.1dnilbWLAhhddepsmhexpmmplugm1.2.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsej9bWLAhhdretiredmhexpmm plug_cowboym2.0.1dnil5bWLAhhdretiredmhexpmmphoenixm1.0.3dnilZbWLAhhdinner_checksummhexpmmpoisonm4.0.1m UoכX[{1 4 K-sW CbWLAhhd timestampmhexpmmplugm1.3.2hhbaahaa4aXbWLAhhdinner_checksummhexpmmplugm1.0.0m ߶ 3]gN{a!<0[bWLAhhdouter_checksummhexpmmphoenixm0.1.0m uW X  Tb~ n?p*:bWLAhhdretiredmhexpmmphoenixm 1.3.0-rc.2dnil8bWLAhhdretiredmhexpmmranchm 2.0.0-rc.1dnilHbWLAhhd timestampmhexpmmplugm 1.5.0-rc.0hhbaahaa4aFbWLAhhd timestampmhexpmmphoenixm1.4.2hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm1.4.7m S>ke5qN4'ՠ$]myZbWLAhhdouter_checksummhexpmmpoisonm1.4.0m qZI99:N֝P`bf2bWLAhhdretiredmhexpmmplugm0.5.0dnil]bWLAhhdouter_checksummhexpmm telemetrym0.2.0m Nqy]YL?C i .x@#2:bWLAhhdretiredmhexpmmdecimalm 1.9.0-rc.0dnilZbWLAhhdouter_checksummhexpmmpoisonm2.1.0m ,9|S>!AN< C,cCbWLAhhd timestampmhexpmmplugm1.0.4hhbaahaa4aYbWLAhhdinner_checksummhexpmmranchm1.6.1m & rL~<l7Bb_]a"35bWLAhhdretiredmhexpmmphoenixm1.5.4dnilZbWLAhhdouter_checksummhexpmmpoisonm1.0.0m ~)E#b :Q G{[bWLAhhdinner_checksummhexpmmcowlibm2.10.1m TBkN48^Y/F\GިCbWLAhhd timestampmhexpmmmimem0.0.1hhbaahaaa.FbWLAhhd timestampmhexpmmphoenixm1.1.1hhba a ha aa fbWLAhhddepsmhexpmmjasonm1.1.1lhmhexpmmdecimalmdecimalm~> 1.0dtruej/bWLAhhddepsmhexpmm telemetrym0.2.0j3bWLAhhdretiredmhexpmmranchm1.6.0dnil5bWLAhhdretiredmhexpmmcowlibm2.10.1dnilFbWLAhhd timestampmhexpmmphoenixm1.3.2hhba a ha aa FbWLAhhd timestampmhexpmmphoenixm1.5.0hhba a ha aa 5bWLAhhdretiredmhexpmmphoenixm1.4.9dnilEbWLAhhd timestampmhexpmmcowlibm2.2.1hhbaahaaa.[bWLAhhdinner_checksummhexpmmdecimalm0.2.1m U%qs]A27MXbWLAhhdouter_checksummhexpmmplugm1.1.9m SPi]I\+B*'3$EbWLAhhd timestampmhexpmmpoisonm1.4.0hhba a ha a.aZbWLAhhdouter_checksummhexpmmpoisonm1.3.1m ׍嫺ؙ/m 0FUZ`ҊXabWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.3m W+w=*.@Vz? 2bWLAhhdversionsmhexpmmcowliblm1.0.0m1.0.1m1.0.2m1.1.0m1.2.0m1.3.0m2.0.0m2.0.1m2.1.0m2.2.0m2.2.1m2.3.0m2.4.0m2.5.0m2.5.1m2.6.0m2.7.0m2.7.1m2.7.2m2.7.3m2.8.0m2.9.0m2.9.1m2.10.0m2.10.1m2.11.0jYbWLAhhdinner_checksummhexpmmranchm1.2.1m ,{F|Oiva~(bsbWLAhhddepsmhexpmm phoenix_htmlm2.0.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej:bWLAhhdretiredmhexpmmphoenixm 1.4.0-rc.3dnilgbWLAhhddepsmhexpmmpoisonm5.0.0lhmhexpmmdecimalmdecimalm~> 2.0dtruejbWLAhhddepsmhexpmm plug_cowboym2.0.2lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.4.0m ;ݙ\_^$HENf ^wQ5[bWLAhhdinner_checksummhexpmmphoenixm0.5.0m tlAe-8æ%Z6@**bWLAhhddepsmhexpmmmimem1.2.0jZbWLAhhdinner_checksummhexpmmcowlibm2.0.0m —qG=RX#-S4 )PbWLAhhddepsmhexpmmcowboym2.0.0lhmhexpmmcowlibmcowlibm~> 2.0.0dfalsehmhexpmmranchmranchm~> 1.4.0dfalsejbWLAhhddepsmhexpmmphoenixm1.1.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejXbWLAhhdouter_checksummhexpmmmimem2.0.1m z Үbas8ߑcB*bWLAhhddepsmhexpmmplugm0.4.4j2bWLAhhdretiredmhexpmmplugm1.8.2dnil5bWLAhhdretiredmhexpmmdecimalm0.2.5dnil[bWLAhhdinner_checksummhexpmmdecimalm0.2.3m r}$޿>4m\lZ$KbWLAhhd timestampmhexpmmdecimalm 1.9.0-rc.0hhbaaha aa:abWLAhhdinner_checksummhexpmm phoenix_htmlm2.13.1m KS(ߠUi7K[ /YbWLAhhdinner_checksummhexpmmplugm0.12.1m X"!崫*x/ӡ~(#_bWLAhhdinner_checksummhexpmm plug_cowboym2.1.2m ݵR8ÎD.'2F]|Gŀ^:bWLAhhdretiredmhexpmm phoenix_htmlm2.3.1dnilbWLAhhddepsmhexpmmplugm1.10.1lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruej`bWLAhhdouter_checksummhexpmmphoenixm 1.3.0-rc.0m 5PN 1.0dtruejFbWLAhhd timestampmhexpmmphoenixm0.4.1hhba a ha aa LbWLAhhd timestampmhexpmm phoenix_htmlm2.10.2hhba a ha aa XbWLAhhdinner_checksummhexpmmplugm1.6.2m j{һm]ݕp ΈSQ"KَZbWLAhhdinner_checksummhexpmmcowboym1.1.2m a)Ze``-7 po)ܩ;wbWLAhhddepsmhexpmm phoenix_htmlm1.1.0lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsej`bWLAhhdinner_checksummhexpmmphoenixm 1.3.0-rc.1m KH#L^Xeu7bWLAhhddepsmhexpmmphoenixm0.12.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm ~> 0.12.1dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.5.1dtruejdbWLAhhdinner_checksummhexpmmcowboy_telemetrym0.3.1m ѡׯ'fTzF'CؠAgTbWLAhhddepsmhexpmm plug_cowboym2.1.1lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsej-bWLAhhddepsmhexpmmdecimalm0.1.2jObWLAhhd timestampmhexpmm phoenix_htmlm 2.7.0-devhhba a ha aa cbWLAhhddepsmhexpmmplugm0.9.0lhmhexpmmcowboymcowboym~> 1.0dtruej[bWLAhhdouter_checksummhexpmmcowlibm2.10.1m Bq(q֘ꣳ.ihD<\tD]bWLAhhdouter_checksummhexpmm telemetrym0.4.0m |1p| 0-Ow?A3bWLAhhdretiredmhexpmmplugm0.13.0dnil[bWLAhhdinner_checksummhexpmmdecimalm1.3.0m Afx`E|Rӣ՗M'}3bWLAhhdretiredmhexpmmplugm1.10.0dnilFbWLAhhd timestampmhexpmmdecimalm1.4.0hhbaaha aa:bWLAhhddepsmhexpmmphoenixm0.2.4lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmplugmplugm0.4.3dfalsejYbWLAhhdouter_checksummhexpmmplugm0.12.1m 4+`%`bȩ@L)^DFPbWLAhhd registry_etagmhexpmmranchm""db832848a90690400d75bacdc5ccd01e"bWLAhhddepsmhexpmmphoenixm0.7.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmpoisonmpoisonm~> 1.2dfalsejZbWLAhhdouter_checksummhexpmmpoisonm3.1.0m fs>{W83vmωTGZbWLAhhdinner_checksummhexpmmpoisonm1.2.0m Am^‹vF-MHK@vgܩ4bWLAhhdretiredmhexpmmpoisonm1.0.0dnilXbWLAhhdinner_checksummhexpmmplugm0.9.0m c"&Ù]!UWrƒD2bWLAhhdretiredmhexpmmplugm1.1.8dnil2bWLAhhdretiredmhexpmmplugm1.7.1dnilMbWLAhhd timestampmhexpmmphoenix_pubsubm0.0.1hhba a ha aa ZbWLAhhdouter_checksummhexpmmcowboym2.2.1m J[S7XJ6ѐ⺄^ק]=5bWLAhhdretiredmhexpmmdecimalm0.2.0dnilZbWLAhhdouter_checksummhexpmmpoisonm1.0.1m a4&)•C}  EbWLAhhd timestampmhexpmmcowboym1.0.4hhbaahaaa.[bWLAhhdinner_checksummhexpmmphoenixm1.1.6m {fi/Z0ڷ=b(ս*BkGZbWLAhhdouter_checksummhexpmmpoisonm2.2.0m Q C9a(AtėRL([yz^bWLAhhdinner_checksummhexpmmranchm 2.0.0-rc.1m J^.CD[jo[>FbWLAhhd timestampmhexpmmphoenixm1.5.1hhba a ha aa ]bWLAhhdinner_checksummhexpmmplugm 1.4.0-rc.0m Solm$a63;3r~[ FbWLAhhd timestampmhexpmmphoenixm1.5.6hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm0.3.1m YHy7^6aM+VSN%XbWLAhhdouter_checksummhexpmmplugm1.7.1m ڥ ċl2 b|uUM^bWLAhhddepsmhexpmmphoenixm0.2.6lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.1dfalsehmhexpmmplugmplugm0.4.4dfalsejFbWLAhhd timestampmhexpmmcowlibm2.10.0hhbaahaaa.`bWLAhhdouter_checksummhexpmm phoenix_htmlm3.0.0m 7=O),[v,2 ^HK@Pf,,ibWLAhhddepsmhexpmm phoenix_htmlm2.14.2lhmhexpmmplugmplugm~> 1.5dfalsejEbWLAhhd timestampmhexpmmcowboym2.6.3hhbaahaaa.JbWLAhhd timestampmhexpmm plug_cowboym2.0.1hhba a ha aa ZbWLAhhdinner_checksummhexpmmcowboym2.5.0m Nn'.܏CGV7[bWLAhhdinner_checksummhexpmmphoenixm1.3.3m _9災Dj,y|XUfcbWLAhhddepsmhexpmmplugm1.1.8lhmhexpmmcowboymcowboym~> 1.0dtruejYbWLAhhdouter_checksummhexpmmranchm1.3.1m ?2ߑ< J _\q,Cud,YbWLAhhdouter_checksummhexpmmplugm1.12.1m ~yw{mڑJ qeE*cL 6bWLAhhdretiredmhexpmmphoenixm1.4.15dnilCbWLAhhd timestampmhexpmmplugm1.6.3hhbaahaa4a,bWLAhhddepsmhexpmmcowlibm2.4.0j2bWLAhhdretiredmhexpmmplugm1.1.9dnil5bWLAhhdretiredmhexpmmphoenixm1.4.4dnilObWLAhhd timestampmhexpmmcowboy_telemetrym0.1.0hhbaahaaazbWLAhhdretiredmhexpmm plug_cowboym2.2.2tdmessagemBroken telemetry supportdreasondRETIRED_INVALIDFbWLAhhd timestampmhexpmmphoenixm1.2.3hhba a ha aa \bWLAhhdinner_checksummhexpmmphoenixm0.11.0m `3dLڜ,\O,pO@-bWLAhhddepsmhexpmmdecimalm0.1.1jXbWLAhhdinner_checksummhexpmmplugm1.5.1m [϶5^LG0?l)ҧoASe[bWLAhhdinner_checksummhexpmmphoenixm1.5.9m 66՝{7C`Z"|~%CbWLAhhd timestampmhexpmmplugm1.8.1hhbaahaa4aZbWLAhhdouter_checksummhexpmmcowlibm2.7.1m /`sx\Sk]Eh)6^CbWLAhhd timestampmhexpmmphoenix_pubsubhhba a ha aa KbWLAhhd timestampmhexpmm phoenix_htmlm3.0.1hhba a ha aa bWLAhhddepsmhexpmmphoenixm1.1.9lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejYbWLAhhdouter_checksummhexpmmranchm1.8.0m Ih/]QWgm)Ym^R--bWLAhhddepsmhexpmmdecimalm1.8.0jbWLAhhddepsmhexpmmcowboy_telemetrym0.3.1lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej4bWLAhhdretiredmhexpmmpoisonm1.0.1dnil,bWLAhhddepsmhexpmmcowlibm2.6.0jFbWLAhhd timestampmhexpmmphoenixm1.4.4hhba a ha aa bWLAhhddepsmhexpmmphoenixm1.0.6lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejbWLAhhddepsmhexpmmcowboym1.0.0lhmhexpmmcowlibmcowlibm~> 1.0.0dfalsehmhexpmmranchmranchm~> 1.0dfalsejdbWLAhhddepsmhexpmmplugm0.11.0lhmhexpmmcowboymcowboym~> 1.0dtruejXbWLAhhdouter_checksummhexpmmplugm0.5.3m E}A[; 2.7dfalsehmhexpmmcowboy_telemetrymcowboy_telemetrym~> 0.3dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej_bWLAhhdinner_checksummhexpmm plug_cowboym2.1.3m 8>k߂aa2D\ܶ34bWLAhhdretiredmhexpmmcowlibm2.7.3dnilFbWLAhhd timestampmhexpmmphoenixm0.9.0hhba a ha aa 7bWLAhhdretiredmhexpmmplugm 1.5.0-rc.2dnil2bWLAhhdretiredmhexpmmplugm1.2.4dnilabWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.4m 2I1c| p?-Mm4bWLAhhdretiredmhexpmmcowboym2.6.1dnilEbWLAhhd timestampmhexpmmpoisonm1.3.1hhba a ha a.a3bWLAhhdretiredmhexpmmplugm0.12.1dnil[bWLAhhdinner_checksummhexpmmdecimalm1.4.1m Ps""|* ږ[ p[bWLAhhdinner_checksummhexpmmphoenixm0.8.0m ҡ:l $,I 2aEӰ|KbbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.1.1m fhׇ$z_i̘Q6 <ibWLAhhddepsmhexpmmphoenixm1.4.8lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej_bWLAhhdouter_checksummhexpmm plug_cryptom1.2.2m czE𣀟y:KsHݞ(ZbWLAhhdouter_checksummhexpmmcowboym1.1.2m v;#>o$O̍q|CWsI|7bWLAhhdretiredmhexpmm telemetrym0.4.1dnilEbWLAhhd timestampmhexpmmpoisonm1.0.1hhba a ha a.aXbWLAhhdinner_checksummhexpmmplugm0.8.0m aC-N`|~<>&ҸEX.ęZbWLAhhdinner_checksummhexpmmcowlibm1.0.1m Zcr6)BdڙbWLAhhddepsmhexpmmphoenixm1.5.9lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13 or ~> 3.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej]bWLAhhdouter_checksummhexpmm telemetrym0.1.0m <1bhxAO\"BMPCD$XbWLAhhdouter_checksummhexpmmplugm1.3.5m X̡(9D/q*tmRdbWLAhhdouter_checksummhexpmmcowboy_telemetrym0.3.0m B")P]Un$b"O!gS[bWLAhhdinner_checksummhexpmmphoenixm0.3.0m |&QP?Xߛ*, b\^G>&݌bWLAhhddepsmhexpmmplugm1.4.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.1.2m {*= 0.12.2 and < 2.0.0dfalsej5bWLAhhdretiredmhexpmmphoenixm1.3.1dnilYbWLAhhdinner_checksummhexpmmranchm2.0.0m זaqT2V]mh$zIf[bWLAhhdouter_checksummhexpmmphoenixm1.4.5m kZJk9uhEA$s[bWLAhhdouter_checksummhexpmmphoenixm1.1.4m We#ΒB;C?DpQ YzXbWLAhhdouter_checksummhexpmmplugm1.8.1m LX:fɵA~mS>cjbWLAhhddepsmhexpmmphoenixm1.4.16lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej_bWLAhhdouter_checksummhexpmm plug_cowboym2.5.0m [,%XtF8k<4VR쀛vz\bWLAhhdouter_checksummhexpmmphoenixm1.4.16m l2S'7A<u%Wm\$ZbWLAhhdouter_checksummhexpmmpoisonm1.0.3m c+\L.V;5+5l-i-fXbWLAhhdinner_checksummhexpmmplugm1.4.4m 'Tvb',5 ӾQG5NFtĴ6bWLAhhdretiredmhexpmmphoenixm0.10.0dnilZbWLAhhdinner_checksummhexpmmcowboym1.0.0m дj^_UCFokV}RbR|dU]XbWLAhhdinner_checksummhexpmmplugm1.7.2m ׷u^ }D"7.CbWLAhhd timestampmhexpmmplugm0.4.4hhbaahaa4a2bWLAhhdretiredmhexpmmplugm0.4.2dnil[bWLAhhdinner_checksummhexpmmphoenixm1.1.3m ZK`c`o^݆ p*<,azlXbWLAhhdinner_checksummhexpmmmimem1.0.1m Ó$v}6'qbCM$zQ5bWLAhhdretiredmhexpmmdecimalm0.2.3dnilDbWLAhhd timestampmhexpmmranchm1.3.0hhba a ha aa abWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.3m C-7.zmYxCDQA"75YbWLAhhdouter_checksummhexpmmjasonm1.0.1m QQjL Y= hv%W4 CbWLAhhd timestampmhexpmmplugm1.6.4hhbaahaa4a2bWLAhhdretiredmhexpmmplugm1.3.5dnilebWLAhhddepsmhexpmmplugm0.7.0lhmhexpmmcowboymcowboym~> 1.0.0dtruej]bWLAhhdouter_checksummhexpmmplugm 1.2.0-rc.0m ~Ie -JizŅkwiC iZbWLAhhdouter_checksummhexpmmpoisonm4.0.1m 6K9KaY mkߗo%EbWLAhhd timestampmhexpmmpoisonm1.5.0hhba a ha a.aabWLAhhdouter_checksummhexpmm phoenix_htmlm2.13.0m kyi,(vS؜'miwu}oaKZ[bWLAhhdouter_checksummhexpmmphoenixm0.7.0m $y|6; w'Px`j1TEEbWLAhhd timestampmhexpmmcowlibm2.4.0hhbaahaaa.\bWLAhhdinner_checksummhexpmmphoenixm1.5.10m >bmrt 2?UI㫻ӋRsbWLAhhddepsmhexpmm phoenix_htmlm2.1.2lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej\bWLAhhdouter_checksummhexpmmphoenixm1.5.12m sOdl/o?gS 2AbWLAhhddepsmhexpmmphoenixm1.5.11lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13 or ~> 3.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej[bWLAhhdinner_checksummhexpmmphoenixm1.5.3m @NH4X? [b0;IabWLAhhdinner_checksummhexpmm phoenix_htmlm2.14.3m Q CW]0=WxieBqbWLAhhdversionsmhexpmmphoenix_pubsubl m0.0.1m0.1.0m 1.0.0-rc.0m1.0.0m1.0.1m1.0.2m1.1.0m1.1.1m1.1.2m2.0.0jKbWLAhhd timestampmhexpmmphoenixm 1.4.0-rc.0hhba a ha aa CbWLAhhd timestampmhexpmmplugm1.5.0hhbaahaa4aXbWLAhhdinner_checksummhexpmmplugm1.1.3m ,Cp~imL`Z[bWLAhhdouter_checksummhexpmmdecimalm0.2.5m .-h̆ lok$+FXnYGCbWLAhhd timestampmhexpmmplugm1.1.8hhbaahaa4a*bWLAhhddepsmhexpmmplugm0.4.3j\bWLAhhdouter_checksummhexpmmphoenixm0.15.0m ijLvȮB.At"u >V!ibWLAhhddepsmhexpmm phoenix_htmlm2.11.2lhmhexpmmplugmplugm~> 1.5dfalsejjbWLAhhddepsmhexpmmphoenixm1.4.12lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejbWLAhhddepsmhexpmmphoenixm1.1.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.2.1m Sg%pXyOdoa⸻9tlKbWLAhhd timestampmhexpmm phoenix_htmlm1.2.0hhba a ha aa abWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.5m O82cηF|IUTu yQ`^E`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.7.0m . D4 .C jYg|Yh5T8ՒB ,bWLAhhddepsmhexpmmpoisonm1.2.0jCbWLAhhd timestampmhexpmmplugm0.8.2hhbaahaa4aXbWLAhhdinner_checksummhexpmmplugm0.5.2m |"Wž/1޹\T5 J:bWLAhhdretiredmhexpmmphoenixm 1.4.0-rc.2dnil 1.0dfalsej,bWLAhhddepsmhexpmmpoisonm4.0.0jbWLAhhddepsmhexpmmplugm1.8.0lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruejbWLAhhddepsmhexpmmplugm 1.5.0-rc.2lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.1dtruehmhexpmmmimemmimem~> 1.0dfalsejCbWLAhhd timestampmhexpmmmimem1.6.0hhbaahaaa.ZbWLAhhdouter_checksummhexpmmcowlibm2.8.0m yT0!P(iR=L02ZbWLAhhdinner_checksummhexpmmcowlibm2.7.0m >nwV/U`YF-v/î>CbWLAhhddepsmhexpmmcowboym1.1.2lhmhexpmmcowlibmcowlibm~> 1.0.2dfalsehmhexpmmranchmranchm~> 1.3.2dfalsejZbWLAhhdinner_checksummhexpmmpoisonm1.0.0m IY+9s2x#Fc|v#_4bWLAhhdretiredmhexpmmcowlibm2.9.0dnilGbWLAhhd timestampmhexpmmphoenixm1.4.14hhba a ha aa 5bWLAhhdretiredmhexpmmphoenixm0.3.1dnil5bWLAhhdretiredmhexpmmphoenixm1.4.5dnilFbWLAhhd timestampmhexpmmdecimalm0.2.0hhbaaha aa:LbWLAhhd timestampmhexpmm phoenix_htmlm2.13.2hhba a ha aa FbWLAhhd timestampmhexpmmdecimalm1.2.0hhbaaha aa:9bWLAhhdretiredmhexpmm plug_cryptom1.2.1dnil5bWLAhhdretiredmhexpmmdecimalm1.1.1dnil4bWLAhhdretiredmhexpmmcowlibm1.3.0dnilXbWLAhhdinner_checksummhexpmmplugm1.3.1m FuB93pL^?B`dūU5bWLAhhdretiredmhexpmmphoenixm1.4.7dnilsbWLAhhddepsmhexpmm phoenix_htmlm2.5.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejabWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.0m iFM|S“4'QA8 JZbWLAhhdouter_checksummhexpmmpoisonm1.1.1m W|4vLl$GcH0kb! gXbWLAhhdinner_checksummhexpmmplugm1.4.0m '^f^Bl% $m_E;l }[bWLAhhdouter_checksummhexpmmphoenixm0.7.1m 7R8CIY<+h Aa&GFbWLAhhd timestampmhexpmmphoenixm0.1.0hhba a ha aa YbWLAhhdinner_checksummhexpmmranchm1.3.2m ZM\|e 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsejCbWLAhhd timestampmhexpmmplugm1.7.2hhbaahaa4aCbWLAhhd timestampmhexpmmplugm1.3.4hhbaahaa4abWLAhhddepsmhexpmmphoenixm1.1.7lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejXbWLAhhdouter_checksummhexpmmplugm1.6.3m o/J-s09+ %UpwJ`Qi[bWLAhhdouter_checksummhexpmmphoenixm1.3.4m I&`L^F/YYi6zĠS-;bWLAhhdretiredmhexpmm phoenix_htmlm2.14.1dnil[bWLAhhdinner_checksummhexpmmphoenixm1.5.8m qϧ7M9yB_ik\ZF!-bWLAhhddepsmhexpmmdecimalm1.1.0j+bWLAhhddepsmhexpmmranchm1.6.0j[bWLAhhdouter_checksummhexpmmphoenixm1.5.1m '+8(y̮og鷐=hx^=#1RKbWLAhhddepsmhexpmmphoenixm1.2.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm6~> 1.4 or ~> 1.3.3 or ~> 1.2.4 or ~> 1.1.8 or ~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejKbWLAhhd timestampmhexpmm phoenix_htmlm2.5.1hhba a ha aa _bWLAhhdinner_checksummhexpmm plug_cowboym2.0.2m `UhhHKncҺڔIxA3w*lbWLAhhddepsmhexpmmphoenixm1.5.7lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejbWLAhhddepsmhexpmmphoenixm1.1.6lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej%bWLAhhddepsmhexpmmphoenixm 1.2.0-rc.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm ~> 1.0.0-rcdfalsehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejGbWLAhhd timestampmhexpmmphoenixm0.12.0hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm0.7.2m leuevoLGgұzoZbWLAhhdinner_checksummhexpmmcowboym2.3.0m &)HoAUdC(KVѐxOVbG$5bWLAhhdretiredmhexpmmphoenixm0.6.2dnil[bWLAhhdouter_checksummhexpmmphoenixm0.6.2m ATg98TA^eVAXbWLAhhdouter_checksummhexpmmmimem1.0.0m ~gG틓\Tzy,OLm}?\IbWLAhhd timestampmhexpmmranchm 2.0.0-rc.1hhba a ha aa YbWLAhhdinner_checksummhexpmmplugm1.10.0m e)\TE&7䨃4vHuM>bWLAhhdretiredmhexpmmcowboy_telemetrym0.4.0dnil:bWLAhhdretiredmhexpmm phoenix_htmlm1.2.1dnil5bWLAhhdretiredmhexpmmphoenixm1.5.9dnilGbWLAhhd timestampmhexpmmphoenixm0.16.1hhba a ha aa zbWLAhhdretiredmhexpmm plug_cowboym2.2.1tdmessagemBroken telemetry supportdreasondRETIRED_INVALIDKbWLAhhd timestampmhexpmm phoenix_htmlm2.4.0hhba a ha aa GbWLAhhd timestampmhexpmmphoenixm1.4.17hhba a ha aa bWLAhhddepsmhexpmmplugm1.12.0lhmhexpmmmimemmimem~> 1.0 or ~> 2.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4 or ~> 1.0dfalsejCbWLAhhd timestampmhexpmmplugm1.5.1hhbaahaa4aYbWLAhhdinner_checksummhexpmmjasonm1.1.0m 4/thՆS\[ WRO^bWLAhhdinner_checksummhexpmmranchm 2.0.0-rc.2m Hm4$2|;*vxQAsKbWLAhhd timestampmhexpmmphoenixm 1.3.0-rc.1hhba a ha aa EbWLAhhd timestampmhexpmmcowlibm1.1.0hhbaahaaa.+bWLAhhddepsmhexpmmranchm1.1.0j:bWLAhhdretiredmhexpmm phoenix_htmlm2.2.0dnilbWLAhhddepsmhexpmm plug_cowboym2.2.0lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej[bWLAhhdouter_checksummhexpmmphoenixm1.2.3m ̷ĨK/c?W?8%it<€2bWLAhhdretiredmhexpmmplugm1.2.0dnil,bWLAhhddepsmhexpmmphoenixm 1.3.0-rc.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.2 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej`bWLAhhdinner_checksummhexpmmphoenixm 1.4.0-rc.2m _ 4a KCGE(/gͮoYXbWLAhhdouter_checksummhexpmmplugm0.8.0m s1eL>:cv6-+JbWLAhhd timestampmhexpmm plug_cowboym2.2.1hhba a ha aa DbWLAhhd timestampmhexpmmjasonm1.2.2hhbaaha aa:`bWLAhhdouter_checksummhexpmmphoenixm 1.3.0-rc.2m ap RŸo ,nE4ns,NDIbWLAhhd timestampmhexpmmranchm 2.0.0-rc.2hhba a ha aa ,bWLAhhddepsmhexpmmpoisonm1.1.0j,bWLAhhddepsmhexpmmcowlibm2.0.0j[bWLAhhdinner_checksummhexpmmphoenixm0.2.9m (N76eVҫbnK;L}dZbWLAhhdinner_checksummhexpmmpoisonm1.0.2m M;su@Sޱ@oVa. 7@S8CbWLAhhd timestampmhexpmmplugm1.1.4hhbaahaa4a_bWLAhhdinner_checksummhexpmm plug_cryptom1.2.1m \D'RU%"_0mZM-n:bWLAhhdretiredmhexpmmphoenixm 1.5.0-rc.0dnil[bWLAhhdouter_checksummhexpmmphoenixm1.1.7m MRVA1,OO'kT)1sbWLAhhddepsmhexpmm phoenix_htmlm2.3.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejXbWLAhhdouter_checksummhexpmmplugm0.7.0m \ꬽVSOy#M96s-vyXg5bWLAhhdretiredmhexpmmphoenixm0.8.0dnil3bWLAhhdretiredmhexpmmjasonm1.1.1dnil5bWLAhhdretiredmhexpmmdecimalm1.1.0dnilEbWLAhhd timestampmhexpmmcowlibm2.9.0hhbaahaaa.[bWLAhhdouter_checksummhexpmmphoenixm1.3.0m 5̑l7O2O/]eeSlcbWLAhhddepsmhexpmmplugm1.0.0lhmhexpmmcowboymcowboym~> 1.0dtruej*bWLAhhddepsmhexpmmplugm0.5.2j/bWLAhhddepsmhexpmm telemetrym0.3.0j1bWLAhhddepsmhexpmm plug_cryptom1.2.2j[bWLAhhdinner_checksummhexpmmphoenixm1.2.0m ޹%OLSLߘ )|b]Wb|;f5bWLAhhdretiredmhexpmmdecimalm1.0.1dnilFbWLAhhd timestampmhexpmmphoenixm0.2.9hhba a ha aa TbWLAhhd registry_etagmhexpmm telemetrym""4a441cbd068ab1fc1e6f8fabddac30ff"[bWLAhhdouter_checksummhexpmmdecimalm0.1.2m Jޗ֊YJ AJ'mFbWLAhhd timestampmhexpmmphoenixm1.1.5hhba a ha aa [bWLAhhdinner_checksummhexpmmphoenixm1.1.2m kl`ٛ D3x e&Qm4|}4bWLAhhdretiredmhexpmmcowboym2.3.0dnilbWLAhhddepsmhexpmmplugm1.11.1lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejXbWLAhhdouter_checksummhexpmmplugm1.1.4m !&=zq(H#10rVƨTmݔ%MXbWLAhhdinner_checksummhexpmmplugm0.4.3m }.sD 2.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej2bWLAhhdretiredmhexpmmplugm1.6.0dnilbWLAhhddepsmhexpmmphoenixm 1.6.0-rc.0lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmm phoenix_viewm phoenix_viewm~> 1.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4 or ~> 1.0dfalsej3bWLAhhdretiredmhexpmmranchm1.3.2dnilYbWLAhhdinner_checksummhexpmmjasonm1.0.0m |#!Aw&Zqo5bWLAhhdretiredmhexpmmphoenixm0.5.0dnil[bWLAhhdinner_checksummhexpmmdecimalm1.7.0m 0ֵ,TfcsYPߞf S_~Ū2bWLAhhdretiredmhexpmmplugm1.2.3dnil,bWLAhhddepsmhexpmmcowlibm1.0.1j_bWLAhhdouter_checksummhexpmm plug_cowboym2.1.0m lѽM?G}gaSՍ@CzF2bWLAhhddepsmhexpmmcowboym2.9.0lhmhexpmmcowlibmcowlibm2.11.0dfalsehmhexpmmranchmranchm1.8.0dfalsej[bWLAhhdouter_checksummhexpmmphoenixm1.4.0m "ڏe=;;vfÉ=B%̄K`bWLAhhdouter_checksummhexpmmphoenixm 1.3.0-rc.1m v,TOƿ<~RS7=bCbWLAhhd timestampmhexpmmplugm1.8.0hhbaahaa4a>bWLAhhdretiredmhexpmmcowboy_telemetrym0.3.1dnilbWLAhhddepsmhexpmmplugm1.5.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.1dtruehmhexpmmmimemmimem~> 1.0dfalsejFbWLAhhd timestampmhexpmmphoenixm0.2.4hhba a ha aa EbWLAhhd timestampmhexpmmcowlibm2.7.3hhbaahaaa.;bWLAhhdretiredmhexpmm phoenix_htmlm2.12.0dnil[bWLAhhdouter_checksummhexpmmdecimalm1.8.1m zybWLAhhdretiredmhexpmmcowboym2.6.2tdmessagemcowlib version 2.7.2 retireddreasondRETIRED_INVALIDEbWLAhhd timestampmhexpmmcowboym2.2.0hhbaahaaa.FbWLAhhd timestampmhexpmmphoenixm0.2.3hhba a ha aa XbWLAhhdinner_checksummhexpmmplugm1.0.5m $W .:ѵȫ2RU)wJ[bWLAhhdouter_checksummhexpmmphoenixm1.3.1m e+a!= ETsyFML2hX2(4bWLAhhdretiredmhexpmmpoisonm1.3.1dnil\bWLAhhdouter_checksummhexpmmphoenixm0.13.0m 2W@ j(;["ֵ"bWLAhhddepsmhexpmmphoenixm1.4.6lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruej[bWLAhhdouter_checksummhexpmmphoenixm0.2.5m ~sؒv `1 l,h˕PybѶ1[bWLAhhdinner_checksummhexpmmphoenixm0.2.0m lE$ KMb™ua@Eh4[bWLAhhdinner_checksummhexpmmdecimalm1.6.0m Mn]CpӔ42_Ӻp0Y ebWLAhhddepsmhexpmmplugm0.8.1lhmhexpmmcowboymcowboym~> 1.0.0dtruejZbWLAhhdinner_checksummhexpmmpoisonm2.0.1m $6Ѷ~UkRI QsbWLAhhddepsmhexpmm plug_cowboym1.0.0lhmhexpmmcowboymcowboym~> 1.0dfalsehmhexpmmplugmplugm~> 1.7dfalsej7bWLAhhdretiredmhexpmmplugm 1.5.0-rc.0dnil9bWLAhhdretiredmhexpmm plug_cryptom1.2.0dnilXbWLAhhdinner_checksummhexpmmplugm1.6.1m /b=P Ϙ Fi~)4XnlabWLAhhdouter_checksummhexpmm phoenix_htmlm2.13.1m BϩNޖ3@ٜ4]Om鲳Bdǡd"bWLAhhddepsmhexpmmphoenixm1.4.2lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejIbWLAhhd timestampmhexpmmjasonm 1.0.0-rc.3hhbaaha aa:dbWLAhhdouter_checksummhexpmm phoenix_htmlm 2.4.0-devm 0a/@/։ꠦ=;Aj_bWLAhhdinner_checksummhexpmm plug_cowboym1.0.0m .*}4 tm3_EX0=h' nzDbWLAhhd timestampmhexpmmplugm1.11.0hhbaahaa4aDbWLAhhd timestampmhexpmmranchm2.0.0hhba a ha aa  bWLAhhddepsmhexpmmphoenixm0.5.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmlinguistmlinguistm~> 0.1.2dfalsehmhexpmmplugmplugm~> 0.8.1dfalsehmhexpmmpoisonmpoisonm~> 1.1dfalsejFbWLAhhd timestampmhexpmmdecimalm0.2.2hhbaaha aa:FbWLAhhd timestampmhexpmmphoenixm0.3.1hhba a ha aa `bWLAhhdinner_checksummhexpmmphoenixm 1.3.0-rc.0m Ni!{19n}o⾊шùGDbWLAhhd timestampmhexpmmplugm0.11.3hhbaahaa4aFbWLAhhd timestampmhexpmmdecimalm0.1.1hhbaaha aa:'bWLAhhddepsmhexpmmphoenixm1.3.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsejbWLAhhddepsmhexpmmplugm1.10.3lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejbWLAhhddepsmhexpmmcowboym2.2.1lhmhexpmmcowlibmcowlibm~> 2.1.0dfalsehmhexpmmranchmranchm~> 1.4.0dfalsejXbWLAhhdouter_checksummhexpmmplugm1.6.2m q<W&a +UlALu{\bWLAhhdinner_checksummhexpmmphoenixm0.10.0m ,~33gaTyV0A*IX+bWLAhhddepsmhexpmmranchm1.6.1j:bWLAhhdretiredmhexpmm phoenix_htmlm2.5.0dnilEbWLAhhd timestampmhexpmmpoisonm1.2.1hhba a ha a.aCbWLAhhd timestampmhexpmmplugm1.4.5hhbaahaa4a_bWLAhhdouter_checksummhexpmm plug_cowboym2.1.1m O W[9DXm}rLs}6bWLAhhdretiredmhexpmmphoenixm0.15.0dnilFbWLAhhd timestampmhexpmmphoenixm0.7.2hhba a ha aa 2bWLAhhdretiredmhexpmmplugm0.8.4dnil7bWLAhhdretiredmhexpmm telemetrym0.1.0dnilCbWLAhhd timestampmhexpmmplugm1.6.2hhbaahaa4a[bWLAhhdouter_checksummhexpmmphoenixm1.4.3m ܨwg*Khb+l0Bňi1X`bWLAhhdouter_checksummhexpmmphoenixm 1.5.0-rc.0m 7}ʋNEBt_y e%gfXbWLAhhdinner_checksummhexpmmmimem1.4.0m PfIDp(aF}/sQ̨/H5і|GXbWLAhhdouter_checksummhexpmmplugm0.9.0m '&PrUv1}V$K8MzTJ bWLAhhddepsmhexpmmphoenixm1.0.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejdbWLAhhdouter_checksummhexpmm phoenix_htmlm 2.7.0-devm OhnV.m%VH;Dyd Z[bWLAhhdouter_checksummhexpmmphoenixm1.5.9m ~K |/ ] 4gyWJuB}FbWLAhhd timestampmhexpmmphoenixm1.4.8hhba a ha aa `bWLAhhdouter_checksummhexpmmphoenixm 1.2.0-rc.1m _ʨul! ifʂA,5bWLAhhdretiredmhexpmmdecimalm1.6.0dnilCbWLAhhd timestampmhexpmmplugm0.4.1hhbaahaa4aDbWLAhhd timestampmhexpmmranchm1.7.1hhba a ha aa jbWLAhhddepsmhexpmmphoenixm1.4.14lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejYbWLAhhdouter_checksummhexpmmplugm1.10.4m #?=.Vaeh`w{g1H-NwQbWLAhhd registry_etagmhexpmmcowlibm""02967331d4715db91bfad19c64a3a0fa"3bWLAhhdretiredmhexpmmplugm1.10.2dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.9.0m ŔEtYLjU yL{D+FbWLAhhd timestampmhexpmmphoenixm1.1.6hhba a ha aa [bWLAhhdinner_checksummhexpmmdecimalm1.1.1m [g1ͬoyo(]nVnv4bWLAhhdretiredmhexpmmcowboym2.5.0dnilZbWLAhhdouter_checksummhexpmmcowlibm2.2.1m 1NdEf8K2kRh-bWLAhhddepsmhexpmmdecimalm0.2.5jabWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.4m vٙ84*F"\h402i gKbWLAhhd timestampmhexpmmphoenixm 1.4.0-rc.3hhba a ha aa ]bWLAhhdouter_checksummhexpmm telemetrym0.4.1m G88.6]g`,V m)ތXHDbWLAhhd timestampmhexpmmplugm0.12.0hhbaahaa4aXbWLAhhdouter_checksummhexpmmplugm1.2.4m @<*< 0!Ǝ +D(;P}wbWLAhhddepsmhexpmm phoenix_htmlm1.0.1lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsejHbWLAhhd timestampmhexpmmplugm 1.5.0-rc.1hhbaahaa4aXbWLAhhdouter_checksummhexpmmplugm1.1.7m ֵePvEb}DزVAZbWLAhhdouter_checksummhexpmmpoisonm5.0.0m a bYO9Bn7bWLAhhdretiredmhexpmm telemetrym0.4.0dnil[bWLAhhdinner_checksummhexpmmphoenixm1.5.6m ʹC$+ArAhufFbWLAhhd timestampmhexpmmphoenixm1.0.0hhba a ha aa KbWLAhhd timestampmhexpmm phoenix_htmlm3.0.3hhba a ha aa `bWLAhhdouter_checksummhexpmmphoenixm 1.4.0-rc.3m SJjJDv.8[˭FOn>35[bWLAhhdinner_checksummhexpmmphoenixm1.4.2m :P e; T4iMbWLAhhddepsmhexpmmphoenixm0.7.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 0.9.0dfalsehmhexpmmpoisonmpoisonm~> 1.2dfalsej[bWLAhhdinner_checksummhexpmmphoenixm0.2.2m "r4|2_IijJPtT fBabWLAhhdouter_checksummhexpmm phoenix_htmlm2.14.3m ֗ZkCۈGˣS}_[bWLAhhdinner_checksummhexpmmphoenixm1.0.2m ] 2EmUah⽶GzC2fPbWLAhhd registry_etagmhexpmmjasonm""c7ccb0b0d3701498a0a717862ef103b1"[bWLAhhdouter_checksummhexpmmdecimalm1.1.2m zmM8׸8P"H|h=3Q㦑2bWLAhhdretiredmhexpmmplugm1.6.1dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.1dnilbWLAhhdretiredmhexpmmcowboy_telemetrym0.1.0dnilbWLAhhddepsmhexpmmphoenixm1.1.8lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejKbWLAhhd timestampmhexpmm phoenix_htmlm2.1.1hhba a ha aa dbWLAhhdouter_checksummhexpmm phoenix_htmlm 2.0.0-devm 0WyʀZPlϠG!ȪbWLAhhddepsmhexpmmplugm1.3.6lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejbWLAhhdretiredmhexpmmcowlibm2.7.1tdmessagem+Published with invalid version in .app filedreasondRETIRED_INVALIDkbWLAhhddepsmhexpmmjasonm 1.0.0-rc.3lhmhexpmmdecimalmdecimalm~> 1.0dtruej]bWLAhhdouter_checksummhexpmm telemetrym0.4.3m r6_֊b %&˂^T$DvA;bWLAhhdretiredmhexpmm phoenix_htmlm2.11.2dnil7bWLAhhdretiredmhexpmm telemetrym0.3.0dnil]bWLAhhdouter_checksummhexpmmplugm 1.4.0-rc.0m \u6q ]v8' ln*AM}~\bWLAhhdouter_checksummhexpmmphoenixm1.5.10m ꥨZA&ƪo>3 Z}YbWLAhhdouter_checksummhexpmmranchm1.1.0m 9>eg][ŽS?`@WHXbWLAhhdinner_checksummhexpmmplugm0.4.1m S?P>UjWz cc "KbWLAhhd timestampmhexpmm phoenix_htmlm1.0.0hhba a ha aa ^bWLAhhdinner_checksummhexpmmjasonm 1.0.0-rc.3m RHr `D>PŕQOˣfƔ~FbWLAhhd timestampmhexpmmdecimalm1.3.0hhbaaha aa:2bWLAhhdretiredmhexpmmplugm1.6.3dnil[bWLAhhdouter_checksummhexpmmphoenixm1.5.5m n.3oZ7xU$N' F;[bWLAhhdouter_checksummhexpmmphoenixm0.2.2m hm1%Ũ1oLR2/(8MXco7bWLAhhdretiredmhexpmm telemetrym0.2.0dnilbbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.0.0m "FY'x@ʇa A ,W[bWLAhhdinner_checksummhexpmmphoenixm1.4.7m 弚Lu R}Zl*<awmXbWLAhhdinner_checksummhexpmmplugm1.3.3m پ$7NG sЕIί#CbWLAhhd timestampmhexpmmplugm1.3.0hhbaahaa4a_bWLAhhdinner_checksummhexpmm plug_cowboym2.1.1m (ۥUbuwK35bWLAhhdretiredmhexpmmphoenixm0.2.1dnilGbWLAhhd timestampmhexpmmphoenixm0.13.0hhba a ha aa 6bWLAhhdretiredmhexpmmphoenixm0.2.10dnil2bWLAhhdretiredmhexpmmmimem1.3.1dnil[bWLAhhdouter_checksummhexpmmphoenixm1.1.2m dƼmd/(VYZ#D/bWLAhhddepsmhexpmm telemetrym0.4.2j`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.1.2m gKHuE?zDFx9 7to6DbWLAhhd timestampmhexpmmranchm1.6.0hhba a ha aa ibWLAhhddepsmhexpmm phoenix_htmlm2.13.1lhmhexpmmplugmplugm~> 1.5dfalsej-bWLAhhddepsmhexpmmdecimalm1.7.0jXbWLAhhdinner_checksummhexpmmmimem1.1.0m =ǸFQ9b4;( ;bWLAhhdretiredmhexpmm phoenix_htmlm2.14.0dnil4bWLAhhdretiredmhexpmmcowboym2.0.0dnilZbWLAhhdouter_checksummhexpmmcowlibm1.2.0m IeBa:%(]ʆ=MgI=[bWLAhhdouter_checksummhexpmmphoenixm1.0.4m Y_:oTIj- {O5&foi3bWLAhhdretiredmhexpmmranchm1.3.1dnilcbWLAhhddepsmhexpmmplugm1.0.1lhmhexpmmcowboymcowboym~> 1.0dtruejLbWLAhhd timestampmhexpmm phoenix_htmlm2.13.4hhba a ha aa JbWLAhhd timestampmhexpmm plug_cryptom1.2.2hhbaahaaa.DbWLAhhd timestampmhexpmmranchm1.4.0hhba a ha aa jbWLAhhddepsmhexpmmphoenixm1.4.10lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejEbWLAhhd timestampmhexpmmpoisonm3.0.0hhba a ha a.abWLAhhddepsmhexpmm plug_cowboym2.1.2lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsej[bWLAhhdinner_checksummhexpmmphoenixm1.2.3m ֧>8YwDXIHHbWLAhhd timestampmhexpmm telemetrym1.0.0hhbaahaa4a7bWLAhhdretiredmhexpmmplugm 1.5.0-rc.1dnilFbWLAhhd timestampmhexpmmphoenixm1.2.4hhba a ha aa CbWLAhhd timestampmhexpmmmimem2.0.1hhbaahaaa.2bWLAhhdretiredmhexpmmplugm0.8.1dnilXbWLAhhdouter_checksummhexpmmmimem1.1.0m 3 ګVh\ã8)'( _M[bWLAhhdouter_checksummhexpmmphoenixm1.2.2m vLJUԾ=er*bWLAhhdretiredmhexpmmcowboy_telemetrym0.3.0dnilXbWLAhhdinner_checksummhexpmmplugm1.2.3m P W8r^ @&sS3,UsYbWLAhhdinner_checksummhexpmmjasonm1.2.0m 4-$!-?]HCv 8yY8HFbWLAhhd timestampmhexpmmdecimalm1.8.1hhbaaha aa:CbWLAhhd timestampmhexpmmplugm1.4.4hhbaahaa4aEbWLAhhd timestampmhexpmmpoisonm4.0.1hhba a ha a.aFbWLAhhd timestampmhexpmmphoenixm0.2.1hhba a ha aa 5bWLAhhdretiredmhexpmmphoenixm1.5.0dnil[bWLAhhdouter_checksummhexpmmdecimalm1.4.0m vqN/q5 :=8K-zEFq#/bWLAhhddepsmhexpmm telemetrym0.4.1jCbWLAhhd timestampmhexpmmplugm1.3.6hhbaahaa4aibWLAhhddepsmhexpmm phoenix_htmlm2.13.2lhmhexpmmplugmplugm~> 1.5dfalsej bWLAhhddepsmhexpmmphoenixm0.6.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmlinguistmlinguistm~> 0.1.4dfalsehmhexpmmplugmplugm~> 0.8.4dfalsehmhexpmmpoisonmpoisonm~> 1.2dfalsej4bWLAhhdretiredmhexpmmpoisonm2.0.1dnilXbWLAhhdouter_checksummhexpmmplugm1.3.4m bˠ*^MujXR:]bWLAhhdouter_checksummhexpmm telemetrym1.0.0m s Y(NF$3U(~ɮvng8PzZbWLAhhdouter_checksummhexpmmcowboym2.7.0m j9ƪa#a*:R{pgHbWLAhhd timestampmhexpmm telemetrym0.4.3hhbaahaa4a0bWLAhhddepsmhexpmmranchm 2.0.0-rc.1jXbWLAhhdinner_checksummhexpmmplugm1.4.5m {sS&,^ ]$ '=KbWLAhhd timestampmhexpmm phoenix_htmlm2.6.1hhba a ha aa bWLAhhddepsmhexpmm plug_cowboym2.1.3lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsejCbWLAhhd timestampmhexpmmplugm0.8.1hhbaahaa4a2bWLAhhdretiredmhexpmmmimem1.0.0dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.2.0m Aگ^˸L^9sgSX9HX[bWLAhhdinner_checksummhexpmmphoenixm0.2.1m e/4QDU(R=7qPDdJ zk5bWLAhhdretiredmhexpmmphoenixm1.3.4dnilbWLAhhddepsmhexpmmphoenixm0.2.11lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.4dfalsehmhexpmmjazzmjazzm0.1.2dfalsehmhexpmmplugmplugm0.5.1dfalsej3bWLAhhdretiredmhexpmmplugm1.11.1dnilYbWLAhhdinner_checksummhexpmmjasonm1.1.2m =g#&LqTVM=!dbWLAhhddepsmhexpmmphoenixm0.2.2lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.0dfalsehmhexpmmplugmplugm0.4.2dfalsej`bWLAhhdinner_checksummhexpmmphoenixm 1.4.0-rc.1m rZsVAE fKjtFbWLAhhd timestampmhexpmmphoenixm1.2.1hhba a ha aa /bWLAhhddepsmhexpmm telemetrym0.4.3j;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.5dnilZbWLAhhdinner_checksummhexpmmcowlibm2.0.1m M^pt ZSڂ8FbWLAhhd timestampmhexpmmdecimalm0.2.1hhbaaha aa:2bWLAhhdretiredmhexpmmplugm1.4.1dnilXbWLAhhdouter_checksummhexpmmplugm1.1.0m iijK'%.? -ޙ/قKEbWLAhhd timestampmhexpmmpoisonm2.0.1hhba a ha a.abWLAhhddepsmhexpmmphoenixm0.3.0lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.4dfalsehmhexpmmjazzmjazzm0.1.2dfalsehmhexpmmplugmplugm0.5.1dfalsej4bWLAhhdretiredmhexpmmpoisonm1.1.0dnilFbWLAhhd timestampmhexpmmdecimalm1.9.0hhbaaha aa:XbWLAhhdinner_checksummhexpmmplugm1.4.1m .g} 1.0dtruehmhexpmmlinguistmlinguistm~> 0.1.3dfalsehmhexpmmplugmplugm~> 0.8.2dfalsehmhexpmmpoisonmpoisonm~> 1.2dfalsej[bWLAhhdouter_checksummhexpmmdecimalm0.2.2m 䑳ƑfZz hӨuR?/ ,.7}.KbWLAhhd timestampmhexpmm phoenix_htmlm2.3.1hhba a ha aa 5bWLAhhdretiredmhexpmmdecimalm1.2.0dnil-bWLAhhddepsmhexpmmdecimalm0.2.1j,bWLAhhddepsmhexpmmcowlibm2.9.1j[bWLAhhd registry_etagmhexpmmcowboy_telemetrym""fa0b78215ec75029c429f147ec08d767"XbWLAhhdinner_checksummhexpmmplugm1.1.5m VEpAZrS!'Z˒7Bn'_bWLAhhdouter_checksummhexpmm plug_cryptom1.1.1m &Mo A i>bWLAhhdretiredmhexpmm phoenix_htmlm 2.4.0-devdnilKbWLAhhd timestampmhexpmm phoenix_htmlm2.2.0hhba a ha aa ZbWLAhhdouter_checksummhexpmmcowboym2.4.0m ]wYG09uf++]AJbWLAhhddepsmhexpmmphoenixm0.2.1lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmplugmplugm0.4.2dfalsejXbWLAhhdinner_checksummhexpmmmimem1.2.0m x+6 ӴQ@уֈ[ 4_bWLAhhdinner_checksummhexpmm plug_cowboym2.0.1m טZ̆-DPf\#nQ2AzbWLAhhddepsmhexpmmplugm1.4.3lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej\bWLAhhdinner_checksummhexpmmphoenixm1.5.11m `՗J1O:ɰ6FΚG`y 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.0.0m Eg^-"t"ޟR ʻu;ɒXw\(abWLAhhdinner_checksummhexpmm phoenix_htmlm2.13.4m =nFd$JI' P*}mء[OWLAhhdouter_checksummhexpmmphoenixm1.1.6m %Gd1D p4~ M_$#5* )4XbWLAhhdouter_checksummhexpmmplugm1.2.2m ^Dl]R&~,23~YbWLAhhdouter_checksummhexpmmjasonm1.1.1m cEϬ2^4gry:42•%#LCbWLAhhd timestampmhexpmmplugm1.1.3hhbaahaa4aZbWLAhhdinner_checksummhexpmmpoisonm1.3.1m ]B߂^.>)jJ[/2}L0RbWLAhhd registry_etagmhexpmmdecimalm""4657f6f92e3c01945c9c9b06b6fd850e"ZbWLAhhdouter_checksummhexpmmcowlibm2.9.0m ;? B-ⵂ'[_헏zL,bWLAhhddepsmhexpmmcowlibm2.5.1jZbWLAhhdouter_checksummhexpmmcowlibm2.5.0m Ivs`ZjNP" N\bWLAhhdinner_checksummhexpmmphoenixm0.13.0m FN6"K]m/6Mݛ%;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.4dnilYbWLAhhdouter_checksummhexpmmplugm1.10.1m R%1EII*,abWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.2m u"cLoМ ֭r*1,bWLAhhddepsmhexpmmpoisonm4.0.1jYbWLAhhdinner_checksummhexpmmranchm1.4.0m '/y4wK r]lٔkXbWLAhhdinner_checksummhexpmmplugm0.5.1m X)],{/xL5_RxP)2bWLAhhdretiredmhexpmmplugm0.4.3dnilZbWLAhhdouter_checksummhexpmmpoisonm1.2.1m {hhb4>B`4.#FbWLAhhd timestampmhexpmmdecimalm2.0.0hhbaaha aa:3bWLAhhdretiredmhexpmmjasonm1.2.1dnil[bWLAhhdouter_checksummhexpmmphoenixm1.0.0m s/L!p_1iRV䒥WbWLAhhddepsmhexpmmcowboym2.6.3lhmhexpmmcowlibmcowlibm~> 2.7.3dfalsehmhexpmmranchmranchm~> 1.7.1dfalsejEbWLAhhd timestampmhexpmmcowboym1.0.1hhbaahaaa.XbWLAhhdouter_checksummhexpmmplugm0.5.2m }8gD'CviD@ӋVSXbWLAhhdouter_checksummhexpmmplugm0.4.4m 1-W3SXd#_Y:[bWLAhhdouter_checksummhexpmmphoenixm1.5.8m 5У/H6z;.I!%C2UZbWLAhhdinner_checksummhexpmmpoisonm1.2.1m P$:er ts IZbWLAhhdinner_checksummhexpmmcowboym1.0.2m j/c[ai@,?H37_bWLAhhdinner_checksummhexpmm plug_cowboym2.3.0m P\<Pj7WP2f#ݩ]bWLAhhdinner_checksummhexpmmplugm 1.5.0-rc.1m r>%f-k,\a$B/9&fbWLAhhddepsmhexpmmjasonm1.1.0lhmhexpmmdecimalmdecimalm~> 1.0dtruej6bWLAhhdretiredmhexpmmphoenixm1.4.12dnilZbWLAhhdouter_checksummhexpmmcowlibm2.0.1m t\"gu"!qdr 2bWLAhhdretiredmhexpmmplugm1.1.4dnil[bWLAhhdouter_checksummhexpmmdecimalm1.9.0m 45h֒>u[] o}XbWLAhhdinner_checksummhexpmmplugm1.9.0m |N&"3Gs$Ë{F}Y$:ZJZbWLAhhdouter_checksummhexpmmcowlibm2.5.1m 4¶:k@UD%,S]EbWLAhhd timestampmhexpmmcowboym1.1.2hhbaahaaa.bWLAhhddepsmhexpmmplugm1.9.0lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruejZbWLAhhdouter_checksummhexpmmcowlibm1.0.2m b-:96jŚ)7'D`bWLAhhdouter_checksummhexpmmphoenixm 1.2.0-rc.0m ߒҏ&=b Oֵ> #iZn`ZSakPCbWLAhhd timestampmhexpmmmimem1.0.0hhbaahaaa.ZbWLAhhdinner_checksummhexpmmcowboym2.8.0m bW٬Pta˜@SɥW{׼f}XbWLAhhdouter_checksummhexpmmplugm1.4.5m (k4oA뽰ĸ^CbWLAhhd timestampmhexpmmplugm1.7.1hhbaahaa4axx*K9YΫK8uFbWLAhhd timestampmhexpmmdecimalm1.4.1hhbaaha aa:4bWLAhhdretiredmhexpmmpoisonm2.1.0dnil,bWLAhhddepsmhexpmmcowlibm2.3.0j6bWLAhhdretiredmhexpmmphoenixm0.16.0dnil]bWLAhhdinner_checksummhexpmm telemetrym0.3.0m <Gqc <"f" :*:jguJs5bWLAhhdretiredmhexpmmdecimalm1.4.0dnilabWLAhhdouter_checksummhexpmm phoenix_htmlm2.11.0m 6h+2INp#9:@7}~Ne h_)IbWLAhhd timestampmhexpmmjasonm 1.0.0-rc.1hhbaaha aa:5bWLAhhdretiredmhexpmmphoenixm1.5.5dnilKbWLAhhd timestampmhexpmm phoenix_htmlm1.1.0hhba a ha aa \bWLAhhdouter_checksummhexpmmphoenixm1.4.14m IX%G{eeq [v+XTEbWLAhhd timestampmhexpmmpoisonm1.1.1hhba a ha a.aZbWLAhhdouter_checksummhexpmmpoisonm2.0.0m \um'A ߫' إCqjbWLAhhddepsmhexpmmphoenixm1.4.15lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej,bWLAhhddepsmhexpmmpoisonm1.3.0j[bWLAhhdinner_checksummhexpmmphoenixm0.2.6m '1C &Sno1lmbu Q^IXbWLAhhdinner_checksummhexpmmplugm1.2.2m Ͻ!L?퍏K͛3bWLAhhdretiredmhexpmmjasonm1.0.1dnilLbWLAhhd timestampmhexpmm phoenix_htmlm2.10.4hhba a ha aa bWLAhhddepsmhexpmmphoenixm0.8.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 0.9.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej3bWLAhhdretiredmhexpmmplugm0.11.3dnildbWLAhhdouter_checksummhexpmmcowboy_telemetrym0.4.0m }Eeb՟#5j˸819tJbWLAhhd timestampmhexpmm plug_cowboym2.0.2hhba a ha aa YbWLAhhdinner_checksummhexpmmjasonm1.0.1m d6K<p3T]s.g[bWLAhhdinner_checksummhexpmmdecimalm2.0.0m LlWCG/By+VB֗,bWLAhhddepsmhexpmmpoisonm1.1.1j:bWLAhhdretiredmhexpmm phoenix_htmlm2.7.0dnil4bWLAhhddepsmhexpmmphoenix_pubsubm2.0.0j2bWLAhhdretiredmhexpmmmimem1.6.0dnilcbWLAhhddepsmhexpmmplugm1.1.0lhmhexpmmcowboymcowboym~> 1.0dtruej4bWLAhhdretiredmhexpmmcowboym2.1.0dnilJbWLAhhd timestampmhexpmm plug_cowboym2.2.0hhba a ha aa CbWLAhhd timestampmhexpmmplugm0.5.3hhbaahaa4aFbWLAhhd timestampmhexpmmdecimalm1.8.0hhbaaha aa:CbWLAhhd timestampmhexpmmplugm1.2.5hhbaahaa4aabWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.2m IclL^>5,uaB1?*GbWLAhhd timestampmhexpmmphoenixm1.4.11hhba a ha aa HbWLAhhd timestampmhexpmm telemetrym0.1.0hhbaahaa4a`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.1.0m tD/}"/Gv"{>_vP]1YbWLAhhdouter_checksummhexpmmplugm0.12.0m LeEo448W }L<NJEbWLAhhd timestampmhexpmmcowlibm2.0.1hhbaahaaa.5bWLAhhdretiredmhexpmmdecimalm1.7.0dnil_bWLAhhdinner_checksummhexpmm plug_cryptom1.0.0m 4?$b')ԥ- }M+bWLAhhddepsmhexpmmranchm1.0.0jbbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.1.2m Il0;.n[::75KM*Z>EbWLAhhd timestampmhexpmmpoisonm2.1.0hhba a ha a.a[bWLAhhdinner_checksummhexpmmdecimalm1.0.0m 4") h_S)3rm"K^GbWLAhhd timestampmhexpmmphoenixm0.2.10hhba a ha aa 3bWLAhhdretiredmhexpmmplugm0.11.1dnil4bWLAhhdretiredmhexpmmcowboym1.0.1dnil:bWLAhhdretiredmhexpmmphoenixm 1.6.0-rc.0dnil\bWLAhhdinner_checksummhexpmmphoenixm0.15.0m JRlá=z^J@"!KibWLAhhddepsmhexpmm phoenix_htmlm2.14.1lhmhexpmmplugmplugm~> 1.5dfalsejZbWLAhhdinner_checksummhexpmmcowlibm2.3.0m Վ7NO|.jNdL6bWLAhhdretiredmhexpmmphoenixm0.11.0dnil\bWLAhhdouter_checksummhexpmmphoenixm1.4.13m vZہbl{_QYb`tRv}"bWLAhhddepsmhexpmmphoenixm1.4.3lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejFbWLAhhd timestampmhexpmmdecimalm0.2.4hhbaaha aa:bWLAhhddepsmhexpmmphoenixm1.5.1lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej9bWLAhhdretiredmhexpmm plug_cowboym2.4.0dnilYbWLAhhdinner_checksummhexpmmplugm0.11.0m ΰ`P&o@dS5,bWLAhhddepsmhexpmmpoisonm3.0.0jbWLAhhdversionsmhexpmmranchlm1.0.0m1.1.0m1.2.0m1.2.1m1.3.0m1.3.1m1.3.2m1.4.0m1.5.0m1.6.0m1.6.1m1.6.2m1.7.0m1.7.1m1.8.0m 2.0.0-rc.1m 2.0.0-rc.2m2.0.0m2.1.0jbWLAhhddepsmhexpmmphoenixm1.5.8lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejObWLAhhd timestampmhexpmmcowboy_telemetrym0.3.1hhbaahaaaObWLAhhd timestampmhexpmmcowboy_telemetrym0.3.0hhbaahaaa\bWLAhhdinner_checksummhexpmmphoenixm1.4.13m g'֛QqT`OJ?a46V9bWLAhhdretiredmhexpmm plug_cryptom1.2.2dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm3.0.2m q}_!"^d*0bWLAhhddepsmhexpmm plug_cowboym2.2.1lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej:bWLAhhdretiredmhexpmmdecimalm 2.0.0-rc.0dnilCbWLAhhd timestampmhexpmmplugm1.4.1hhbaahaa4a[bWLAhhdinner_checksummhexpmmphoenixm1.5.4m ʜ`Ic _%[ g~p?`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.1.1m *Zbu6n4"0A(uTW705bWLAhhdretiredmhexpmmphoenixm1.4.2dnil4bWLAhhdretiredmhexpmmcowboym1.0.0dnil bWLAhhddepsmhexpmmphoenixm0.4.0lhmhexpmmcowboymcowboym~> 1.0.0dtruehmhexpmmlinguistmlinguistm~> 0.1.2dfalsehmhexpmmplugmplugm0.7.0dfalsehmhexpmmpoisonmpoisonm~> 1.0.1dfalsej4bWLAhhddepsmhexpmmphoenix_pubsubm1.1.0jObWLAhhd timestampmhexpmmcowboy_telemetrym0.2.0hhbaahaaa2bWLAhhdretiredmhexpmmplugm1.8.0dnilcbWLAhhddepsmhexpmmplugm1.0.3lhmhexpmmcowboymcowboym~> 1.0dtruej`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.3.1m ?in`"yԡ_n}fo0-B_bWLAhhdinner_checksummhexpmm plug_cryptom1.1.0m HCՐbOH%oGU]ɇT.bWLAhhddepsmhexpmm plug_cowboym2.2.2lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejYbWLAhhdouter_checksummhexpmmranchm1.2.0m Qzע- ɱOÙGbWLAhhd timestampmhexpmmphoenixm0.16.0hhba a ha aa [bWLAhhdinner_checksummhexpmmdecimalm1.4.0m eqjSӦEf(Ze.J3JbWLAhhd timestampmhexpmm plug_cryptom1.2.0hhbaahaaa.[bWLAhhdouter_checksummhexpmmphoenixm0.2.4m 1=Trū9cJ q4)(8}`bWLAhhdouter_checksummhexpmmdecimalm 1.9.0-rc.0m fuEsW\^KE0|dX< GEbWLAhhd timestampmhexpmmcowlibm1.0.1hhbaahaaa.zbWLAhhdretiredmhexpmm plug_cowboym2.2.0tdmessagemBroken telemetry supportdreasondRETIRED_INVALID6bWLAhhdretiredmhexpmmphoenixm1.4.10dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.11.0dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.2dnil,bWLAhhddepsmhexpmmphoenixm 1.3.0-rc.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.2 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej-bWLAhhddepsmhexpmmdecimalm1.0.1j*bWLAhhddepsmhexpmmmimem2.0.0jdbWLAhhddepsmhexpmmplugm0.13.0lhmhexpmmcowboymcowboym~> 1.0dtruejXbWLAhhdouter_checksummhexpmmplugm1.6.4m iE;2 0 tH`EbWLAhhd timestampmhexpmmpoisonm1.0.0hhba a ha a.aYbWLAhhdinner_checksummhexpmmranchm1.3.0m ,U]X@]'.-v/YbWLAhhdinner_checksummhexpmmplugm1.12.0m 9kmRlE,Sh؅Ym0ZbWLAhhdouter_checksummhexpmmpoisonm1.5.2m JYܭȹ4UNdz+Gg8:f?:bWLAhhdretiredmhexpmm phoenix_htmlm2.9.1dnil_bWLAhhdinner_checksummhexpmm plug_cowboym2.0.0m r+ 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejYbWLAhhdouter_checksummhexpmmplugm0.11.0m "89fأXI?J\sT68EhGCbWLAhhd timestampmhexpmmplugm0.6.0hhbaahaa4abWLAhhddepsmhexpmmphoenixm1.1.4lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejXbWLAhhdinner_checksummhexpmmplugm1.7.1m er.t%O6N >sbWLAhhddepsmhexpmm phoenix_htmlm2.3.1lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej6bWLAhhdretiredmhexpmmphoenixm1.5.10dnil3bWLAhhdretiredmhexpmmranchm1.1.0dnil`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.7.0m h׫~~څ1m%s{q ORNw[bWLAhhdouter_checksummhexpmmphoenixm0.3.0m syeݞ 5aREx#7vK"[bWLAhhdinner_checksummhexpmmdecimalm1.2.0m F)`q(.W{Gkkh'}M dcRiK abWLAhhdouter_checksummhexpmm phoenix_htmlm2.14.1m SmR7[2A z:, _wc$_bWLAhhdouter_checksummhexpmm plug_cowboym2.4.1m !z}*[h(㩧R~P2@S2bWLAhhdretiredmhexpmmplugm1.1.0dnilabWLAhhdinner_checksummhexpmm phoenix_htmlm2.14.0m Ƽ(_Z=,XiB{eZhbWLAhhddepsmhexpmm phoenix_htmlm2.9.3lhmhexpmmplugmplugm~> 1.0dfalsejbbWLAhhdouter_checksummhexpmmphoenix_pubsubm2.0.0m -O&wKPYuCSPqXbWLAhhdinner_checksummhexpmmplugm1.2.6m a6ՀEʫz:( :$"J 1.0dtruehmhexpmmlinguistmlinguistm~> 0.1.4dfalsehmhexpmmplugmplugm~> 0.8.4dfalsehmhexpmmpoisonmpoisonm~> 1.2dfalsejXbWLAhhdinner_checksummhexpmmmimem2.0.0m ާpxxFب?fG V[bWLAhhdouter_checksummhexpmmphoenixm0.6.0m \&9&)!cigN{Ezx9[bWLAhhdinner_checksummhexpmmdecimalm0.1.2m iڠV;j\åiTYj+bWLAhhddepsmhexpmmranchm2.0.0jXbWLAhhdouter_checksummhexpmmplugm1.0.4m ,翈QEfss0Lӛ[Q[bWLAhhdouter_checksummhexpmmphoenixm1.2.0m l@CF/l,86B"D^xQ_Un\bWLAhhdinner_checksummhexpmmphoenixm1.4.14m ڭh\@WF>ˇj슶ޢBL$AN8XbWLAhhdinner_checksummhexpmmmimem0.0.1m s3ާj2Ӭeěs!>&ZbWLAhhdouter_checksummhexpmmcowboym1.0.4m jh 3SBcSLڦbWLAhhddepsmhexpmmphoenixm0.11.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm ~> 0.11.3dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.4.2dtruej2bWLAhhdretiredmhexpmmplugm1.4.5dnilObWLAhhd registry_etagmhexpmmplugm""4d85e7c2ce3c20c0441d3cb07bf25c4c"EbWLAhhd timestampmhexpmmcowlibm2.0.0hhbaahaaa.ibWLAhhddepsmhexpmm phoenix_htmlm2.10.1lhmhexpmmplugmplugm~> 1.0dfalsej>bWLAhhdretiredmhexpmm phoenix_htmlm 2.0.0-devdnilXbWLAhhdouter_checksummhexpmmplugm1.2.5m >m?ªc`p\ѥLEuEbWLAhhd timestampmhexpmmcowboym2.6.0hhbaahaaa.3bWLAhhdretiredmhexpmmplugm1.10.4dnilZbWLAhhdinner_checksummhexpmmcowboym2.1.0m i;#Ji5q0k9͡ł>RXFbWLAhhd timestampmhexpmmphoenixm1.0.2hhba a ha aa FbWLAhhd timestampmhexpmmphoenixm0.2.6hhba a ha aa 5bWLAhhdretiredmhexpmmphoenixm0.2.6dnilFbWLAhhd timestampmhexpmmphoenixm1.0.3hhba a ha aa YbWLAhhdouter_checksummhexpmmplugm0.13.0m +oĦ%W{US1o":gL_bWLAhhddepsmhexpmmphoenixm0.17.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej2bWLAhhdretiredmhexpmmplugm1.3.4dnil]bWLAhhdouter_checksummhexpmmplugm 1.5.0-rc.2m 8TUHlH̖"4jaLZbWLAhhdinner_checksummhexpmmcowlibm2.4.0m R_(zJ{kf'DpHeڎ:bWLAhhdretiredmhexpmm phoenix_htmlm1.1.0dnilbWLAhhddepsmhexpmmphoenixm1.5.12lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13 or ~> 3.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejKbWLAhhd timestampmhexpmm phoenix_htmlm3.0.2hhba a ha aa KbWLAhhd timestampmhexpmm phoenix_htmlm1.2.1hhba a ha aa CbWLAhhd timestampmhexpmmplugm0.5.1hhbaahaa4aibWLAhhddepsmhexpmmphoenixm1.4.7lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej[bWLAhhdinner_checksummhexpmmdecimalm1.9.0m 12q$,QK =M,bWLAhhddepsmhexpmmcowlibm2.1.0j*bWLAhhddepsmhexpmmplugm0.4.1jCbWLAhhd timestampmhexpmmplugm0.8.0hhbaahaa4a`bWLAhhdouter_checksummhexpmm phoenix_htmlm3.0.1m PUi]O[vkT z.::bWLAhhdretiredmhexpmm phoenix_htmlm2.1.2dnil4bWLAhhdretiredmhexpmmpoisonm1.3.0dnilIbWLAhhd timestampmhexpmmjasonm 1.0.0-rc.2hhbaaha aa:ZbWLAhhdinner_checksummhexpmmcowlibm2.9.0m esj*td ˢIKabWLAhhdinner_checksummhexpmm phoenix_htmlm2.11.2m h% 'W [ۓH]doL1f,bWLAhhddepsmhexpmmpoisonm1.5.1j`bWLAhhdinner_checksummhexpmmdecimalm 2.0.0-rc.0m ĸK%5 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruej[bWLAhhdinner_checksummhexpmmphoenixm0.6.0m wކM`H ٤>!CՖ6:bWLAhhdretiredmhexpmm phoenix_htmlm2.9.2dnilbWLAhhddepsmhexpmmphoenixm0.3.1lhmhexpmmex_confmex_confm0.1.3dfalsehmhexpmminflexminflexm0.2.4dfalsehmhexpmmjazzmjazzm0.1.2dfalsehmhexpmmplugmplugm0.5.1dfalsejKbWLAhhd timestampmhexpmm phoenix_htmlm2.7.0hhba a ha aa dbWLAhhddepsmhexpmmplugm0.11.1lhmhexpmmcowboymcowboym~> 1.0dtruej3bWLAhhdretiredmhexpmmranchm1.2.0dnil_bWLAhhdouter_checksummhexpmm plug_cowboym2.2.0m NrrlgzyGMR;(Ѯ\}[XbWLAhhdinner_checksummhexpmmplugm1.3.2m غ.,}i!YdU Uac-'bWLAhhddepsmhexpmmphoenixm1.3.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej2bWLAhhdretiredmhexpmmplugm1.1.1dnil_bWLAhhdouter_checksummhexpmm plug_cowboym2.0.0m ?IbЙ$m|/.j) ns:tXbWLAhhdouter_checksummhexpmmplugm1.8.3m K8-ĄI**w 3N'4ZbWLAhhdinner_checksummhexpmmcowboym1.0.4m $ߟ#3p:'"l穿ix;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.3dnil[bWLAhhdinner_checksummhexpmmdecimalm1.1.0m 33s/}z_ 0-g\ʁ*c>r`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.3.0m $lGT?iM*7Pq+_?;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.1dnil4bWLAhhdretiredmhexpmmcowlibm1.0.1dnil3bWLAhhdretiredmhexpmmplugm1.12.0dnil]bWLAhhdouter_checksummhexpmmplugm 1.5.0-rc.1m A^3\1=ݴGp 1.0 or ~> 2.0dtruej1bWLAhhddepsmhexpmm plug_cryptom1.2.1jbWLAhhddepsmhexpmm plug_cowboym2.0.0lhmhexpmmcowboymcowboym~> 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsej]bWLAhhdouter_checksummhexpmm telemetrym0.4.2m -j m{XRr.+#b {*DbWLAhhd timestampmhexpmmplugm0.11.2hhbaahaa4a5bWLAhhdretiredmhexpmmphoenixm1.1.9dnilCbWLAhhd timestampmhexpmmplugm0.5.0hhbaahaa4aJbWLAhhd timestampmhexpmm plug_cowboym2.0.0hhba a ha aa @bWLAhhd timestampmhexpmm plug_cowboyhhba a ha aa bWLAhhddepsmhexpmmplugm1.3.2lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej-bWLAhhddepsmhexpmmdecimalm0.2.2j[bWLAhhdinner_checksummhexpmmphoenixm1.5.7m )#:$EK _Fi=&&\bWLAhhdouter_checksummhexpmmphoenixm1.5.11m 1ê"t 6y_1ւvᴙzֺ$YbWLAhhdinner_checksummhexpmmplugm0.11.3m v;X5!6חtwI`+?WJhbWLAhhddepsmhexpmm phoenix_htmlm2.6.1lhmhexpmmplugmplugm~> 1.0dfalsejFbWLAhhd timestampmhexpmmphoenixm1.5.3hhba a ha aa `bWLAhhdinner_checksummhexpmmphoenixm 1.3.0-rc.3m 7 9 5r}F!Yj 0DZbWLAhhdinner_checksummhexpmmpoisonm1.1.1m  5?# z·8sbWLAhhddepsmhexpmm phoenix_htmlm2.1.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej+bWLAhhddepsmhexpmmranchm1.3.2j+bWLAhhddepsmhexpmmranchm1.8.0jCbWLAhhd timestampmhexpmmplugm0.4.3hhbaahaa4a[bWLAhhdinner_checksummhexpmmphoenixm1.5.5m Z~(8RMCj5Ex鴽7bWLAhhdretiredmhexpmm telemetrym0.4.3dnil_bWLAhhdouter_checksummhexpmm plug_cowboym1.0.0m BzD$eE"c2u@JabWLAhhddepsmhexpmmphoenixm1.2.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.1dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejKbWLAhhd timestampmhexpmm phoenix_htmlm2.1.2hhba a ha aa 5bWLAhhdretiredmhexpmmphoenixm1.1.1dnilKbWLAhhd timestampmhexpmmphoenixm 1.3.0-rc.3hhba a ha aa 4bWLAhhdretiredmhexpmmpoisonm1.0.3dnil`bWLAhhdouter_checksummhexpmmphoenixm 1.4.0-rc.1m t4<Q7lWHAw>bWLAhhddepsmhexpmmplugm1.2.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsejXbWLAhhdouter_checksummhexpmmmimem1.3.0m ^(`2j` Ɠݫ%y{ffS(lbWLAhhddepsmhexpmm phoenix_htmlm 2.7.0-devlhmhexpmmplugmplugm~> 1.0dfalsej[bWLAhhdinner_checksummhexpmmphoenixm0.2.8m _3uDj*EЏ%e I}=cZbWLAhhdouter_checksummhexpmmcowboym2.6.3m X)?t6.ZkZ. abWLAhhdinner_checksummhexpmm phoenix_htmlm2.11.1m wRnsd7RX͡2f&~bbWLAhhdouter_checksummhexpmmphoenix_pubsubm0.0.1m SieZc6@1oW: DbWLAhhd timestampmhexpmmjasonm1.0.0hhbaaha aa:YbWLAhhdinner_checksummhexpmmranchm1.0.0m NBewim֦{u%`3YbWLAhhdinner_checksummhexpmmplugm0.14.0m KN&ïF9VgD|Az[`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.1.1m /q?e*;155~`N*m[bWLAhhdouter_checksummhexpmmphoenixm1.1.9m 1gxف 1.0dtruejFbWLAhhd timestampmhexpmmphoenixm0.6.1hhba a ha aa ;bWLAhhdretiredmhexpmm phoenix_htmlm2.11.1dnil:bWLAhhdretiredmhexpmm phoenix_htmlm2.9.0dnil`bWLAhhdouter_checksummhexpmmdecimalm 2.0.0-rc.0m %^,>8W$d. 1.0dtruehmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejdbWLAhhddepsmhexpmmplugm0.14.0lhmhexpmmcowboymcowboym~> 1.0dtruejcbWLAhhddepsmhexpmmplugm1.1.3lhmhexpmmcowboymcowboym~> 1.0dtruej2bWLAhhdretiredmhexpmmplugm1.7.2dnilXbWLAhhdouter_checksummhexpmmplugm0.8.2m ɗg)&'(|VVԃ7 XbWLAhhdouter_checksummhexpmmplugm0.4.2m Anۅm 4 u4`bWLAhhdinner_checksummhexpmmphoenixm 1.6.0-rc.0m Xx,-"}1 t 4f?p2bWLAhhddepsmhexpmmdecimalm 2.0.0-rc.0jXbWLAhhdinner_checksummhexpmmplugm1.8.2m ڤ I9@wa\;Y t@[bWLAhhdinner_checksummhexpmmphoenixm1.5.0m YόsJ0W6eIaij ĮB`bWLAhhdouter_checksummhexpmm phoenix_htmlm3.0.2m ]RoRQy̿PCoO5bWLAhhdretiredmhexpmmphoenixm1.1.3dnilGbWLAhhd timestampmhexpmmphoenixm0.15.0hhba a ha aa XbWLAhhdouter_checksummhexpmmplugm1.5.0m ͜\c~:ɿPtovͲױΓԠ.R1bWLAhhddepsmhexpmm plug_cryptom1.0.0jYbWLAhhdinner_checksummhexpmmplugm1.10.4m AѢqSgd[գ}*?92bWLAhhdretiredmhexpmmmimem1.0.1dnilhbWLAhhddepsmhexpmm phoenix_htmlm2.9.1lhmhexpmmplugmplugm~> 1.0dfalsej2bWLAhhdretiredmhexpmmplugm0.8.0dnilZbWLAhhdinner_checksummhexpmmcowlibm2.7.3m  M_ γ}1FvL_bWLAhhdinner_checksummhexpmm plug_cryptom1.1.1m K`*BЄq'I5 FCbWLAhhd timestampmhexpmmplugm1.1.5hhbaahaa4aDbWLAhhd timestampmhexpmmjasonm1.1.2hhbaaha aa:EbWLAhhd timestampmhexpmmcowlibm2.7.1hhbaahaaa.ZbWLAhhdinner_checksummhexpmmcowboym2.2.0m R3xk;{^K| a杈vbWLAhhddepsmhexpmmcowboym2.5.0lhmhexpmmcowlibmcowlibm~> 2.6.0dfalsehmhexpmmranchmranchm~> 1.6.2dfalsejbWLAhhddepsmhexpmmplugm 1.5.0-rc.1lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.1dtruehmhexpmmmimemmimem~> 1.0dfalsej[bWLAhhdouter_checksummhexpmmphoenixm1.5.4m NQmއh.}^0\۳5[bWLAhhdinner_checksummhexpmmphoenixm1.0.0m QyՉy ecoN*[bWLAhhdouter_checksummhexpmmdecimalm1.0.0m T ! oC d0'${ՓBt,bWLAhhddepsmhexpmmcowlibm2.7.2j2bWLAhhdretiredmhexpmmplugm0.5.2dnilDbWLAhhd timestampmhexpmmplugm1.11.1hhbaahaa4a]bWLAhhdinner_checksummhexpmmplugm 1.5.0-rc.0m f!T`B sU-m(L[bWLAhhdouter_checksummhexpmmphoenixm1.1.3m Wv pwd6Bf&Ͱp`R J2bWLAhhdretiredmhexpmmplugm1.2.6dnilMbWLAhhd timestampmhexpmmphoenix_pubsubm0.1.0hhba a ha aa CbWLAhhd timestampmhexpmmplugm1.4.2hhbaahaa4a,bWLAhhddepsmhexpmmcowlibm2.5.0j0bWLAhhddepsmhexpmmranchm 2.0.0-rc.2jZbWLAhhdouter_checksummhexpmmpoisonm1.2.0m :b#%?)A@ʽĭXZbʦ[XbWLAhhdinner_checksummhexpmmplugm1.1.9m r!gкgfk8邗#3(7$s,bWLAhhddepsmhexpmmpoisonm1.0.0jEbWLAhhd timestampmhexpmmcowboym1.0.3hhbaahaaa.2bWLAhhdretiredmhexpmmplugm0.8.2dnil[bWLAhhdinner_checksummhexpmmphoenixm1.4.9m tm t3M=<ʱud5C4Ay.ft4bWLAhhdretiredmhexpmmpoisonm2.0.0dnilEbWLAhhd timestampmhexpmmcowlibm1.2.0hhbaahaaa.8bWLAhhdretiredmhexpmmranchm 2.0.0-rc.2dnildbWLAhhdouter_checksummhexpmmcowboy_telemetrym0.1.0m ٖqczPJ~|L4be3DbWLAhhd timestampmhexpmmplugm1.10.0hhbaahaa4aKbWLAhhd timestampmhexpmm phoenix_htmlm3.0.0hhba a ha aa EbWLAhhd timestampmhexpmmcowboym2.5.0hhbaahaaa.`bWLAhhdouter_checksummhexpmmphoenixm 1.6.0-rc.0m * 4M*/eJ8!v.dooIDbWLAhhd timestampmhexpmmranchm2.1.0hhba a ha aa 4bWLAhhdretiredmhexpmmcowlibm2.7.0dnilFbWLAhhd timestampmhexpmmphoenixm1.5.5hhba a ha aa `bWLAhhdouter_checksummhexpmm phoenix_htmlm1.0.1m /+P3)׾Jabʶ$§O5o[bWLAhhdouter_checksummhexpmmphoenixm0.8.0m dgz1R,GdSv*>\bWLAhhdinner_checksummhexpmmphoenixm1.5.12m u 88ji3?6CUfgbWLAhhddepsmhexpmm phoenix_htmlm3.0.2lhmhexpmmplugmplugm~> 1.5dtruejFbWLAhhd timestampmhexpmmphoenixm0.4.0hhba a ha aa cbWLAhhddepsmhexpmmplugm1.1.9lhmhexpmmcowboymcowboym~> 1.0dtruej[bWLAhhdouter_checksummhexpmmphoenixm1.5.7m wLDţx+ j {| x_bWLAhhdinner_checksummhexpmm plug_cowboym2.2.0m 1{Qp"YrA z $4bWLAhhdretiredmhexpmmcowboym2.6.3dnilbWLAhhddepsmhexpmmplugm1.2.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsejXbWLAhhdouter_checksummhexpmmplugm0.4.1m Hd,dÎY7qrwܩ:`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.0.1m wcC$f-fZ$ mK]d!8Z1xEbWLAhhd timestampmhexpmmcowboym2.9.0hhbaahaaa.[bWLAhhdinner_checksummhexpmmphoenixm1.0.4m /(L#:ߋkK2}?LJnGbWLAhhd timestampmhexpmmphoenixm1.4.12hhba a ha aa [bWLAhhdinner_checksummhexpmmphoenixm1.3.0m LJzo PgA]$>ʼn]bWLAhhdinner_checksummhexpmm telemetrym0.4.2m (ɒE^s"M;kb_#:sPXps/E>bWLAhhdretiredmhexpmm phoenix_htmlm 2.7.0-devdnilJbWLAhhd timestampmhexpmm plug_cryptom1.0.0hhbaahaaa.XbWLAhhdinner_checksummhexpmmplugm0.8.4m D?+ _gxfbS)`_NcbWLAhhddepsmhexpmmplugm1.1.1lhmhexpmmcowboymcowboym~> 1.0dtruej-bWLAhhddepsmhexpmmdecimalm1.1.1j2bWLAhhdretiredmhexpmmplugm1.5.1dnil\bWLAhhdinner_checksummhexpmmphoenixm1.4.10m aJTUb)M"7-(#4ez$(UYbWLAhhdouter_checksummhexpmmranchm1.5.0m *{iR=K[e"ɘE2PfbWLAhhddepsmhexpmmjasonm1.0.0lhmhexpmmdecimalmdecimalm~> 1.0dtruejXbWLAhhdouter_checksummhexpmmplugm1.0.0m YC1S [(R-7Vc -bWLAhhddepsmhexpmmphoenixm0.1.0j\bWLAhhdinner_checksummhexpmmphoenixm1.4.11m b÷lz>XPڧǦ K XbWLAhhdouter_checksummhexpmmplugm1.1.3m 0c倉w<\zQY/OZ~N3o3bWLAhhdretiredmhexpmmjasonm1.1.2dnilLbWLAhhd timestampmhexpmm phoenix_htmlm2.10.1hhba a ha aa fbWLAhhddepsmhexpmmjasonm1.0.1lhmhexpmmdecimalmdecimalm~> 1.0dtruejCbWLAhhd timestampmhexpmmplugm1.2.4hhbaahaa4a4bWLAhhdretiredmhexpmmcowlibm1.2.0dnilZbWLAhhdouter_checksummhexpmmcowboym2.6.2m CC^`1lhr`A{FbWLAhhd timestampmhexpmmphoenixm1.2.2hhba a ha aa XbWLAhhdouter_checksummhexpmmplugm1.3.2m jhZ84 cM^~2bWLAhhdretiredmhexpmmmimem2.0.0dnilZbWLAhhdinner_checksummhexpmmpoisonm1.5.1m ¯_7t`FkJdB ;c4sjI:bWLAhhdretiredmhexpmm phoenix_htmlm1.4.0dnil5bWLAhhdretiredmhexpmmphoenixm0.2.5dnilbWLAhhddepsmhexpmmphoenixm 1.5.0-rc.0lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.1dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejbWLAhhddepsmhexpmm plug_cowboym2.3.0lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.6.0m =cEGw=v2ztUi,bWLAhhddepsmhexpmmpoisonm1.5.2j[bWLAhhdouter_checksummhexpmmphoenixm0.9.0m ' =/ˍvVފ(tOP#ji3bWLAhhdretiredmhexpmmplugm1.12.1dnil;bWLAhhd timestampmhexpmmcowboyhhbaahaaa.YbWLAhhdouter_checksummhexpmmplugm1.10.2m xGgﳹ%p^f;ō*ؚZ;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.0dnil]bWLAhhdinner_checksummhexpmm telemetrym0.2.0m [@ʣ޳-|OUomk\7L#fw!a1w*bWLAhhddepsmhexpmmmimem1.0.0j`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.5.1m cSE\&m'BipgB_EbWLAhhd timestampmhexpmmpoisonm1.0.3hhba a ha a.aQbWLAhhd registry_etagmhexpmmpoisonm""644f196a2afe2fb023680a25490fecdd"ZbWLAhhdouter_checksummhexpmmcowboym1.1.0m t]"n){z>Wx=$ތ"w^ZbWLAhhdinner_checksummhexpmmcowboym2.6.0m 5Lj>>39mܻB#dm"bWLAhhddepsmhexpmmphoenixm1.4.4lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruej2bWLAhhdretiredmhexpmmplugm1.3.0dnil3bWLAhhdretiredmhexpmmranchm1.0.0dnilbWLAhhddepsmhexpmmplugm1.6.2lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsejZbWLAhhdinner_checksummhexpmmpoisonm1.0.1m {Uۯn)S"F[bWLAhhdouter_checksummhexpmmdecimalm1.4.1m #{RNUV]JrV&hL{ʀ_; 1.0dtruehmhexpmmpoisonmpoisonm~> 1.2dfalsej*bWLAhhddepsmhexpmmmimem1.3.1jXbWLAhhdouter_checksummhexpmmplugm1.1.6m #d):4p]mϤ\bWLAhhddepsmhexpmmcowboy_telemetrym0.3.0lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejFbWLAhhd timestampmhexpmmphoenixm1.2.0hhba a ha aa DbWLAhhd timestampmhexpmmjasonm1.2.1hhbaaha aa:bbWLAhhdinner_checksummhexpmmphoenix_pubsubm0.0.1m |ļ[kY`dF>NSKtYbWLAhhdouter_checksummhexpmmplugm1.12.0m RnCKhʙ8F;9bWLAhhdretiredmhexpmm plug_cowboym1.0.0dnilabWLAhhdinner_checksummhexpmm phoenix_htmlm2.13.2m |Έ`}+R'1OkA4WjbWLAhhddepsmhexpmmphoenixm1.4.13lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejXbWLAhhdinner_checksummhexpmmplugm1.1.7m @MMerFL/YH"[bWLAhhddepsmhexpmmcowboym2.6.0lhmhexpmmcowlibmcowlibm~> 2.7.0dfalsehmhexpmmranchmranchm~> 1.7.0dfalsejbWLAhhddepsmhexpmmplugm1.3.5lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejibWLAhhddepsmhexpmm phoenix_htmlm2.10.4lhmhexpmmplugmplugm~> 1.0dfalsejabWLAhhdinner_checksummhexpmm phoenix_htmlm2.13.0m ;^lYz ?GALV,A 5bWLAhhdretiredmhexpmmphoenixm1.0.1dnilXbWLAhhdinner_checksummhexpmmplugm1.1.4m .B n[1vMoaB+Ű.Ι[bWLAhhdouter_checksummhexpmmphoenixm1.2.1m ;f`5 nz 0.13 or ~> 1.0dfalsej5bWLAhhdretiredmhexpmmphoenixm1.1.0dnil7bWLAhhdretiredmhexpmmplugm 1.4.0-rc.0dnilFbWLAhhd timestampmhexpmmphoenixm1.2.5hhba a ha aa 5bWLAhhdretiredmhexpmmphoenixm0.6.1dnil[bWLAhhdinner_checksummhexpmmdecimalm1.8.1m ?_4( 57@)Nޅ3SoEh٬<ZbWLAhhdouter_checksummhexpmmcowboym1.0.1m  injY?Ka8'ũ9bWLAhhdretiredmhexpmm plug_cryptom1.0.0dnil,bWLAhhddepsmhexpmmpoisonm3.1.0jabWLAhhdouter_checksummhexpmm phoenix_htmlm2.13.3m ӗ1TWm%u_U7%gLbWLAhhd timestampmhexpmm phoenix_htmlm2.10.3hhba a ha aa fbWLAhhddepsmhexpmmjasonm1.2.1lhmhexpmmdecimalmdecimalm~> 1.0dtruejLbWLAhhd timestampmhexpmm phoenix_htmlm2.11.2hhba a ha aa 3bWLAhhdretiredmhexpmmranchm2.0.0dnilLbWLAhhd timestampmhexpmm phoenix_htmlm2.12.0hhba a ha aa KbWLAhhd timestampmhexpmm phoenix_htmlm2.6.0hhba a ha aa FbWLAhhd timestampmhexpmmdecimalm1.1.2hhbaaha aa:CbWLAhhd timestampmhexpmmplugm1.8.2hhbaahaa4aXbWLAhhdinner_checksummhexpmmplugm1.0.6m dpBcOfXeyu6LCelIEbWLAhhd timestampmhexpmmcowboym1.1.1hhbaahaaa.`bWLAhhdouter_checksummhexpmm phoenix_htmlm3.0.3m *eaĻ~) T~-KbWLAhhd timestampmhexpmm phoenix_htmlm1.0.1hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm1.0.6m 7.zUH}c[u뷃ܞ^6mü cbWLAhhddepsmhexpmmplugm1.0.4lhmhexpmmcowboymcowboym~> 1.0dtruejZbWLAhhdinner_checksummhexpmmcowlibm2.7.1m |[bfĘy_d{I5`FbWLAhhd timestampmhexpmmphoenixm0.5.0hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm0.2.7m :=ќxלFaG5=Z;@vB9ϕ;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.2dnilYbWLAhhdouter_checksummhexpmmplugm1.10.3m z*3jDKʻ8l s9ZbWLAhhdinner_checksummhexpmmpoisonm2.0.0m e'0kIt U&Ca6bWLAhhdretiredmhexpmmphoenixm1.4.13dnil[bWLAhhdinner_checksummhexpmmphoenixm1.0.5m E)PQ!jflW1)d5bWLAhhdretiredmhexpmmdecimalm0.1.1dnilYbWLAhhdinner_checksummhexpmmplugm0.13.0m /:.Gűw υIl4KbWLAhhddepsmhexpmmphoenixm0.13.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.5.1 or ~> 1.6dtruejKbWLAhhd timestampmhexpmmphoenixm 1.4.0-rc.2hhba a ha aa :bWLAhhd timestampmhexpmmjasonhhbaaha aa:,bWLAhhddepsmhexpmmpoisonm2.1.0j[bWLAhhdouter_checksummhexpmmcowlibm2.10.0m /- vt)u!H{*MN[bWLAhhdinner_checksummhexpmmphoenixm0.7.2m HN!3rWDvQ b{wf;[bWLAhhdouter_checksummhexpmmphoenixm1.0.5m иdm 0˨YOvo//7׬)e1 ^bWLAhhdouter_checksummhexpmmranchm 2.0.0-rc.2m gY`sC0o=Ho[;ZbWLAhhdinner_checksummhexpmmcowlibm2.5.0m bXKK%֋ IFrLbWLAhhd timestampmhexpmm phoenix_htmlm2.14.3hhba a ha aa [bWLAhhdinner_checksummhexpmmphoenixm1.1.8m %J&RG ʩB).A-6T\CbWLAhhd timestampmhexpmmmimem1.3.0hhbaahaaa.XbWLAhhdinner_checksummhexpmmplugm1.1.0m iHI Pjy=W%ZbWLAhhdouter_checksummhexpmmcowboym1.0.2m 89·,Gq[OLX?4bWLAhhddepsmhexpmmphoenix_pubsubm0.0.1jYbWLAhhdouter_checksummhexpmmjasonm1.1.0m #aJc5o( ǫh_QЄR68l5bWLAhhdretiredmhexpmmdecimalm0.2.2dnilFbWLAhhd timestampmhexpmmphoenixm0.2.8hhba a ha aa 2bWLAhhdretiredmhexpmmplugm0.6.0dnilXbWLAhhdouter_checksummhexpmmplugm1.4.4m _~AVƐ:݈x53,/Cm:T2bWLAhhdretiredmhexpmmplugm1.5.0dnilbWLAhhddepsmhexpmmphoenixm1.5.2lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejYbWLAhhdinner_checksummhexpmmranchm1.8.0m z 2{dzYLDsYz5bWLAhhdretiredmhexpmmphoenixm1.3.3dnil]bWLAhhdinner_checksummhexpmm telemetrym0.4.1m 'HHD$GjA|2w(ttR*bWLAhhddepsmhexpmmmimem1.3.0jabWLAhhdouter_checksummhexpmm phoenix_htmlm2.13.2m 4gddے*yz#$YbWLAhhdinner_checksummhexpmmplugm1.11.1m +fgSa4 oCѲ-SY9bWLAhhdretiredmhexpmm plug_cowboym2.4.1dnilXbWLAhhdouter_checksummhexpmmplugm0.4.3m &[ }yv6[A.q`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.4.0m 9܍u7| ?׮:jzcbWLAhhddepsmhexpmmplugm0.8.4lhmhexpmmcowboymcowboym~> 1.0dtruejZbWLAhhdouter_checksummhexpmmcowlibm2.1.0m }!:,KK#M)YV-fm2ZbWLAhhdouter_checksummhexpmmpoisonm1.5.0m wIO-l,2575.幜yaCbWLAhhd timestampmhexpmmmimem1.4.0hhbaahaaa.ZbWLAhhdinner_checksummhexpmmcowboym2.4.0m /ȥdZ_TtG3Ro]K bWLAhhddepsmhexpmmphoenixm1.2.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.1dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.1.0m `+&}C!kI˯E MbWLAhhd timestampmhexpmmphoenix_pubsubm1.1.1hhba a ha aa 5bWLAhhdretiredmhexpmmphoenixm1.5.8dnil[bWLAhhdinner_checksummhexpmmphoenixm1.1.1m XH.!ޜnT-cI!_aG,0 C$2bWLAhhdretiredmhexpmmplugm1.0.6dnilabWLAhhdouter_checksummhexpmm phoenix_htmlm2.12.0m y /DGP)%kmn^wbWLAhhddepsmhexpmm phoenix_htmlm1.0.0lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsejbWLAhhddepsmhexpmmcowboym1.1.0lhmhexpmmcowlibmcowlibm~> 1.0.2dfalsehmhexpmmranchmranchm~> 1.2.0dfalsejFbWLAhhd timestampmhexpmmdecimalm1.0.0hhbaaha aa:5bWLAhhdretiredmhexpmmphoenixm1.0.0dnilibWLAhhddepsmhexpmm phoenix_htmlm2.11.1lhmhexpmmplugmplugm~> 1.5dfalsejJbWLAhhd timestampmhexpmm plug_cowboym2.4.0hhba a ha aa FbWLAhhd timestampmhexpmmphoenixm1.4.3hhba a ha aa YbWLAhhdinner_checksummhexpmmranchm1.7.1m kQ s:IvFZG љȁ:bWLAhhdretiredmhexpmmphoenixm 1.4.0-rc.0dnil[bWLAhhdouter_checksummhexpmmdecimalm1.1.1m ?6"/+ 2.5dfalsehmhexpmmplugmplugm~> 1.7dfalsejFbWLAhhd timestampmhexpmmphoenixm1.1.9hhba a ha aa HbWLAhhd timestampmhexpmm telemetrym0.4.0hhbaahaa4aXbWLAhhdouter_checksummhexpmmplugm1.2.1m = ;BoƳa+]>F[bWLAhhdouter_checksummhexpmmphoenixm1.4.9m 3&oUu xOՔ_tz읰.5bWLAhhdretiredmhexpmmphoenixm0.9.0dnil-bWLAhhddepsmhexpmmdecimalm1.1.2j\bWLAhhdouter_checksummhexpmmphoenixm0.17.1m L+bP"n tߔҋۑ4bWLAhhdretiredmhexpmmpoisonm1.0.2dnilwbWLAhhddepsmhexpmm phoenix_htmlm 2.4.0-devlhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsej9bWLAhhdretiredmhexpmm plug_cowboym2.1.0dnilfbWLAhhddepsmhexpmmjasonm1.2.0lhmhexpmmdecimalmdecimalm~> 1.0dtruejbbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.1.1m ؐmQayܪ2DV'ŇVxul5bWLAhhdretiredmhexpmmphoenixm0.2.9dnilkbWLAhhddepsmhexpmmjasonm 1.0.0-rc.2lhmhexpmmdecimalmdecimalm~> 1.0dtruej[bWLAhhdinner_checksummhexpmmphoenixm0.2.3m ^v& G prY 1.5dfalsej`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.6.0m uXk_<Pׁ\}L͖{'5bWLAhhdretiredmhexpmmdecimalm1.1.2dnil3bWLAhhdretiredmhexpmmplugm0.10.0dnil2bWLAhhdretiredmhexpmmplugm1.1.2dnilbWLAhhdversionsmhexpmmcowboylm1.0.0m1.0.1m1.0.2m1.0.3m1.0.4m1.1.0m1.1.1m1.1.2m2.0.0m2.1.0m2.2.0m2.2.1m2.2.2m2.3.0m2.4.0m2.5.0m2.6.0m2.6.1m2.6.2m2.6.3m2.7.0m2.8.0m2.9.0jsbWLAhhddepsmhexpmm phoenix_htmlm2.4.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejabWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.1m ,ƭwLx@1D>Qy!¦AbWLAhhddepsmhexpmmphoenixm1.2.5lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm,~> 1.3.3 or ~> 1.2.4 or ~> 1.1.8 or ~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej5bWLAhhdretiredmhexpmmphoenixm0.6.0dnilXbWLAhhdouter_checksummhexpmmplugm1.3.0m RD5~mVQ5)_4E3-GbWLAhhd timestampmhexpmmphoenixm1.5.12hhba a ha aa XbWLAhhdouter_checksummhexpmmplugm1.4.0m p>PPSm mɆE5bWLAhhdretiredmhexpmmphoenixm0.2.4dnilCbWLAhhd timestampmhexpmmplugm1.2.3hhbaahaa4a)bWLAhhddepsmhexpmmphoenixm 1.4.0-rc.0lhmhexpmmcowboymcowboym~> 1.0 or ~> 2.3dtruehmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.6.2 or ~> 1.7dfalsej'bWLAhhddepsmhexpmmphoenixm 1.4.0-rc.2lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejDbWLAhhd timestampmhexpmmplugm0.13.0hhbaahaa4a`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.0.0m >ִZPA$<y5PτWDzi gbWLAhhddepsmhexpmm phoenix_htmlm3.0.1lhmhexpmmplugmplugm~> 1.5dtruejZbWLAhhdinner_checksummhexpmmcowlibm1.0.0m 9} fVԆ2s$ 47i֔AdbWLAhhddepsmhexpmmplugm0.12.2lhmhexpmmcowboymcowboym~> 1.0dtruejEbWLAhhd timestampmhexpmmcowlibm2.7.2hhbaahaaa.ObWLAhhd timestampmhexpmm phoenix_htmlm 2.4.0-devhhba a ha aa [bWLAhhdouter_checksummhexpmmcowlibm2.11.0m +>EeumI L\ ҫm҇XbWLAhhdouter_checksummhexpmmmimem1.2.0m MpB `UQ`\([+DbWLAhhd timestampmhexpmmplugm0.12.1hhbaahaa4a`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.2.0m tO$w^WGwLUcՌAEbWLAhhd timestampmhexpmmpoisonm1.5.1hhba a ha a.a`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.2.1m N ĪI,"sin ]}6bWLAhhdretiredmhexpmmphoenixm1.4.11dnilXbWLAhhdouter_checksummhexpmmplugm1.0.1m Lq ۖ}|e7;d[bWLAhhdinner_checksummhexpmmphoenixm1.4.5m n ? e?E 7]t,bWLAhhddepsmhexpmmcowlibm2.7.1j:bWLAhhdretiredmhexpmm phoenix_htmlm2.8.0dnil4bWLAhhdretiredmhexpmmpoisonm3.1.0dnilLbWLAhhd timestampmhexpmm phoenix_htmlm2.13.3hhba a ha aa 2bWLAhhdretiredmhexpmmplugm1.0.4dnilFbWLAhhd timestampmhexpmmdecimalm1.5.0hhbaaha aa:5bWLAhhdretiredmhexpmmphoenixm1.3.0dnilZbWLAhhdouter_checksummhexpmmpoisonm4.0.0m dxv$$q$U. ƍg'Z_bWLAhhdinner_checksummhexpmm plug_cryptom1.2.2m eEq2$G}`C@jM"tҀyMgbWLAhhddepsmhexpmm phoenix_htmlm3.0.3lhmhexpmmplugmplugm~> 1.5dtruej[bWLAhhdouter_checksummhexpmmphoenixm1.0.1m s$DeOă&x Uk4A4bWLAhhdretiredmhexpmmpoisonm4.0.1dnil[bWLAhhdinner_checksummhexpmmphoenixm1.4.8m -íIc$dQNzSXbWLAhhdouter_checksummhexpmmplugm0.8.3m L(G/1hMKKzXbWLAhhdinner_checksummhexpmmmimem2.0.1m n$2MMׇ7VDbWLAhhd timestampmhexpmmranchm1.0.0hhba a ha aa FbWLAhhd timestampmhexpmmphoenixm1.3.1hhba a ha aa DbWLAhhd timestampmhexpmmranchm1.7.0hhba a ha aa LbWLAhhd timestampmhexpmm phoenix_htmlm2.11.1hhba a ha aa \bWLAhhdouter_checksummhexpmmphoenixm1.4.17m :]z=vR_n{7cԮ\bWLAhhdinner_checksummhexpmmphoenixm0.17.1m xG.rgk.W%Y49+kY3bWLAhhdretiredmhexpmmplugm0.12.0dnilXbWLAhhdouter_checksummhexpmmplugm1.5.1m 1-]yuCSN!nj6[bWLAhhdinner_checksummhexpmmdecimalm0.2.2m b^BJ;@>ҜLz:K \bWLAhhdouter_checksummhexpmmphoenixm0.2.10m eXNil ?-_0qA $Q"KbWLAhhd timestampmhexpmm phoenix_htmlm2.6.2hhba a ha aa JbWLAhhd timestampmhexpmm plug_cowboym2.5.1hhba a ha aa JbWLAhhd timestampmhexpmm plug_cowboym2.1.2hhba a ha aa _bWLAhhdinner_checksummhexpmm plug_cowboym2.5.1m |oE>tDdAO(-hGേa,bWLAhhddepsmhexpmmphoenixm 1.3.0-rc.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.2 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsejXbWLAhhdouter_checksummhexpmmplugm1.1.8m -nOWz?~iW6F1؀,JabWLAhhdouter_checksummhexpmm phoenix_htmlm2.13.4m 򕜸'YuRRL clMZbWLAhhdouter_checksummhexpmmcowboym2.6.0m |z'b#EF2N\~ x[(2944bWLAhhdretiredmhexpmmcowboym2.2.2dnil5bWLAhhdretiredmhexpmmcowlibm2.11.0dnilYbWLAhhdouter_checksummhexpmmplugm0.13.1m P|u>p;y%N}퐉EwI FbWLAhhd timestampmhexpmmdecimalm0.1.2hhbaaha aa:DbWLAhhd timestampmhexpmmranchm1.1.0hhba a ha aa 2.2.1dfalsehmhexpmmranchmranchm~> 1.4.0dfalsej\bWLAhhdinner_checksummhexpmmphoenixm0.16.1m 6F''-apJBo1tdq:DbWLAhhd timestampmhexpmmplugm0.10.0hhbaahaa4a`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.0.0m ϲ aq|Ǿoqd$6:bWLAhhdretiredmhexpmm phoenix_htmlm1.3.0dnilEbWLAhhd timestampmhexpmmpoisonm1.2.0hhba a ha a.a`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.9.3m Z!"C$/TOx0OKLC% XX:bWLAhhdretiredmhexpmmphoenixm 1.2.0-rc.1dnil5bWLAhhdretiredmhexpmmphoenixm0.2.0dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.3dnilbWLAhhddepsmhexpmmphoenixm1.0.4lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej;bWLAhhdretiredmhexpmm phoenix_htmlm2.10.0dnilbbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.0.0m ,{?\MfVI$iqrXbWLAhhdinner_checksummhexpmmplugm1.8.1m py9pߠ~L֫X qL:3bWLAhhdretiredmhexpmmranchm1.7.0dnilXbWLAhhdouter_checksummhexpmmplugm0.5.0m CQ rU!w*q LkSצoZbWLAhhdinner_checksummhexpmmcowlibm2.7.2m 2ϑ15ͥ#BbWLAhhddepsmhexpmmplugm1.7.1lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsej5bWLAhhdretiredmhexpmmphoenixm0.7.2dnil[bWLAhhdinner_checksummhexpmmphoenixm0.4.0m *S]PoH39B;(X5uhj2bWLAhhdretiredmhexpmmmimem1.4.0dnilYbWLAhhdouter_checksummhexpmmplugm0.12.2m ncoŸ> iv,i7n|-1bWLAhhddepsmhexpmm plug_cryptom1.2.0jbWLAhhddepsmhexpmmplugm1.7.2lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsejZbWLAhhdouter_checksummhexpmmpoisonm1.1.0m 8ws@] ૢfS 3bWLAhhdretiredmhexpmmplugm0.13.1dnilZbWLAhhdinner_checksummhexpmmcowboym1.1.1m  ԃ]]=m mMJHV#n_bWLAhhdinner_checksummhexpmm plug_cowboym2.5.0m QɘG:RvLpeZbWLAhhdouter_checksummhexpmmcowlibm1.1.0m LQucIWϕ;{xׂZbWLAhhdinner_checksummhexpmmpoisonm1.5.0m `b:oF45%%8gͽWP2HKbWLAhhd timestampmhexpmm phoenix_htmlm2.3.0hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm1.3.2m Cn [N24z9Or|Ex۶bWLAhhddepsmhexpmmplugm1.3.4lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.2.0m QR«`ǭ}10R~2*NЇlv5bWLAhhdretiredmhexpmmphoenixm1.2.2dnil[bWLAhhdinner_checksummhexpmmdecimalm0.2.0m [.ٙ)b9*O^GLzb}F5bWLAhhdretiredmhexpmmphoenixm0.4.0dnilDbWLAhhd timestampmhexpmmplugm0.13.1hhbaahaa4a`bWLAhhdinner_checksummhexpmmphoenixm 1.2.0-rc.0m ?uF&ːIbJZ} |3ҋbWLAhhddepsmhexpmmplugm1.3.3lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej5bWLAhhdretiredmhexpmmphoenixm1.4.3dnilXbWLAhhdouter_checksummhexpmmplugm1.0.3m 1&|=lAM5!n_bWLAhhdouter_checksummhexpmm plug_cowboym2.2.1m ;C$F (nz b䎷#YTh ]޶:bWLAhhdretiredmhexpmm phoenix_htmlm2.9.3dnildbWLAhhdinner_checksummhexpmmcowboy_telemetrym0.4.0m 9XwM *:PWjZ !VTFbWLAhhd timestampmhexpmmphoenixm1.4.1hhba a ha aa 2bWLAhhdretiredmhexpmmplugm1.2.5dnil,bWLAhhddepsmhexpmmpoisonm1.0.2jHbWLAhhd timestampmhexpmm telemetrym0.3.0hhbaahaa4a*bWLAhhddepsmhexpmmmimem0.0.1jbWLAhhddepsmhexpmmplugm1.3.1lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejXbWLAhhdinner_checksummhexpmmplugm0.8.2m 9[-!2bA&~YezAEbWLAhhd timestampmhexpmmpoisonm3.1.0hhba a ha a.aZbWLAhhdinner_checksummhexpmmcowboym2.0.0m loVQwp(ml$5aDbWLAhhd timestampmhexpmmranchm1.3.2hhba a ha aa DbWLAhhd timestampmhexpmmjasonm1.1.0hhbaaha aa:YbWLAhhdinner_checksummhexpmmplugm0.10.0m D?K/Fr"E*ScˋXbWLAhhdouter_checksummhexpmmmimem1.6.0m 1a?!=`}(+Z[bWLAhhdouter_checksummhexpmmphoenixm1.4.1m [t=] xU&MYbWLAhhdouter_checksummhexpmmranchm1.3.2m nVI:$3:0%Fr R52bWLAhhdretiredmhexpmmmimem0.0.1dnil5bWLAhhdretiredmhexpmmphoenixm0.2.7dnil`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.5.0m rJPwO`.; Sk ۩ ]-A?4bWLAhhdretiredmhexpmmpoisonm1.5.2dnilXbWLAhhdinner_checksummhexpmmplugm0.4.2m ¤X {p&ʜKbWLAhhd timestampmhexpmm phoenix_htmlm2.0.1hhba a ha aa ZbWLAhhdinner_checksummhexpmmpoisonm1.1.0m ge xgkn]9+9t QcbWLAhhddepsmhexpmmplugm1.1.2lhmhexpmmcowboymcowboym~> 1.0dtruej,bWLAhhddepsmhexpmmcowlibm2.9.0jibWLAhhddepsmhexpmm phoenix_htmlm2.10.5lhmhexpmmplugmplugm~> 1.0dfalsej4bWLAhhdretiredmhexpmmpoisonm1.1.1dnilXbWLAhhdouter_checksummhexpmmplugm1.1.5m phq=fLKΪP4@P1cM=XbWLAhhdinner_checksummhexpmmplugm0.7.0m ;\W/ppe5ȖL{dh:bWLAhhdretiredmhexpmmphoenixm 1.4.0-rc.1dnilYbWLAhhdinner_checksummhexpmmplugm1.10.2m y4\}FTTŇd8\wZcbWLAhhddepsmhexpmmplugm1.0.5lhmhexpmmcowboymcowboym~> 1.0dtruej5bWLAhhdretiredmhexpmmdecimalm0.2.1dnilYbWLAhhdouter_checksummhexpmmplugm1.10.0m B*'g; {w[-퐏2dA^JZbWLAhhdinner_checksummhexpmmcowboym1.0.3m _lStsn~I._&TL+EbWLAhhd timestampmhexpmmcowboym1.0.2hhbaahaaa.:bWLAhhdretiredmhexpmm phoenix_htmlm1.2.0dnil[bWLAhhdouter_checksummhexpmmdecimalm1.3.1m WVHGrn\οǫ*w-bWLAhhddepsmhexpmmdecimalm0.2.0j[bWLAhhdinner_checksummhexpmmphoenixm0.2.4m Nr[+:Igʨ(4Y\]bWLAhhdinner_checksummhexpmmplugm 1.5.0-rc.2m ; _A2heu=fog%_bWLAhhdinner_checksummhexpmm plug_cowboym2.1.0m Wh<:9Բ[NŎJnj' 0 XbWLAhhdouter_checksummhexpmmplugm0.6.0m ' ]R\bWLAhhddepsmhexpmmphoenixm1.5.3lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej,bWLAhhddepsmhexpmmcowlibm1.3.0jibWLAhhddepsmhexpmm phoenix_htmlm2.13.0lhmhexpmmplugmplugm~> 1.5dfalsej+bWLAhhddepsmhexpmmranchm1.7.0jZbWLAhhdouter_checksummhexpmmcowlibm2.7.0m YRoS"oۋJg'||ުmC؎ZbWLAhhdouter_checksummhexpmmcowboym2.0.0m l| CSߟ?,=XѰM+e>VUx5bWLAhhdretiredmhexpmmphoenixm1.1.4dnil`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.9.1m pqm e=EFxenX".Hi6DX?bbWLAhhdouter_checksummhexpmmphoenix_pubsubm0.1.0m ktp\5Ikz@}9N\ҡVb9_bWLAhhdinner_checksummhexpmm plug_cryptom1.1.2m чW,mq6)%򵀡VB0'-bWLAhhddepsmhexpmmdecimalm1.4.0jEbWLAhhd timestampmhexpmmpoisonm2.0.0hhba a ha a.aYbWLAhhd registry_etagmhexpmmphoenix_pubsubm""9c40253b1ea746f7a666b077918a909f"bWLAhhddepsmhexpmmphoenixm0.2.8lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.1dfalsehmhexpmmplugmplugm0.4.4dfalsej[bWLAhhdouter_checksummhexpmmphoenixm0.2.6m xJlӐ,ϔMwYe`?>bWLAhhd timestampmhexpmm telemetryhhbaahaa4aCbWLAhhd timestampmhexpmmplugm1.1.7hhbaahaa4aibWLAhhddepsmhexpmm phoenix_htmlm2.10.2lhmhexpmmplugmplugm~> 1.0dfalsej[bWLAhhdouter_checksummhexpmmdecimalm1.2.0m t"HD2HDM_dш`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.8.0m V -*J= z%߻!FbWLAhhd timestampmhexpmmphoenixm1.4.9hhba a ha aa bWLAhhddepsmhexpmmplugm1.12.1lhmhexpmmmimemmimem~> 1.0 or ~> 2.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4.3 or ~> 1.0dfalsejdbWLAhhddepsmhexpmmplugm0.11.2lhmhexpmmcowboymcowboym~> 1.0dtruej4bWLAhhdretiredmhexpmmcowlibm2.0.1dnil+bWLAhhddepsmhexpmmranchm1.5.0jEbWLAhhd timestampmhexpmmcowlibm1.3.0hhbaahaaa.dbWLAhhdinner_checksummhexpmmcowboy_telemetrym0.2.0m ,CP!ԕu'VRa-<) 5bWLAhhdretiredmhexpmmphoenixm1.5.7dnilDbWLAhhd timestampmhexpmmranchm1.3.1hhba a ha aa JbWLAhhd timestampmhexpmm plug_cowboym1.0.0hhba a ha aa 5bWLAhhdretiredmhexpmmphoenixm1.2.1dnilYbWLAhhdinner_checksummhexpmmplugm0.11.1m +.W)yyڴ8w1q.o4&XbWLAhhdinner_checksummhexpmmplugm1.0.3m LQp\!Svx$[bWLAhhdinner_checksummhexpmmphoenixm0.6.1m 0Y 9cQ#hư(* qZbWLAhhdinner_checksummhexpmmpoisonm1.4.0m ZєW/d#WFNwy%EbWLAhhd timestampmhexpmmcowlibm2.5.1hhbaahaaa.XbWLAhhdinner_checksummhexpmmplugm0.5.3m ͢Q:ID+Y1g%8RMZbWLAhhdouter_checksummhexpmmcowlibm1.0.1m OkG L& #؏As\#SZbWLAhhdouter_checksummhexpmmcowboym2.1.0m š6h2ߊ 6r&[bWLAhhdouter_checksummhexpmmphoenixm1.4.2m Q8|YΥS*rUŨa,AB|F|kMKXFbWLAhhd timestampmhexpmmphoenixm1.1.2hhba a ha aa bWLAhhddepsmhexpmmcowboym1.0.1lhmhexpmmcowlibmcowlibm~> 1.0.0dfalsehmhexpmmranchmranchm~> 1.0dfalsejZbWLAhhdouter_checksummhexpmmpoisonm3.0.0m = /MBi'zC$氏|'!XbWLAhhdouter_checksummhexpmmplugm1.7.0m ~ƫjxXoDm* CbWLAhhd timestampmhexpmmplugm0.7.0hhbaahaa4abWLAhhddepsmhexpmmplugm1.7.0lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsej6bWLAhhdretiredmhexpmmphoenixm1.4.17dnilXbWLAhhdinner_checksummhexpmmmimem1.6.0m ڽv`ȒPV߰ MbWLAhhd timestampmhexpmmphoenix_pubsubm1.0.0hhba a ha aa 3bWLAhhdretiredmhexpmmplugm0.11.0dnilbWLAhhdversionsmhexpmm plug_cowboylm1.0.0m2.0.0m2.0.1m2.0.2m2.1.0m2.1.1m2.1.2m2.1.3m2.2.0m2.2.1m2.2.2m2.3.0m2.4.0m2.4.1m2.5.0m2.5.1m2.5.2jGbWLAhhd timestampmhexpmmphoenixm1.5.10hhba a ha aa 9bWLAhhdretiredmhexpmm plug_cowboym2.1.2dnilYbWLAhhdinner_checksummhexpmmranchm1.1.0m mی*'̨\T5XţU:{eT[EbWLAhhd timestampmhexpmmcowboym2.2.1hhbaahaaa.*bWLAhhddepsmhexpmmmimem2.0.1jgbWLAhhdinner_checksummhexpmmphoenix_pubsubm 1.0.0-rc.0m \S+@L?1+ xH\bWLAhhdinner_checksummhexpmmphoenixm0.17.0m fFznM[|q]TM8^_r,wwbWLAhhddepsmhexpmm phoenix_htmlm1.2.1lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsej4bWLAhhdretiredmhexpmmcowboym1.0.4dnil_bWLAhhdouter_checksummhexpmm plug_cowboym2.1.2m }r%ΆZ#~mopAt %k>c"pXbWLAhhdouter_checksummhexpmmplugm1.6.0m vΛ6ѝ\U^/À.HFbWLAhhd timestampmhexpmmphoenixm1.1.3hhba a ha aa 5bWLAhhdretiredmhexpmmdecimalm1.9.0dnilebWLAhhddepsmhexpmmplugm0.8.0lhmhexpmmcowboymcowboym~> 1.0.0dtruejZbWLAhhdinner_checksummhexpmmcowlibm2.1.0m 6X=C@@ >Oٗ aLXbWLAhhdouter_checksummhexpmmplugm1.6.1m s?2IC/bWLAhhdretiredmhexpmmcowlibm2.7.2tdmessagem+Published with invalid version in .app filedreasondRETIRED_INVALID4bWLAhhdretiredmhexpmmcowlibm2.0.0dnilabWLAhhdinner_checksummhexpmm phoenix_htmlm2.13.3m )/%_LToS`·к38g\bWLAhhdinner_checksummhexpmmphoenixm1.4.17m |ު}`݌"ChI@;8gbWLAhhddepsmhexpmm phoenix_htmlm3.0.0lhmhexpmmplugmplugm~> 1.5dtruej5bWLAhhdretiredmhexpmmdecimalm1.3.0dnilZbWLAhhdinner_checksummhexpmmcowboym1.1.0m cr~p:,oz"[DA44bWLAhhdretiredmhexpmmcowboym1.0.3dnil5bWLAhhdretiredmhexpmmphoenixm1.1.6dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.14.2dnilKbWLAhhd timestampmhexpmmphoenixm 1.3.0-rc.2hhba a ha aa ,bWLAhhddepsmhexpmmpoisonm1.5.0jbWLAhdversionaXbWLAhhdinner_checksummhexpmmplugm1.1.2m ~$ZVɭ\1L>m ٛHE ZbWLAhhdinner_checksummhexpmmpoisonm5.0.0m ҵEAW.Ww$F:TKn טU;$JbWLAhhd timestampmhexpmm plug_cryptom1.2.1hhbaahaaa.bWLAhhddepsmhexpmmphoenixm0.16.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 0.14 or ~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej]bWLAhhdinner_checksummhexpmm telemetrym1.0.0m E:,$7T 0R5bWLAhhdretiredmhexpmmphoenixm1.5.3dnil[bWLAhhdouter_checksummhexpmmphoenixm0.2.1m +glXOptDt hT9ky[9{-4bWLAhhdretiredmhexpmmcowboym1.1.2dnilYbWLAhhdouter_checksummhexpmmplugm0.14.0m qh5Y#oAf]h0=4bWLAhhdretiredmhexpmmcowboym2.4.0dnilGbWLAhhd timestampmhexpmmphoenixm0.17.0hhba a ha aa bWLAhhddepsmhexpmmplugm 1.2.0-rc.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsejbWLAhhddepsmhexpmmphoenixm0.2.5lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmplugmplugm0.4.4dfalsejbWLAhhddepsmhexpmmcowboym2.2.2lhmhexpmmcowlibmcowlibm~> 2.1.0dfalsehmhexpmmranchmranchm~> 1.4.0dfalsej'bWLAhhddepsmhexpmmphoenixm1.3.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.3.1m 7i8x }6JyHhk`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.3.0m E~<&[_^ NWbWLAhhd registry_etagmhexpmm phoenix_htmlm""0ecf0546b4ca52ab2dbe5ee3a933fc6a"YbWLAhhdinner_checksummhexpmmplugm1.11.0m rRUbúퟎ?`qGӎ'bWLAhhddepsmhexpmmphoenixm 1.4.0-rc.3lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruejbWLAhhddepsmhexpmmphoenixm1.1.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejXbWLAhhdouter_checksummhexpmmplugm1.2.0m '8êBJm0ʭOh::AbWLAhhdretiredmhexpmmphoenix_pubsubm 1.0.0-rc.0dnil-bWLAhhddepsmhexpmmdecimalm1.3.0j[bWLAhhdinner_checksummhexpmmphoenixm1.2.4m ArG^!j^AuH 9 .c[6bWLAhhdretiredmhexpmmphoenixm1.4.14dnilbWLAhhdversionsmhexpmmplugl]m0.4.1m0.4.2m0.4.3m0.4.4m0.5.0m0.5.1m0.5.2m0.5.3m0.6.0m0.7.0m0.8.0m0.8.1m0.8.2m0.8.3m0.8.4m0.9.0m0.10.0m0.11.0m0.11.1m0.11.2m0.11.3m0.12.0m0.12.1m0.12.2m0.13.0m0.13.1m0.14.0m1.0.0m1.0.1m1.0.2m1.0.3m1.0.4m1.0.5m1.0.6m1.1.0m1.1.1m1.1.2m1.1.3m1.1.4m1.1.5m1.1.6m1.1.7m1.1.8m1.1.9m 1.2.0-rc.0m1.2.0m1.2.1m1.2.2m1.2.3m1.2.4m1.2.5m1.2.6m1.3.0m1.3.1m1.3.2m1.3.3m1.3.4m1.3.5m1.3.6m 1.4.0-rc.0m1.4.0m1.4.1m1.4.2m1.4.3m1.4.4m1.4.5m 1.5.0-rc.0m 1.5.0-rc.1m 1.5.0-rc.2m1.5.0m1.5.1m1.6.0m1.6.1m1.6.2m1.6.3m1.6.4m1.7.0m1.7.1m1.7.2m1.8.0m1.8.1m1.8.2m1.8.3m1.9.0m1.10.0m1.10.1m1.10.2m1.10.3m1.10.4m1.11.0m1.11.1m1.12.0m1.12.1j`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.8.0m wu`֫{%ɯ)dNH"Θ 9bWLAhhdretiredmhexpmm plug_cowboym2.1.1dnilKbWLAhhddepsmhexpmmphoenixm1.2.4lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm6~> 1.4 or ~> 1.3.3 or ~> 1.2.4 or ~> 1.1.8 or ~> 1.0.5dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm3.0.0m HkR!p;i(InE*+bWLAhhddepsmhexpmmplugm1.10.0lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruej[bWLAhhdinner_checksummhexpmmphoenixm1.2.5m Z_"Y^#*evH#CbWLAhhd timestampmhexpmmplugm1.2.6hhbaahaa4aKbWLAhhd timestampmhexpmm phoenix_htmlm2.0.0hhba a ha aa FbWLAhhd timestampmhexpmmcowlibm2.10.1hhbaahaaa.4bWLAhhdretiredmhexpmmcowlibm2.2.1dnilEbWLAhhd timestampmhexpmmpoisonm1.1.0hhba a ha a.aYbWLAhhdinner_checksummhexpmmranchm1.3.1m =OYALRz z)HE-. ryvhbWLAhhddepsmhexpmm phoenix_htmlm2.6.2lhmhexpmmplugmplugm~> 1.0dfalsej:bWLAhhdretiredmhexpmm phoenix_htmlm1.0.0dnilKbWLAhhd timestampmhexpmmphoenixm 1.2.0-rc.1hhba a ha aa FbWLAhhd timestampmhexpmmphoenixm0.7.1hhba a ha aa `bWLAhhdouter_checksummhexpmm phoenix_htmlm2.0.1m Sf&]rJsu7 eUyB7~XbWLAhhdinner_checksummhexpmmplugm1.0.4m ׼fFOshM$L3m*bWLAhhddepsmhexpmm plug_cowboym2.5.1lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmcowboy_telemetrymcowboy_telemetrym~> 0.3dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4 or ~> 1.0dfalsejbWLAhhddepsmhexpmmplugm1.4.1lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejFbWLAhhd timestampmhexpmmphoenixm1.1.8hhba a ha aa [bWLAhhdinner_checksummhexpmmphoenixm1.4.0m Vs_>;1IԴ6fb{`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.6.2m J^X OLiP>0[(D9%>ZbWLAhhdinner_checksummhexpmmcowboym1.0.1m  Q˻u 4R eh3]@FbWLAhhd timestampmhexpmmcowlibm2.11.0hhbaahaaa.JbWLAhhd timestampmhexpmm plug_cowboym2.1.1hhba a ha aa 2bWLAhhdretiredmhexpmmmimem1.5.0dnil'bWLAhhddepsmhexpmmphoenixm1.3.2lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsejcbWLAhhddepsmhexpmmplugm1.1.7lhmhexpmmcowboymcowboym~> 1.0dtruej`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.3.0m (&M"$& $bn 2q>/bbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.0.1m b7|Kչ .: NjXbWLAhhdinner_checksummhexpmmplugm1.3.4m :8?YERI44GHwbWLAhhddepsmhexpmmcowboym2.6.1lhmhexpmmcowlibmcowlibm~> 2.7.0dfalsehmhexpmmranchmranchm~> 1.7.1dfalsejEbWLAhhd timestampmhexpmmpoisonm4.0.0hhba a ha a.abWLAhhddepsmhexpmmplugm1.3.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.9.1m ȽP#4|oA iOT]bWLAhhdinner_checksummhexpmm telemetrym0.4.3m d(c)<٦&:f;șW_bWLAhhdouter_checksummhexpmm plug_cryptom1.2.1m iaп2ӑT].7h9ax,`bWLAhhdouter_checksummhexpmm phoenix_htmlm1.4.0m jJZ:bxhk ~RsXI֟kLdbWLAhhddepsmhexpmmplugm0.11.3lhmhexpmmcowboymcowboym~> 1.0dtruejXbWLAhhdinner_checksummhexpmmplugm0.5.0m r"cuM>͖ x7ɮ4|)uR#vtObWLAhhd timestampmhexpmmcowboy_telemetrym0.4.0hhbaahaaa4bWLAhhdretiredmhexpmmcowboym2.2.0dnil^bWLAhhdinner_checksummhexpmmjasonm 1.0.0-rc.2m *]f?v7@.FV)2bWLAhhdretiredmhexpmmplugm1.4.0dnil[bWLAhhdinner_checksummhexpmmphoenixm1.0.1m .ٝrl#H[;'r9p؂3XbWLAhhdinner_checksummhexpmmplugm1.6.3m C3{*/c5i~LSH,^2bWLAhhdretiredmhexpmmplugm1.4.3dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm3.0.3m 2-p~^++iy}[ 0JbWLAhhd timestampmhexpmm plug_cowboym2.4.1hhba a ha aa \bWLAhhdinner_checksummhexpmmphoenixm0.14.0m q;{;  )=oR b/_bWLAhhdouter_checksummhexpmm plug_cryptom1.0.0m sh/AL]oi;tNXwY5bWLAhhdretiredmhexpmmphoenixm0.1.0dnil5bWLAhhdretiredmhexpmmphoenixm0.7.1dnil5bWLAhhdretiredmhexpmmphoenixm1.4.8dnilDbWLAhhdversionsmhexpmmdecimallm0.1.1m0.1.2m0.2.0m0.2.1m0.2.2m0.2.3m0.2.4m0.2.5m1.0.0m1.0.1m1.1.0m1.1.1m1.1.2m1.2.0m1.3.0m1.3.1m1.4.0m1.4.1m1.5.0m1.6.0m1.7.0m1.8.0m1.8.1m 1.9.0-rc.0m1.9.0m 2.0.0-rc.0m2.0.0j[bWLAhhdinner_checksummhexpmmphoenixm1.4.1m c(e|e|bLB#FbWLAhhd timestampmhexpmmphoenixm0.2.2hhba a ha aa DbWLAhhd timestampmhexpmmplugm1.12.0hhbaahaa4a7bWLAhhdretiredmhexpmm telemetrym1.0.0dnil5bWLAhhdretiredmhexpmmphoenixm1.5.1dnil\bWLAhhdouter_checksummhexpmmphoenixm0.11.0m @7#&[vnf"ď?O#y*[bWLAhhdinner_checksummhexpmmphoenixm1.3.2m *QpkNn~ˊ,q痍\sxDbWLAhhd timestampmhexpmmplugm0.11.1hhbaahaa4aZbWLAhhdouter_checksummhexpmmcowboym2.8.0m FCJmM,u=г]T_[bWLAhhdouter_checksummhexpmmphoenixm1.5.2m 0G#g5ng*y4Ԇ-.rQL$"4MbWLAhhd timestampmhexpmmphoenix_pubsubm1.0.2hhba a ha aa bbWLAhhdinner_checksummhexpmmphoenix_pubsubm0.1.0m zڏAI+Y@W<5y5EbWLAhhd timestampmhexpmmpoisonm1.3.0hhba a ha a.aXbWLAhhdouter_checksummhexpmmplugm1.3.3m C4t~ws/[4 };EbWLAhhd timestampmhexpmmcowboym2.2.2hhbaahaaa.dbWLAhhdinner_checksummhexpmm phoenix_htmlm 2.0.0-devm 3{ۼ/"\4s9sHee[}(e[bWLAhhdinner_checksummhexpmmdecimalm1.8.0m F. _ ţB~5HZes4.abWLAhhdouter_checksummhexpmm phoenix_htmlm2.10.0m .8CN҄W~`s}") .U<=mDbWLAhhd timestampmhexpmmjasonm1.1.1hhbaaha aa:bbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.1.0m ^%/dcfa-PSYD2bWLAhhdretiredmhexpmmmimem2.0.1dnil[bWLAhhdouter_checksummhexpmmphoenixm1.4.8m 9e" MrJgjt--EbWLAhhd timestampmhexpmmcowlibm2.7.0hhbaahaaa.4bWLAhhdretiredmhexpmmcowlibm2.5.0dnil[bWLAhhdouter_checksummhexpmmphoenixm1.5.3m d 3ZiVHd(68:#\׶|%:bWLAhhdretiredmhexpmm phoenix_htmlm3.0.2dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.0.0m JnPp~ղi>TCHYF>!\5+bWLAhhddepsmhexpmmranchm1.6.2j3bWLAhhdretiredmhexpmmranchm1.7.1dnil\bWLAhhdouter_checksummhexpmmphoenixm1.4.15m dv#f mW7JܻiIFbWLAhhd timestampmhexpmmphoenixm1.3.4hhba a ha aa gbWLAhhdouter_checksummhexpmmphoenix_pubsubm 1.0.0-rc.0m v\f_vM^Z"q9ۏ ;W_EbWLAhhd timestampmhexpmmcowlibm2.2.0hhbaahaaa.jbWLAhhddepsmhexpmmphoenixm1.4.17lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsej2bWLAhhddepsmhexpmmdecimalm 1.9.0-rc.0jbWLAhhddepsmhexpmmcowboym2.7.0lhmhexpmmcowlibmcowlibm~> 2.8.0dfalsehmhexpmmranchmranchm~> 1.7.1dfalsej[bWLAhhdinner_checksummhexpmmphoenixm1.1.0m :>VV5E6M^^AE@uUEhDbWLAhhd timestampmhexpmmplugm1.10.2hhbaahaa4aGbWLAhhd timestampmhexpmmphoenixm1.4.10hhba a ha aa FbWLAhhd timestampmhexpmmphoenixm0.7.0hhba a ha aa bWLAhhddepsmhexpmmplugm1.8.3lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruej9bWLAhhdretiredmhexpmm plug_cowboym2.3.0dnil*bWLAhhddepsmhexpmmplugm0.5.1j[bWLAhhdouter_checksummhexpmmphoenixm1.0.2m VBSkeѠOU~9V#wk`Rg8bWLAhhdretiredmhexpmmjasonm 1.0.0-rc.2dnil,bWLAhhddepsmhexpmmcowlibm2.8.0jbWLAhhddepsmhexpmmphoenixm1.2.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.1dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejGbWLAhhd timestampmhexpmmphoenixm0.10.0hhba a ha aa 4bWLAhhdretiredmhexpmmpoisonm1.5.1dnil2bWLAhhdretiredmhexpmmplugm1.1.6dnil+bWLAhhddepsmhexpmmranchm1.3.1jbWLAhhddepsmhexpmmplugm1.4.4lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsej5bWLAhhdretiredmhexpmmdecimalm1.8.0dnilCbWLAhhd timestampmhexpmmplugm1.1.0hhbaahaa4a2bWLAhhdretiredmhexpmmplugm1.0.1dnil\bWLAhhdouter_checksummhexpmmphoenixm0.14.0m حTx&y/ݝ98ZbWLAhhdinner_checksummhexpmmcowboym2.2.2m lcMڋ+ m 1.5dfalsejJbWLAhhd timestampmhexpmm plug_cowboym2.5.2hhba a ha aa bWLAhhddepsmhexpmmphoenixm0.10.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm ~> 0.11.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.4.2dtruej2bWLAhhdretiredmhexpmmplugm0.4.1dnil4bWLAhhddepsmhexpmmphoenix_pubsubm1.0.1j/bWLAhhddepsmhexpmm telemetrym0.1.0jZbWLAhhdouter_checksummhexpmmcowboym2.2.0m ]`>_J40BN./d5|ZbWLAhhdinner_checksummhexpmmcowlibm1.2.0m / VE;>-b' N\,`@bWLAhhd timestampmhexpmm plug_cryptohhbaahaaa.RbWLAhhd registry_etagmhexpmmphoenixm""b1c4092fd2fdcc64525a93181cd45bcd"6bWLAhhdretiredmhexpmmphoenixm1.5.11dnil3bWLAhhdretiredmhexpmmplugm0.12.2dnil4bWLAhhdretiredmhexpmmcowlibm2.3.0dnilFbWLAhhd timestampmhexpmmphoenixm1.0.6hhba a ha aa `bWLAhhdinner_checksummhexpmm phoenix_htmlm2.1.0m ud*7kH|K~9dƀbWLAhhddepsmhexpmmphoenixm0.9.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm ~> 0.10.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.4.2dtruej*bWLAhhddepsmhexpmmmimem1.0.1jXbWLAhhdinner_checksummhexpmmplugm0.4.4m ÃnOWs˧'S/M)WW`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.9.2m 7` Co񚮘dbw:[.`,bWLAhhddepsmhexpmmcowlibm2.0.1j2bWLAhhdretiredmhexpmmplugm0.5.1dnil[bWLAhhdouter_checksummhexpmmphoenixm1.2.4m ]ͤr GM(\rn\qV[\bWLAhhdinner_checksummhexpmmphoenixm0.12.0m Bp5 »O+hȠ& F!@ F2,bWLAhhdretiredmhexpmm plug_cryptom1.1.1tdmessagem/Wrong default value is used for salt on encryptdreasondRETIRED_INVALID9bWLAhhd timestampmhexpmmmimehhbaahaaa.4bWLAhhddepsmhexpmmphoenix_pubsubm1.0.0j'bWLAhhddepsmhexpmmphoenixm1.3.4lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.3 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej[bWLAhhdouter_checksummhexpmmdecimalm0.2.3m tVX7aCVh`ZV1ւu2bWLAhhdretiredmhexpmmmimem1.1.0dnil4bWLAhhdretiredmhexpmmcowlibm1.0.2dnil_bWLAhhdouter_checksummhexpmm plug_cowboym2.0.1m s nh4jQQ@! 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.1.1 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej2bWLAhhdretiredmhexpmmplugm1.8.1dnil[bWLAhhdouter_checksummhexpmmphoenixm0.4.0m 碆B~@9YUOb*b/bWLAhhddepsmhexpmm telemetrym0.4.0jCbWLAhhd timestampmhexpmmplugm1.0.5hhbaahaa4aKbWLAhhd timestampmhexpmm phoenix_htmlm2.1.0hhba a ha aa dbWLAhhdinner_checksummhexpmm phoenix_htmlm 2.7.0-devm <|nKx;&y-0GY]bWLAhhdouter_checksummhexpmm telemetrym0.3.0m c}11b!1 Z6h!/rsbWLAhhddepsmhexpmm phoenix_htmlm2.6.0lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejCbWLAhhd timestampmhexpmmplugm1.0.6hhbaahaa4a[bWLAhhdouter_checksummhexpmmdecimalm1.0.1m dk+5~ kƿF|xwt[bWLAhhdouter_checksummhexpmmphoenixm1.3.3m (& 1A E-;4sN0]J+DbWLAhhd timestampmhexpmmranchm1.2.1hhba a ha aa _bWLAhhdouter_checksummhexpmm plug_cryptom1.2.0m S8DRU| $ ih?XbWLAhhdinner_checksummhexpmmplugm1.7.0m ͌U17 HuJ%#nYbWLAhhdouter_checksummhexpmmranchm2.1.0m $N*au' Ő$v)J2Wޏ;yi,bWLAhhddepsmhexpmmcowlibm1.2.0jbWLAhhddepsmhexpmmplugm1.8.2lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruejLbWLAhhd timestampmhexpmm phoenix_htmlm2.10.0hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm0.5.0m /ߌͥB( P fk.O4bWLAhhdretiredmhexpmmcowboym1.1.1dnilEbWLAhhd timestampmhexpmmcowlibm2.5.0hhbaahaaa.CbWLAhhd timestampmhexpmmplugm1.3.5hhbaahaa4abWLAhhddepsmhexpmmcowboy_telemetrym0.1.0lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejgbWLAhhdversionsmhexpmmcowboy_telemetrylm0.1.0m0.2.0m0.3.0m0.3.1m0.4.0j`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.6.1m }S= zn$Ÿf0I["7 R}4bWLAhhdretiredmhexpmmpoisonm2.2.0dnil,bWLAhhddepsmhexpmmpoisonm1.4.0j[bWLAhhdinner_checksummhexpmmcowlibm2.10.0m âɹ5.[ZAib}!CbWLAhhd timestampmhexpmmmimem2.0.0hhbaahaaa.FbWLAhhd timestampmhexpmmdecimalm1.7.0hhbaaha aa:CbWLAhhd timestampmhexpmmplugm0.9.0hhbaahaa4avbWLAhhdversionsmhexpmm plug_cryptolm1.0.0m1.1.0m1.1.1m1.1.2m1.2.0m1.2.1m1.2.2jDbWLAhhd timestampmhexpmmplugm1.10.3hhbaahaa4a`bWLAhhdinner_checksummhexpmmphoenixm 1.5.0-rc.0m 8;njxPZh>"Ξǣ,DbWLAhhd timestampmhexpmmjasonm1.0.1hhbaaha aa:FbWLAhhd timestampmhexpmmphoenixm1.5.9hhba a ha aa XbWLAhhdouter_checksummhexpmmplugm1.3.1m b\P1Yu.e34hDJT<\bWLAhhdouter_checksummhexpmmphoenixm0.10.0m @` L)-%T[bWLAhhdouter_checksummhexpmmphoenixm1.1.5m ebHm O^<<9Ubj}še]H:bWLAhhdretiredmhexpmm phoenix_htmlm2.1.1dnil[bWLAhhdinner_checksummhexpmmphoenixm1.2.2m 4[RY8ΖlL‰'JDhbWLAhhddepsmhexpmm phoenix_htmlm2.9.0lhmhexpmmplugmplugm~> 1.0dfalsej2bWLAhhdretiredmhexpmmplugm1.2.1dnil*bWLAhhddepsmhexpmmmimem1.4.0j 1.0 or ~> 2.5dtruehmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.6.4 or ~> 1.7dfalsej[bWLAhhdinner_checksummhexpmmphoenixm0.7.0m *~t@ `fNV][:;MYGbWLAhhd timestampmhexpmmphoenixm0.2.11hhba a ha aa EbWLAhhd timestampmhexpmmcowboym2.3.0hhbaahaaa.:bWLAhhdretiredmhexpmm phoenix_htmlm2.3.0dnil2bWLAhhdretiredmhexpmmplugm1.8.3dnilibWLAhhddepsmhexpmm phoenix_htmlm2.14.0lhmhexpmmplugmplugm~> 1.5dfalsej3bWLAhhdretiredmhexpmmjasonm1.2.0dnil9bWLAhhdretiredmhexpmm plug_cowboym2.5.2dnilbbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.0.2m o6L]kӨ4lVˮftCbWLAhhd timestampmhexpmmplugm1.7.0hhbaahaa4a[bWLAhhdinner_checksummhexpmmphoenixm0.1.0m Hyr M{=w-bWLAhhddepsmhexpmmphoenixm0.17.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejYbWLAhhdinner_checksummhexpmmplugm0.13.1m GA2wY!^asoK/}5bWLAhhdretiredmhexpmmphoenixm0.4.1dnil;bWLAhhdretiredmhexpmm phoenix_htmlm2.13.4dnil5bWLAhhdretiredmhexpmmphoenixm1.1.5dnilbWLAhhddepsmhexpmmphoenixm1.1.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejHbWLAhhd timestampmhexpmm telemetrym0.2.0hhbaahaa4aDbWLAhhd timestampmhexpmmplugm0.12.2hhbaahaa4a+bWLAhhddepsmhexpmmranchm1.3.0jFbWLAhhd timestampmhexpmmphoenixm0.2.0hhba a ha aa LbWLAhhd timestampmhexpmm phoenix_htmlm2.14.0hhba a ha aa `bWLAhhdinner_checksummhexpmmphoenixm 1.4.0-rc.0m k]MvF/x[bcjfj8{.ޤ3bWLAhhdretiredmhexpmmjasonm1.2.2dnilEbWLAhhd timestampmhexpmmcowlibm1.0.2hhbaahaaa.XbWLAhhdinner_checksummhexpmmplugm1.0.2m 4)ȏưMq/gV@Lꗦ1:Iʨ#n2bWLAhhdretiredmhexpmmplugm1.9.0dnilFbWLAhhd timestampmhexpmmdecimalm1.6.0hhbaaha aa::bWLAhhdretiredmhexpmm phoenix_htmlm2.6.1dnilcbWLAhhddepsmhexpmmplugm1.1.4lhmhexpmmcowboymcowboym~> 1.0dtruej[bWLAhhdinner_checksummhexpmmcowlibm2.11.0m FbV.vwn  cKbWLAhhd timestampmhexpmm phoenix_htmlm2.8.0hhba a ha aa YbWLAhhdouter_checksummhexpmmranchm1.2.1m Wa\7\#U0ű%ZЎ[FbWLAhhd timestampmhexpmmphoenixm1.0.4hhba a ha aa wbWLAhhddepsmhexpmm phoenix_htmlm1.2.0lhmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsejbWLAhhddepsmhexpmmphoenixm1.5.0lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej\bWLAhhdouter_checksummhexpmmphoenixm1.4.10m %jס@)p6=|pnd"tcbWLAhhddepsmhexpmmplugm1.1.5lhmhexpmmcowboymcowboym~> 1.0dtruejZbWLAhhdinner_checksummhexpmmpoisonm1.3.0m 1|S7Yx.k^mF4bWLAhhdretiredmhexpmmcowboym2.9.0dnil:bWLAhhdretiredmhexpmm phoenix_htmlm2.5.1dnil9bWLAhhddepsmhexpmmphoenix_pubsubm 1.0.0-rc.0jFbWLAhhd timestampmhexpmmphoenixm1.3.0hhba a ha aa [bWLAhhdinner_checksummhexpmmdecimalm0.2.4m qt6Dh2A?k't*PgLICVbWLAhhdversionsmhexpmmphoenixllm0.1.0m0.2.0m0.2.1m0.2.2m0.2.3m0.2.4m0.2.5m0.2.6m0.2.7m0.2.8m0.2.9m0.2.10m0.2.11m0.3.0m0.3.1m0.4.0m0.4.1m0.5.0m0.6.0m0.6.1m0.6.2m0.7.0m0.7.1m0.7.2m0.8.0m0.9.0m0.10.0m0.11.0m0.12.0m0.13.0m0.13.1m0.14.0m0.15.0m0.16.0m0.16.1m0.17.0m0.17.1m1.0.0m1.0.1m1.0.2m1.0.3m1.0.4m1.0.5m1.0.6m1.1.0m1.1.1m1.1.2m1.1.3m1.1.4m1.1.5m1.1.6m1.1.7m1.1.8m1.1.9m 1.2.0-rc.0m 1.2.0-rc.1m1.2.0m1.2.1m1.2.2m1.2.3m1.2.4m1.2.5m 1.3.0-rc.0m 1.3.0-rc.1m 1.3.0-rc.2m 1.3.0-rc.3m1.3.0m1.3.1m1.3.2m1.3.3m1.3.4m 1.4.0-rc.0m 1.4.0-rc.1m 1.4.0-rc.2m 1.4.0-rc.3m1.4.0m1.4.1m1.4.2m1.4.3m1.4.4m1.4.5m1.4.6m1.4.7m1.4.8m1.4.9m1.4.10m1.4.11m1.4.12m1.4.13m1.4.14m1.4.15m1.4.16m1.4.17m 1.5.0-rc.0m1.5.0m1.5.1m1.5.2m1.5.3m1.5.4m1.5.5m1.5.6m1.5.7m1.5.8m1.5.9m1.5.10m1.5.11m1.5.12m 1.6.0-rc.0jEbWLAhhd timestampmhexpmmcowboym2.7.0hhbaahaaa._bWLAhhdouter_checksummhexpmm plug_cowboym2.2.2m #dۭ7SՈ~^Pbf17'6bWLAhhdretiredmhexpmmphoenixm1.4.16dnil`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.9.2m MI?V`1= f[0g7iqKNoXbWLAhhdinner_checksummhexpmmplugm1.3.5m up*afm,T˺及Y ;p1,bWLAhhddepsmhexpmmpoisonm1.3.1j;bWLAhhdretiredmhexpmm phoenix_htmlm2.14.3dnilDbWLAhhd timestampmhexpmmplugm1.10.4hhbaahaa4aibWLAhhddepsmhexpmmphoenixm1.4.9lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.1dfalsehmhexpmmplugmplugm~> 1.8.1 or ~> 1.9dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.0dtruehmhexpmm telemetrym telemetrym~> 0.4dfalsejKbWLAhhd timestampmhexpmmphoenixm 1.5.0-rc.0hhba a ha aa  bWLAhhddepsmhexpmm plug_cowboym2.4.0lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmcowboy_telemetrymcowboy_telemetrym~> 0.3dfalsehmhexpmmplugmplugm~> 1.7dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej-bWLAhhddepsmhexpmmcowlibm2.11.0j5bWLAhhdretiredmhexpmmcowlibm2.10.0dnil4bWLAhhdretiredmhexpmmcowboym2.8.0dnilKbWLAhhd timestampmhexpmmdecimalm 2.0.0-rc.0hhbaaha aa:2bWLAhhdretiredmhexpmmplugm1.3.3dnilXbWLAhhdinner_checksummhexpmmmimem1.0.0m 0's;;]ȶbˁw1TJVJbWLAhhd timestampmhexpmm plug_cryptom1.1.2hhbaahaaa.:bWLAhhdretiredmhexpmm phoenix_htmlm2.6.0dnilGbWLAhhd timestampmhexpmmphoenixm0.11.0hhba a ha aa 4bWLAhhdretiredmhexpmmcowboym2.6.0dnilFbWLAhhd timestampmhexpmmphoenixm1.4.5hhba a ha aa cbWLAhhddepsmhexpmmplugm1.0.6lhmhexpmmcowboymcowboym~> 1.0dtruej2bWLAhhdretiredmhexpmmplugm0.4.4dnil-bWLAhhddepsmhexpmmdecimalm1.3.1j_bWLAhhdinner_checksummhexpmm plug_cryptom1.2.0m c3ף_ӚWgm-CbWLAhhd timestampmhexpmmplugm1.3.3hhbaahaa4a6bWLAhhdretiredmhexpmmphoenixm0.2.11dnilFbWLAhhd timestampmhexpmmphoenixm1.5.7hhba a ha aa ibWLAhhddepsmhexpmm phoenix_htmlm2.14.3lhmhexpmmplugmplugm~> 1.5dfalsejbWLAhhddepsmhexpmmphoenixm0.2.9lhmhexpmmex_confmex_confm0.1.2dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.1dfalsehmhexpmmplugmplugm0.5.0dfalsej2bWLAhhdretiredmhexpmmplugm1.6.2dnilKbWLAhhd timestampmhexpmmphoenixm 1.4.0-rc.1hhba a ha aa XbWLAhhdinner_checksummhexpmmplugm1.3.0m n+?JBE(W Dk̒Dz3bWLAhhdretiredmhexpmmplugm0.11.2dnil3bWLAhhdretiredmhexpmmplugm1.11.0dnil2bWLAhhdretiredmhexpmmplugm1.1.3dnilXbWLAhhdinner_checksummhexpmmplugm1.1.1m UWlٹUh e<>h|,{\{-bWLAhhddepsmhexpmmcowlibm2.10.0j`bWLAhhdouter_checksummhexpmmphoenixm 1.3.0-rc.3m >tm~Ļsb`&x ewYbWLAhhdouter_checksummhexpmmjasonm1.0.0m l@eLc# H;g͠yCbWLAhhd timestampmhexpmmplugm1.2.2hhbaahaa4aGbWLAhhd timestampmhexpmmphoenixm0.13.1hhba a ha aa -bWLAhhddepsmhexpmmdecimalm0.2.4jZbWLAhhdinner_checksummhexpmmpoisonm3.0.0m b^d:RMl|ȶ- x(ƒ 1XbWLAhhdouter_checksummhexpmmplugm1.9.0m ** d4h.I?]MjƼ_#PCbWLAhhd timestampmhexpmmplugm1.0.1hhbaahaa4a[bWLAhhdouter_checksummhexpmmdecimalm1.5.0m  &XUMu_]r?3ɻ9W⡭.abWLAhhdinner_checksummhexpmm phoenix_htmlm2.11.0m m[\VB3x2ba~Weڡl8:bWLAhhdretiredmhexpmm phoenix_htmlm2.0.1dnilVbWLAhhddepsmhexpmmphoenixm 1.2.0-rc.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsehmhexpmmphoenix_pubsubmphoenix_pubsubm ~> 1.0.0-rcdfalsehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejXbWLAhhdinner_checksummhexpmmplugm1.6.4m 5aiE/k7vЙs?'G?8bWLAhhdretiredmhexpmmjasonm 1.0.0-rc.3dnilXbWLAhhdouter_checksummhexpmmmimem1.3.1m lvj  1Lc KζE8du8bWLAhhdretiredmhexpmmjasonm 1.0.0-rc.1dnilKbWLAhhd timestampmhexpmm phoenix_htmlm1.4.0hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm1.1.1m Iu꿣 CMMbK,bWLAhhddepsmhexpmmcowlibm2.7.0j[bWLAhhdinner_checksummhexpmmphoenixm1.1.7m 4ظ ?TL_?85ȭaU2bWLAhhdretiredmhexpmmplugm1.6.4dnil,bWLAhhddepsmhexpmmphoenixm 1.3.0-rc.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 1.0dfalsehmhexpmmplugmplugm~> 1.3.2 or ~> 1.4dfalsehmhexpmmpoisonmpoisonm~> 2.2 or ~> 3.0dfalsej[bWLAhhdouter_checksummhexpmmphoenixm1.1.8m n^YF%{(l<: ]'viDYbWLAhhdinner_checksummhexpmmranchm1.2.0m Hpjp W~\-`yݲ S`ibWLAhhddepsmhexpmmphoenixm0.13.1lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm>= 0.12.2 and < 2.0.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsehmhexpmmpoolboympoolboym~> 1.5.1 or ~> 1.6dtruejZbWLAhhdinner_checksummhexpmmcowlibm1.3.0m l(cעcsC+VF z;9CbWLAhhd timestampmhexpmmplugm1.2.1hhbaahaa4aGbWLAhhd timestampmhexpmmphoenixm0.14.0hhba a ha aa YbWLAhhdouter_checksummhexpmmplugm0.11.1m M}O໿Fk΍]/]/9ݸZbWLAhhdouter_checksummhexpmmpoisonm1.3.0m v QN F%\B6Üq>N_JbWLAhhd timestampmhexpmm plug_cowboym2.3.0hhba a ha aa 6bWLAhhdretiredmhexpmmphoenixm0.17.1dnilYbWLAhhdouter_checksummhexpmmranchm1.6.2m ex֘wkf; mE'CXbWLAhhdinner_checksummhexpmmplugm1.8.3m ym.aNL Be ZhDxYbWLAhhdouter_checksummhexpmmranchm1.3.0m j֫j$Ս҃+7>ụ) [8FbWLAhhd timestampmhexpmmphoenixm1.4.0hhba a ha aa FbWLAhhd timestampmhexpmmphoenixm1.5.8hhba a ha aa [bWLAhhdinner_checksummhexpmmphoenixm1.3.4m ^U#:{mဿ,TS#I<*%=`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.4.0m "s3f?r&Yg~?f׹K_bWLAhhdinner_checksummhexpmm plug_cowboym2.2.2m z ]盒2ĔvLȐXbWLAhhdinner_checksummhexpmmplugm1.1.6m '3Y8|(71'3Pf^bWLAhhdinner_checksummhexpmmjasonm 1.0.0-rc.1m BNnn|+dcXah=S`F%XbWLAhhdouter_checksummhexpmmmimem1.0.1m ^m r,)G XbWLAhhdouter_checksummhexpmmplugm1.8.0m L [8Ɵ*x}kTot$YbWLAhhdouter_checksummhexpmmranchm1.6.0m apeFh=1E^sa`]J7ZbWLAhhdinner_checksummhexpmmcowlibm2.8.0m x}J!s >qr+#Ȥ5bWLAhhdretiredmhexpmmphoenixm0.2.3dnilDbWLAhhd timestampmhexpmmplugm1.10.1hhbaahaa4abWLAhhddepsmhexpmmcowboym2.2.0lhmhexpmmcowlibmcowlibm~> 2.1.0dfalsehmhexpmmranchmranchm~> 1.4.0dfalsej`bWLAhhdinner_checksummhexpmm phoenix_htmlm1.1.0m UL-\^'u2˖ut(DbWLAhhd timestampmhexpmmjasonm1.2.0hhbaaha aa:4bWLAhhddepsmhexpmmphoenix_pubsubm1.1.1jbWLAhhddepsmhexpmmplugm1.6.4lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsej9bWLAhhdretiredmhexpmm plug_cowboym2.5.1dnil6bWLAhhdretiredmhexpmmphoenixm0.12.0dnil[bWLAhhdinner_checksummhexpmmphoenixm1.4.6m 5 xj.HQxvlYbbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.1.2m ig)tѕR@i8MbWLAhhd timestampmhexpmmphoenix_pubsubm2.0.0hhba a ha aa GbWLAhhd timestampmhexpmmphoenixm1.4.15hhba a ha aa  bWLAhhddepsmhexpmmphoenixm0.4.1lhmhexpmmcowboymcowboym~> 1.0.0dtruehmhexpmmlinguistmlinguistm~> 0.1.2dfalsehmhexpmmplugmplugm0.7.0dfalsehmhexpmmpoisonmpoisonm~> 1.1.0dfalsej6bWLAhhdretiredmhexpmmphoenixm0.13.1dnilFbWLAhhd timestampmhexpmmphoenixm1.4.7hhba a ha aa `bWLAhhdinner_checksummhexpmm phoenix_htmlm3.0.1m 5 __T81y@&'[SM2bWLAhhdretiredmhexpmmplugm1.0.5dnilbWLAhhddepsmhexpmmphoenixm0.15.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm>= 0.13.1 and < 2.0.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejJbWLAhhd timestampmhexpmm plug_cryptom1.1.0hhbaahaaa.ZbWLAhhdouter_checksummhexpmmpoisonm2.0.1m 4j9󴛛vGFQDxvC!Bv+LbWLAhhd timestampmhexpmm phoenix_htmlm2.14.1hhba a ha aa bWLAhhddepsmhexpmmphoenixm1.1.5lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.5 or ~> 2.0dfalsejXbWLAhhdinner_checksummhexpmmplugm1.2.1m ܇ Te N+o>&t'CbWLAhhd timestampmhexpmmplugm1.2.0hhbaahaa4a`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.9.3m ]*⹰sQ.Nkr׿1MJRKbWLAhhd timestampmhexpmm phoenix_htmlm2.9.1hhba a ha aa 7bWLAhhdretiredmhexpmmplugm 1.2.0-rc.0dnilXbWLAhhdouter_checksummhexpmmmimem1.4.0m uB"?p#KjGO?jzOFbWLAhhd timestampmhexpmmphoenixm1.5.2hhba a ha aa KbWLAhhd timestampmhexpmmphoenixm 1.6.0-rc.0hhba a ha aa ,bWLAhhddepsmhexpmmpoisonm2.0.1jGbWLAhhd timestampmhexpmmphoenixm1.4.13hhba a ha aa 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejXbWLAhhdinner_checksummhexpmmplugm1.3.6m ߔKø~Y+QJ _EbWLAhhd timestampmhexpmmcowboym2.0.0hhbaahaaa.[bWLAhhdinner_checksummhexpmmphoenixm0.2.5m ",Ҍ5 L<ؼ߬32bWLAhhdretiredmhexpmmplugm1.3.1dnil[bWLAhhdouter_checksummhexpmmphoenixm0.2.0m D7܆qO6ǁ79*0]P쿺sEiCbWLAhhd timestampmhexpmmplugm1.1.6hhbaahaa4aCbWLAhhd timestampmhexpmmplugm1.1.1hhbaahaa4a3bWLAhhdretiredmhexpmmranchm1.6.1dnilEbWLAhhd timestampmhexpmmcowlibm2.3.0hhbaahaaa.`bWLAhhdinner_checksummhexpmmphoenixm 1.3.0-rc.2m SJ%h܂o8Bs E"(ت4bWLAhhdretiredmhexpmmcowboym2.7.0dnil_bWLAhhdouter_checksummhexpmm plug_cowboym2.0.2m DSݢiu| Mq 1bWLAhhdversionsmhexpmmjasonl m 1.0.0-rc.1m 1.0.0-rc.2m 1.0.0-rc.3m1.0.0m1.0.1m1.1.0m1.1.1m1.1.2m1.2.0m1.2.1m1.2.2jebWLAhhddepsmhexpmmplugm0.6.0lhmhexpmmcowboymcowboym~> 1.0.0dtruej[bWLAhhdouter_checksummhexpmmphoenixm0.6.1m ύK lt~/S3ۗhN1bsbWLAhhddepsmhexpmm phoenix_htmlm2.1.1lhmhexpmmplugmplugm~> 0.13 or ~> 1.0dfalsejbWLAhhddepsmhexpmmcowboym2.1.0lhmhexpmmcowlibmcowlibm~> 2.0.1dfalsehmhexpmmranchmranchm~> 1.4.0dfalsejYbWLAhhdinner_checksummhexpmmjasonm1.2.2m CpѪΐi\Vx?R*bWLAhhddepsmhexpmmmimem1.6.0jcbWLAhhddepsmhexpmmplugm1.0.2lhmhexpmmcowboymcowboym~> 1.0dtruej+bWLAhhddepsmhexpmmranchm2.1.0jbWLAhhddepsmhexpmmplugm1.2.6lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsejFbWLAhhd timestampmhexpmmdecimalm0.2.3hhbaaha aa:cbWLAhhddepsmhexpmmplugm0.8.2lhmhexpmmcowboymcowboym~> 1.0dtruejEbWLAhhd timestampmhexpmmcowlibm2.9.1hhbaahaaa.FbWLAhhd timestampmhexpmmphoenixm0.2.5hhba a ha aa XbWLAhhdinner_checksummhexpmmplugm1.2.4m e)Do=."'vu=HϾKbWLAhhd timestampmhexpmmphoenixm 1.2.0-rc.0hhba a ha aa [bWLAhhdinner_checksummhexpmmdecimalm1.3.1m { 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej^bWLAhhdouter_checksummhexpmmjasonm 1.0.0-rc.3m tE;#:˛V83;jWD+lE,LbWLAhhd timestampmhexpmm phoenix_htmlm2.13.1hhba a ha aa ZbWLAhhdouter_checksummhexpmmcowboym2.5.0m v=%3vqW>,,δ )90ZbWLAhhdouter_checksummhexpmmcowlibm2.6.0m Eo*e)YU7,-3$SILbWLAhhd timestampmhexpmm phoenix_htmlm2.11.0hhba a ha aa `bWLAhhdouter_checksummhexpmm phoenix_htmlm2.5.1m |] ^7d"> Q)`MbWLAhhd timestampmhexpmmphoenix_pubsubm1.1.2hhba a ha aa VbWLAhhd registry_etagmhexpmm plug_cryptom""29f1eae1dd8d5dc4c084385d2b97a633"4bWLAhhdretiredmhexpmmpoisonm3.0.0dnilbWLAhhddepsmhexpmmplugm1.8.1lhmhexpmmmimemmimem~> 1.0dfalsehmhexpmm plug_cryptom plug_cryptom~> 1.0dfalsehmhexpmm telemetrym telemetrym~> 0.4dtruejbWLAhhddepsmhexpmmplugm 1.4.0-rc.0lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejabWLAhhdinner_checksummhexpmm phoenix_htmlm2.14.2m r?Hd0P}ٜ lwRFO=V>ZbWLAhhdinner_checksummhexpmmpoisonm1.5.2m V ߷D=#!" XեꄉbWLAhhddepsmhexpmmplugm1.2.4lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsej,bWLAhhddepsmhexpmmpoisonm2.0.0jabWLAhhdouter_checksummhexpmm phoenix_htmlm2.11.2m /T06!lEZ n'CbWLAhhd timestampmhexpmmplugm0.8.3hhbaahaa4a,bWLAhhddepsmhexpmmpoisonm1.0.1j5bWLAhhdretiredmhexpmmphoenixm1.5.2dnil`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.6.1m nIDb$ݲ޺`Ao>!5Ù~ `bWLAhhdinner_checksummhexpmmphoenixm 1.4.0-rc.3m >Y$z^-c㬭}GknډA)gbWLAhhddepsmhexpmmplugm1.6.1lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1 or ~> 2.4dtruehmhexpmmmimemmimem~> 1.0dfalsejbWLAhhddepsmhexpmmplugm1.4.2lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejbWLAhhddepsmhexpmm plug_cowboym2.5.2lhmhexpmmcowboymcowboym~> 2.7dfalsehmhexpmmcowboy_telemetrymcowboy_telemetrym~> 0.3dfalsehmhexpmmplugmplugm~> 1.7dfalsej[bWLAhhdinner_checksummhexpmmphoenixm1.5.2m {]lNvA I/jIg,bWLAhhddepsmhexpmmcowlibm1.0.0j\bWLAhhdouter_checksummhexpmmphoenixm0.13.1m Z. MeC9fԮZB/bWLAhhddepsmhexpmm telemetrym1.0.0jXbWLAhhdouter_checksummhexpmmplugm1.3.6m ?/ ߶? V.\od/uR-}[bWLAhhdinner_checksummhexpmmdecimalm1.0.1m Jćs1K܃ǒ+l ZbWLAhhdinner_checksummhexpmmpoisonm1.0.3m Ljxq߉Õԓ7O]bWLAhhdinner_checksummhexpmm telemetrym0.4.0m 9˄L)5sm U84EbWLAhhd timestampmhexpmmcowlibm2.1.0hhbaahaaa.bWLAhhddepsmhexpmmphoenixm0.16.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 0.14 or ~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejYbWLAhhdouter_checksummhexpmmranchm1.6.1m &O]4b uj[X}b+']X8#nDbWLAhhd timestampmhexpmmranchm1.8.0hhba a ha aa [bWLAhhdouter_checksummhexpmmphoenixm1.4.6m oI uqqYnb>9bWLAhhdretiredmhexpmm plug_cowboym2.5.0dnil5bWLAhhdretiredmhexpmmphoenixm1.0.6dnilbWLAhhddepsmhexpmmplugm1.4.5lhmhexpmmcowboymcowboym~> 1.0.1 or ~> 1.1dtruehmhexpmmmimemmimem~> 1.0dfalsejFbWLAhhd timestampmhexpmmdecimalm1.1.0hhbaaha aa:hbWLAhhddepsmhexpmm phoenix_htmlm2.9.2lhmhexpmmplugmplugm~> 1.0dfalsejbbWLAhhdouter_checksummhexpmmphoenix_pubsubm1.0.1m J/a?bsBqv˗ ӘXbWLAhhdouter_checksummhexpmmplugm1.8.2m TȻ,(#GU(1 VGbWLAhhd timestampmhexpmmphoenixm1.5.11hhba a ha aa 4bWLAhhdretiredmhexpmmpoisonm4.0.0dnilDbWLAhhd timestampmhexpmmranchm1.6.2hhba a ha aa HbWLAhhd timestampmhexpmm telemetrym0.4.2hhbaahaa4adbWLAhhdinner_checksummhexpmm phoenix_htmlm 2.4.0-devm 4 }hd2+6V5bWLAhhdretiredmhexpmmdecimalm0.2.4dnil+bWLAhhddepsmhexpmmranchm1.2.0jbWLAhhddepsmhexpmmplugm1.2.3lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsejZbWLAhhdouter_checksummhexpmmcowlibm2.2.0m ס ;X/-fy7Y@^wZ46bWLAhhdretiredmhexpmmphoenixm0.13.0dnilHbWLAhhd timestampmhexpmmplugm 1.5.0-rc.2hhbaahaa4abWLAhhddepsmhexpmmphoenixm1.0.5lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsej\bWLAhhdinner_checksummhexpmmphoenixm1.4.15m \90j3RβV)bX+Y(ZbWLAhhdouter_checksummhexpmmcowboym1.0.3m :SY]NR [=ȖJfuId5bWLAhhdretiredmhexpmmphoenixm1.2.5dnilEbWLAhhd timestampmhexpmmcowboym1.1.0hhbaahaaa.[bWLAhhdouter_checksummhexpmmdecimalm0.1.1m ZA57/P,#n^}[WBxYbWLAhhdouter_checksummhexpmmplugm0.11.3m O0% Ԣq\%V#4^IebbWLAhhdinner_checksummhexpmmphoenix_pubsubm1.0.2m Rx^ QQXR?44bWLAhhdretiredmhexpmmpoisonm1.2.0dnilCbWLAhhd timestampmhexpmmplugm1.9.0hhbaahaa4aabWLAhhdinner_checksummhexpmm phoenix_htmlm2.10.5m Ot"D s*VlN3|(O ZbWLAhhdinner_checksummhexpmmpoisonm3.1.0m cfo%٤o5V Y;2nHFedbWLAhhddepsmhexpmmplugm0.12.1lhmhexpmmcowboymcowboym~> 1.0dtruejZbWLAhhdinner_checksummhexpmmcowlibm1.1.0m , ؁^l^GZLbWLAhhd timestampmhexpmm phoenix_htmlm2.14.2hhba a ha aa bWLAhhddepsmhexpmmplugm1.2.5lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmmimemmimem~> 1.0dfalsejXbWLAhhdouter_checksummhexpmmplugm1.4.1m ʕ'PpL]MLH,kObWLAhhddepsmhexpmmphoenixm1.5.10lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13 or ~> 3.0dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejJbWLAhhd timestampmhexpmm plug_cowboym2.5.0hhba a ha aa KbWLAhhd timestampmhexpmm phoenix_htmlm2.5.0hhba a ha aa ~bWLAhhdversionsmhexpmm telemetrylm0.1.0m0.2.0m0.3.0m0.4.0m0.4.1m0.4.2m0.4.3m1.0.0j3bWLAhhdretiredmhexpmmjasonm1.1.0dnil3bWLAhhdretiredmhexpmmranchm1.4.0dnilZbWLAhhdouter_checksummhexpmmcowlibm2.0.0m (!gEFD3v5eLѰFbWLAhhd timestampmhexpmmphoenixm1.0.1hhba a ha aa [bWLAhhdinner_checksummhexpmmphoenixm1.4.3m Jd7,4rK֑Rv7]g}JbWLAhhd timestampmhexpmm plug_cowboym2.1.0hhba a ha aa XbWLAhhdinner_checksummhexpmmmimem1.3.0m ^EP O`J4Ǣ QQ_bWLAhhdouter_checksummhexpmm plug_cowboym2.3.0m YZp?Vhp!u̬ۏ\~YbWLAhhdouter_checksummhexpmmjasonm1.2.0m gGWyL:>N;|cNNJYu.bWLAhhddepsmhexpmmcowboym1.0.3lhmhexpmmcowlibmcowlibm~> 1.0.0dfalsehmhexpmmranchmranchm~> 1.0dfalsejYbWLAhhdouter_checksummhexpmmranchm1.7.0m YP:V[/hL0HCM9A,'DbWLAhhd timestampmhexpmmranchm1.2.0hhba a ha aa :bWLAhhdretiredmhexpmm phoenix_htmlm3.0.0dnil`bWLAhhdinner_checksummhexpmm phoenix_htmlm2.0.1m ߲8MςÝzffSpo&YbWLAhhdouter_checksummhexpmmranchm1.7.1m E'x}ٝabY4].ǯ5bWLAhhdretiredmhexpmmphoenixm1.4.6dnilFbWLAhhd timestampmhexpmmdecimalm1.3.1hhbaaha aa:YbWLAhhdinner_checksummhexpmmranchm2.1.0m "atDkmU@++3g;r[bWLAhhdouter_checksummhexpmmdecimalm1.6.0m $@@s`I*sGHM:bJiCbWLAhhd timestampmhexpmmplugm1.1.9hhbaahaa4abWLAhhddepsmhexpmmphoenixm0.2.0lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmmplugmplugm0.4.2dfalsejZbWLAhhdinner_checksummhexpmmcowboym2.6.1m ou|3{;17rxE[ڡTxY?bWLAhhddepsmhexpmmcowboym2.8.0lhmhexpmmcowlibmcowlibm~> 2.9.1dfalsehmhexpmmranchmranchm~> 1.7.1dfalsej3bWLAhhdretiredmhexpmmranchm1.8.0dnilYbWLAhhdouter_checksummhexpmmranchm1.4.0m S "]CG<(L _`bWLAhhdouter_checksummhexpmm phoenix_htmlm2.9.0m ne7WuG5FD))%cA:k .3ebWLAhhddepsmhexpmmplugm0.5.3lhmhexpmmcowboymcowboym~> 1.0.0dtruej9bWLAhhdretiredmhexpmm plug_cowboym2.0.2dnil4bWLAhhdretiredmhexpmmcowlibm1.0.0dnilbWLAhhddepsmhexpmmphoenixm0.2.3lhmhexpmmex_confmex_confm0.1.1dfalsehmhexpmminflexminflexm0.2.0dfalsehmhexpmmjazzmjazzm0.1.0dfalsehmhexpmmplugmplugm0.4.3dfalsejbWLAhhddepsmhexpmmphoenixm1.5.6lhmhexpmmjasonmjasonm~> 1.0dtruehmhexpmm phoenix_htmlm phoenix_htmlm~> 2.13dtruehmhexpmmphoenix_pubsubmphoenix_pubsubm~> 2.0dfalsehmhexpmmplugmplugm~> 1.10dfalsehmhexpmm plug_cowboym plug_cowboym~> 1.0 or ~> 2.2dtruehmhexpmm plug_cryptom plug_cryptom~> 1.1.2 or ~> 1.2dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej[bWLAhhdinner_checksummhexpmmdecimalm1.5.0m C:6C=P)e<7of[CיchHehCbWLAhhd timestampmhexpmmplugm1.4.3hhbaahaa4aZbWLAhhdinner_checksummhexpmmpoisonm2.2.0m GcwwoG}d(A&vW'SJcYbWLAhhdinner_checksummhexpmmplugm1.10.1m jm-XY;T ҇@ZbWLAhhdinner_checksummhexpmmcowboym2.6.2m -n3=-ҿ] 莲ASe>4MɍXbWLAhhdinner_checksummhexpmmmimem1.5.0m >^8m6?/z ;Z>[bWLAhhdouter_checksummhexpmmphoenixm1.4.4m DEL@3aho9O3i^t7mZ;y ~DbWLAhhd timestampmhexpmmranchm1.5.0hhba a ha aa ,bWLAhhddepsmhexpmmcowlibm1.0.2jYbWLAhhdinner_checksummhexpmmjasonm1.2.1m (%/F>Kˍ spD[bWLAhhdouter_checksummhexpmmphoenixm1.2.5m S2&īaipHdRα8ZbWLAhhdinner_checksummhexpmmcowlibm2.9.1m a $[P ;fW\xFbWLAhhd timestampmhexpmmdecimalm1.0.1hhbaaha aa:3bWLAhhdretiredmhexpmmranchm2.1.0dnilKbWLAhhd timestampmhexpmm phoenix_htmlm2.9.0hhba a ha aa bWLAhhddepsmhexpmmphoenixm1.0.0lhmhexpmmcowboymcowboym~> 1.0dtruehmhexpmmplugmplugm~> 1.0dfalsehmhexpmmpoisonmpoisonm~> 1.3dfalsejFbWLAhhd timestampmhexpmmdecimalm1.1.1hhbaaha aa:[bWLAhhdinner_checksummhexpmmdecimalm0.1.1m }VRqtgNpjY$XbWLAhhdouter_checksummhexpmmplugm1.0.2m A› Nm~Q@LÅDySXbWLAhhdouter_checksummhexpmmplugm0.8.4m "5 3T[ۼ~`2p2(5_ZbWLAhhdouter_checksummhexpmmcowlibm2.7.2m .6ЖH U;h~_>k LU@J/_bWLAhhdinner_checksummhexpmm plug_cowboym2.2.1m 2'2*G<..4 UP^hex-2.0.6/test/fixtures/registries/20210926.ets000066400000000000000000001201751437023760000207450ustar00rootroot00000000000000cXM bWLAhhdidZd nonode@nohostxk M]@hddecentralized_countersdfalsehdread_concurrencydfalsehdwrite_concurrencydfalsehd compresseddfalsehdmemoryb>hdownerXd nonode@nohosthdheirdnonehdnamedElixir.Hex.Devhdsizebhdnoded nonode@nohosthd named_tabledfalsehdtypedsethdkeyposahd protectiond protectedhd major_versionahd minor_versionahd extended_infoj-bWLAhhddepsmhexpmmdecimalm1.3.0j/bWLAhhddepsmhexpmm telemetrym0.4.0j5bWLAhhdretiredmhexpmmdecimalm0.2.3dnil_bWLAhhdinner_checksummhexpmm chromic_pdfm0.5.2m Hg[]EdבVXo] (f⋟a[bWLAhhdouter_checksummhexpmmpoolboym1.3.0m 25c*rutR<ϰP+aDbWLAhhd timestampmhexpmmjasonm1.2.2hhba ahaaa4]bWLAhhdouter_checksummhexpmm telemetrym0.4.0m |1p| 0-Ow?A[bWLAhhdinner_checksummhexpmmdecimalm0.2.0m [.ٙ)b9*O^GLzb}F-bWLAhhddepsmhexpmmdecimalm1.0.1j_bWLAhhdinner_checksummhexpmm chromic_pdfm0.6.2m m_#]dn!v}(ɀ^ D?-bWLAhhddepsmhexpmmdecimalm1.7.0j_bWLAhhdouter_checksummhexpmm nimble_poolm0.1.0m 4:b C *#p9 Ox\uZbWLAhhddepsmhexpmm chromic_pdfm0.4.0lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmmpoolboympoolboym~> 1.5dfalsej`bWLAhhdinner_checksummhexpmmdecimalm 1.9.0-rc.0m cfja8{@<Lp}9bWLAhhdretiredmhexpmm chromic_pdfm1.1.1dnil9bWLAhhdretiredmhexpmm chromic_pdfm0.6.1dnil-bWLAhhddepsmhexpmmdecimalm1.1.0j[bWLAhhdouter_checksummhexpmmdecimalm0.1.1m ZA57/P,#n^}[WBxbWLAhhddepsmhexpmm chromic_pdfm0.7.0lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmm nimble_poolm nimble_poolm~> 0.2.3dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejbWLAhhddepsmhexpmm chromic_pdfm0.5.2lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmmpoolboympoolboym~> 1.5dfalsejxbWLAhhddepsmhexpmmtelemetry_pollerm0.1.0lhmhexpmm telemetrym telemetrym~> 0.2.0dfalsejbWLAhhddepsmhexpmm chromic_pdfm0.6.2lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmm nimble_poolm nimble_poolm~> 0.2.3dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsejdbWLAhhdinner_checksummhexpmmtelemetry_pollerm0.4.1m P=j;8R戄 v: :udbWLAhhdouter_checksummhexpmmtelemetry_pollerm0.4.0m 7MRg_3h䱤9ڌ}B3gFbWLAhhd timestampmhexpmmdecimalm1.2.0hhba ahaaa4>bWLAhhdretiredmhexpmmtelemetry_pollerm0.5.0dnil[bWLAhhdinner_checksummhexpmmdecimalm0.2.3m r}$޿>4m\lZ$FbWLAhhd timestampmhexpmmdecimalm0.2.0hhba ahaaa49bWLAhhdretiredmhexpmm chromic_pdfm1.1.0dnil-bWLAhhddepsmhexpmmpoolboym1.4.0j9bWLAhhdretiredmhexpmm chromic_pdfm0.3.0dnil[bWLAhhdouter_checksummhexpmmdecimalm1.1.2m zmM8׸8P"H|h=3Q㦑7bWLAhhdretiredmhexpmm telemetrym0.4.3dnil[bWLAhhdouter_checksummhexpmmdecimalm1.9.0m 45h֒>u[] o}^bWLAhhdouter_checksummhexpmmjasonm 1.0.0-rc.1m Iл;_,n4%G)fbWLAhhddepsmhexpmmjasonm1.1.0lhmhexpmmdecimalmdecimalm~> 1.0dtruejFbWLAhhd timestampmhexpmmdecimalm1.4.0hhba ahaaa4[bWLAhhdouter_checksummhexpmmdecimalm1.1.1m ?6"/+ 1.0dtruejObWLAhhd timestampmhexpmmtelemetry_pollerm0.1.0hhbaaha a*a 9bWLAhhdretiredmhexpmm chromic_pdfm0.5.2dnil5bWLAhhdretiredmhexpmmdecimalm1.0.0dnil>bWLAhhdretiredmhexpmmtelemetry_pollerm1.0.0dnil[bWLAhhdinner_checksummhexpmmdecimalm1.0.0m 4") h_S)3rm"K^JbWLAhhd timestampmhexpmm chromic_pdfm0.5.0hhba aha a8a [bWLAhhdouter_checksummhexpmmpoolboym1.5.2m חT@գh%ѥaɕ( FbWLAhhd timestampmhexpmmpoolboym1.2.1hhbaaha a9a[bWLAhhdouter_checksummhexpmmdecimalm1.0.1m dk+5~ kƿF|xwt9bWLAhhdretiredmhexpmm chromic_pdfm0.7.0dnil_bWLAhhdinner_checksummhexpmm nimble_poolm0.1.0m վ' cNI'{9oxN_bWLAhhdouter_checksummhexpmm nimble_poolm0.2.4m 6~q7vNj̵{'m(%5g}QdbWLAhhdouter_checksummhexpmmtelemetry_pollerm0.2.0m m>\IIid!}^g[bWLAhhdinner_checksummhexpmmpoolboym1.5.0m ]q:k{L= W@QQGZ#=m[bWLAhhdouter_checksummhexpmmdecimalm2.0.0m 4fnUި}7b2j# Dw5bWLAhhdretiredmhexpmmdecimalm0.2.5dnilbWLAhhddepsmhexpmm chromic_pdfm0.1.0lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmmpoolboympoolboym~> 1.5dfalsejObWLAhhd timestampmhexpmmtelemetry_pollerm0.3.0hhbaaha a*a [bWLAhhdouter_checksummhexpmmpoolboym1.2.0m w~:02[iYbWLAhhdouter_checksummhexpmmjasonm1.1.1m cEϬ2^4gry:42•%#LKbWLAhhd timestampmhexpmmdecimalm 1.9.0-rc.0hhba ahaaa4&bWLAhd last_updatehhba ahaaaYbWLAhhdinner_checksummhexpmmjasonm1.1.0m 4/thՆS\[ WRO[bWLAhhdouter_checksummhexpmmdecimalm1.8.0m RiNn`PsLfXO[}1xfc]bWLAhhdouter_checksummhexpmm telemetrym0.4.2m -j m{XRr.+#b {*lbWLAhhdversionsmhexpmm nimble_poollm0.1.0m0.2.0m0.2.1m0.2.2m0.2.3m0.2.4jbWLAhhddepsmhexpmm chromic_pdfm0.6.0lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmm nimble_poolm nimble_poolm~> 0.2.3dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej-bWLAhhddepsmhexpmmdecimalm1.5.0j_bWLAhhdouter_checksummhexpmm chromic_pdfm0.7.0m VT5;TvGL˻;oVJbWLAhhd timestampmhexpmm nimble_poolm0.2.4hhbaahaaa!_bWLAhhdinner_checksummhexpmm nimble_poolm0.2.1m QF4yNjq, "V8-锑_kJbWLAhhdversionsmhexpmmpoolboyl m1.2.0m1.2.1m1.3.0m1.4.0m1.4.1m1.4.2m1.5.0m1.5.1m1.5.2j_bWLAhhdouter_checksummhexpmm chromic_pdfm0.7.1m Z2DUNKܼ3V4Aй7bWLAhhdretiredmhexpmm telemetrym0.3.0dnilYbWLAhhdouter_checksummhexpmmjasonm1.0.0m l@eLc# H;g͠y[bWLAhhdinner_checksummhexpmmpoolboym1.2.0m RjᙎJ^DX}#^T#N65bWLAhhdretiredmhexpmmdecimalm1.3.1dnilObWLAhhd timestampmhexpmmtelemetry_pollerm0.4.1hhbaaha a*a HbWLAhhd timestampmhexpmm telemetrym0.4.1hhbaaha aa[bWLAhhdouter_checksummhexpmmpoolboym1.4.1m 0QJ` ϥA?dbWLAhhdinner_checksummhexpmmtelemetry_pollerm0.2.0m ߏmRΚ] &*mu9|j R#7bWLAhhdretiredmhexpmm telemetrym0.4.2dnilYbWLAhhdinner_checksummhexpmmjasonm1.1.1m ̸@߰o/56MH#X^[bWLAhhdouter_checksummhexpmmdecimalm1.4.0m vqN/q5 :=8K-zEFq#5bWLAhhdretiredmhexpmmdecimalm1.9.0dnil[bWLAhhdouter_checksummhexpmmdecimalm1.0.0m T ! oC d0'${ՓBt9bWLAhhdretiredmhexpmm chromic_pdfm0.5.0dnil[bWLAhhdinner_checksummhexpmmdecimalm1.3.1m {N;|cNNJYu.5bWLAhhdretiredmhexpmmdecimalm0.2.4dnilYbWLAhhdouter_checksummhexpmmjasonm1.2.2m (򟞮aðvhя!y^bWLAhhdouter_checksummhexpmmjasonm 1.0.0-rc.2m wv3ԉ ĘDo$-bWLAhhddepsmhexpmmpoolboym1.5.2j-bWLAhhddepsmhexpmmdecimalm0.2.4jIbWLAhhd timestampmhexpmmjasonm 1.0.0-rc.1hhba ahaaa41bWLAhhddepsmhexpmm nimble_poolm0.2.3j[bWLAhhd registry_etagmhexpmmtelemetry_pollerm""5c9b38c868f4640a594548ebba5bc657"[bWLAhhdinner_checksummhexpmmdecimalm0.2.2m b^BJ;@>ҜLz:K [bWLAhhdouter_checksummhexpmmdecimalm1.1.0m  }9 ,SHmga8-k!HbWLAhhd timestampmhexpmm telemetrym0.1.0hhbaaha aaRbWLAhhd registry_etagmhexpmmpoolboym""624f36e367e5b64af565501d4ca9ce2c"FbWLAhhd timestampmhexpmmdecimalm1.8.0hhba ahaaa4EbWLAhhd timestampmhexpmmtelemetry_pollerhhbaaha a*a bWLAhhddepsmhexpmm chromic_pdfm0.7.1lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmm nimble_poolm nimble_poolm~> 0.2.3dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej/bWLAhhddepsmhexpmm telemetrym0.3.0jFbWLAhhd timestampmhexpmmdecimalm0.2.4hhba ahaaa4bWLAhhddepsmhexpmm chromic_pdfm0.5.1lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmmpoolboympoolboym~> 1.5dfalsej_bWLAhhdouter_checksummhexpmm chromic_pdfm1.0.0m P H @4gENciZ1À2] bVFbWLAhhd timestampmhexpmmdecimalm0.2.1hhba ahaaa4FbWLAhhd timestampmhexpmmpoolboym1.2.0hhbaaha a9a-bWLAhhddepsmhexpmmdecimalm0.2.3j[bWLAhhdouter_checksummhexpmmdecimalm0.2.0m &EQ{-D; Mʝ4$bWLAhhddepsmhexpmm chromic_pdfm0.7.2lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmm nimble_poolm nimble_poolm~> 0.2.3dfalsehmhexpmm telemetrym telemetrym~> 0.4.2dfalsej9bWLAhhdretiredmhexpmm chromic_pdfm1.0.0dnil_bWLAhhdinner_checksummhexpmm nimble_poolm0.2.2m w  C<{sK&´1 ;clFbWLAhhd timestampmhexpmmdecimalm1.9.0hhba ahaaa4-bWLAhhddepsmhexpmmdecimalm1.3.1j_bWLAhhdouter_checksummhexpmm nimble_poolm0.2.1m Z[>b~Ƭ>D@,~- yl[bWLAhhdouter_checksummhexpmmdecimalm0.2.4m eBB:QN.cGJ9@5"-bWLAhhddepsmhexpmmdecimalm2.0.0j-bWLAhhddepsmhexpmmdecimalm0.2.5j_bWLAhhdinner_checksummhexpmm chromic_pdfm0.7.2m ꑍ {ibn 9 upOJbWLAhhd timestampmhexpmm chromic_pdfm0.5.1hhba aha a8a -bWLAhhddepsmhexpmmdecimalm1.9.0j[bWLAhhdouter_checksummhexpmmdecimalm1.5.0m  &XUMu_]r?3ɻ9W⡭.-bWLAhhddepsmhexpmmdecimalm1.1.1j1bWLAhhddepsmhexpmm nimble_poolm0.2.2j_bWLAhhdinner_checksummhexpmm chromic_pdfm0.3.0m ?Gx1[v?%%}/grp0`bWLAhhdouter_checksummhexpmmdecimalm 2.0.0-rc.0m %^,>8W$d. 0.4dfalsej5bWLAhhdretiredmhexpmmpoolboym1.4.2dnil3bWLAhhdretiredmhexpmmjasonm1.2.0dnilfbWLAhhddepsmhexpmmjasonm1.0.0lhmhexpmmdecimalmdecimalm~> 1.0dtruejFbWLAhhd timestampmhexpmmdecimalm2.0.0hhba ahaaa4PbWLAhhd registry_etagmhexpmmjasonm""c7ccb0b0d3701498a0a717862ef103b1"3bWLAhhdretiredmhexpmmjasonm1.2.1dnil[bWLAhhdinner_checksummhexpmmdecimalm1.7.0m 0ֵ,TfcsYPߞf S_~Ū[bWLAhhdouter_checksummhexpmmdecimalm0.2.3m tVX7aCVh`ZV1ւu>bWLAhhdretiredmhexpmmtelemetry_pollerm0.4.1dnil]bWLAhhdinner_checksummhexpmm telemetrym0.1.0m s 1 3|m*c8y+A<_bWLAhhdouter_checksummhexpmm chromic_pdfm0.5.1m Ul\&S*;cڰY#KF5 (kbWLAhhddepsmhexpmmjasonm 1.0.0-rc.3lhmhexpmmdecimalmdecimalm~> 1.0dtruejFbWLAhhd timestampmhexpmmdecimalm1.4.1hhba ahaaa4FbWLAhhd timestampmhexpmmdecimalm0.2.5hhba ahaaa4[bWLAhhdouter_checksummhexpmmdecimalm0.2.5m .-h̆ lok$+FXnYG-bWLAhhddepsmhexpmmdecimalm1.0.0j-bWLAhhddepsmhexpmmpoolboym1.4.1jFbWLAhhd timestampmhexpmmdecimalm1.3.0hhba ahaaa4]bWLAhhdinner_checksummhexpmm telemetrym0.4.3m d(c)<٦&:f;șW_bWLAhhdinner_checksummhexpmm chromic_pdfm1.0.0m TíT )@EGO>U+l~!C1bWLAhhddepsmhexpmm nimble_poolm0.2.0j[bWLAhhdouter_checksummhexpmmpoolboym1.5.0m P\"?GU?fD)N6~ s$ik~[bWLAhhdinner_checksummhexpmmdecimalm1.1.2m yie{-S{Q<Қ+HkQlBS VbWLAhhd registry_etagmhexpmm nimble_poolm""06c85751bbe7bda60efea8ca3d0ebf94"HbWLAhhd timestampmhexpmm telemetrym1.0.0hhbaaha aa5bWLAhhdretiredmhexpmmpoolboym1.4.0dnilFbWLAhhd timestampmhexpmmdecimalm1.8.1hhba ahaaa4_bWLAhhdouter_checksummhexpmm chromic_pdfm1.1.0m NUӘ|saGeR{e7;[bWLAhhdinner_checksummhexpmmdecimalm1.3.0m Afx`E|Rӣ՗M'}vbWLAhhddepsmhexpmmtelemetry_pollerm0.2.0lhmhexpmm telemetrym telemetrym~> 0.3dfalsej-bWLAhhddepsmhexpmmpoolboym1.5.1j5bWLAhhdretiredmhexpmmpoolboym1.5.0dnilbWLAhhddepsmhexpmm chromic_pdfm0.5.0lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmmpoolboympoolboym~> 1.5dfalsejdbWLAhhdinner_checksummhexpmmtelemetry_pollerm1.0.0m ۑBNnso> %剠~S[bWLAhhdinner_checksummhexpmmpoolboym1.5.1m kF9С=i&W~YSZwϛl2bWLAhhddepsmhexpmmdecimalm 1.9.0-rc.0j@bWLAhhd timestampmhexpmm chromic_pdfhhba aha a8a HbWLAhhd timestampmhexpmm telemetrym0.4.3hhbaaha aa_bWLAhhdinner_checksummhexpmm nimble_poolm0.2.3m K߇ϋ@67֪+='[TKQ[bWLAhhdinner_checksummhexpmmdecimalm1.8.1m ?_4( 57@)Nޅ3SoEh٬<IbWLAhhd timestampmhexpmmjasonm 1.0.0-rc.3hhba ahaaa4>bWLAhhdretiredmhexpmmtelemetry_pollerm0.3.0dnil7bWLAhhdretiredmhexpmm telemetrym0.4.1dnilbWLAhhddepsmhexpmm chromic_pdfm0.3.0lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmmpoolboympoolboym~> 1.5dfalsej[bWLAhhdouter_checksummhexpmmpoolboym1.2.1m ^M |P磃b+pSYy/%]b#iFbWLAhhd timestampmhexpmmdecimalm0.2.2hhba ahaaa4FbWLAhhd timestampmhexpmmdecimalm0.1.1hhba ahaaa4^bWLAhhdinner_checksummhexpmmjasonm 1.0.0-rc.1m BNnn|+dcXah=S`F%]bWLAhhdinner_checksummhexpmm telemetrym0.4.1m 'HHD$GjA|2w(ttR5bWLAhhdretiredmhexpmmdecimalm1.4.1dnil9bWLAhhdretiredmhexpmm chromic_pdfm0.5.1dnil_bWLAhhdouter_checksummhexpmm chromic_pdfm0.2.0m +±;p#z[&q(:oa9Ó X_bWLAhhdinner_checksummhexpmm chromic_pdfm1.1.1m j QFV07:Rz-yiZ_bWLAhhdinner_checksummhexpmm chromic_pdfm1.1.0m oGFs-+8AvLE@ xX(Vs]bWLAhhdinner_checksummhexpmm telemetrym0.2.0m [@ʣ޳-|OUomk\7L#fw!a1w/bWLAhhddepsmhexpmm telemetrym0.4.3j]bWLAhhdinner_checksummhexpmm telemetrym0.4.0m 9˄L)5sm U84]bWLAhhdouter_checksummhexpmm telemetrym1.0.0m s Y(NF$3U(~ɮvng8Pz2bWLAhhddepsmhexpmmdecimalm 2.0.0-rc.0j_bWLAhhdinner_checksummhexpmm chromic_pdfm0.7.1m [Lʘ^Qd&rB-F0BY-bWLAhhddepsmhexpmmpoolboym1.5.0jJbWLAhhd timestampmhexpmm chromic_pdfm0.6.2hhba aha a8a ObWLAhhd timestampmhexpmmtelemetry_pollerm0.5.1hhbaaha a*a 3bWLAhhdretiredmhexpmmjasonm1.2.2dnilYbWLAhhdinner_checksummhexpmmjasonm1.2.0m 4-$!-?]HCv 8yY8HdbWLAhhdinner_checksummhexpmmtelemetry_pollerm0.5.1m !6 V(5RpX>*FbWLAhhd timestampmhexpmmdecimalm1.5.0hhba ahaaa4bWLAhhdretiredmhexpmm nimble_poolm0.2.2tdmessagemstrategy: :lifo is not usefuldreasondRETIRED_INVALID^bWLAhhdinner_checksummhexpmmjasonm 1.0.0-rc.2m *]f?v7@.FV)[bWLAhhdinner_checksummhexpmmdecimalm1.9.0m 12q$,QK =M[bWLAhhdouter_checksummhexpmmdecimalm0.2.2m 䑳ƑfZz hӨuR?/ ,.7}.FbWLAhhd timestampmhexpmmpoolboym1.4.2hhbaaha a9a-bWLAhhddepsmhexpmmpoolboym1.2.1jbWLAhhdversionsmhexpmm chromic_pdflm0.1.0m0.2.0m0.3.0m0.3.1m0.4.0m0.5.0m0.5.1m0.5.2m0.6.0m0.6.1m0.6.2m0.7.0m0.7.1m0.7.2m1.0.0m1.1.0m1.1.1j_bWLAhhdouter_checksummhexpmm nimble_poolm0.2.0m ]Gp8z[bWLAhhdinner_checksummhexpmmdecimalm0.1.2m iڠV;j\åiTYjdbWLAhhdinner_checksummhexpmmtelemetry_pollerm0.4.0m dޥKw`@#]]L>V+T29bWLAhhdretiredmhexpmm nimble_poolm0.2.0dnilFbWLAhhd timestampmhexpmmdecimalm0.1.2hhba ahaaa4DbWLAhhd timestampmhexpmmjasonm1.2.1hhba ahaaa4JbWLAhhd timestampmhexpmm chromic_pdfm1.0.0hhba aha a8a 5bWLAhhdretiredmhexpmmdecimalm0.2.2dnil9bWLAhhdretiredmhexpmm chromic_pdfm0.7.1dnilYbWLAhhdinner_checksummhexpmmjasonm1.0.1m d6K<p3T]s.gFbWLAhhd timestampmhexpmmdecimalm1.1.2hhba ahaaa4[bWLAhhdinner_checksummhexpmmpoolboym1.2.1m }X͉05&lإ孈5bWLAhhdretiredmhexpmmdecimalm1.0.1dnil[bWLAhhdouter_checksummhexpmmdecimalm1.7.0m wvPZՊOW\_`e]vbWLAhhddepsmhexpmmtelemetry_pollerm0.4.1lhmhexpmm telemetrym telemetrym~> 0.4dfalsej_bWLAhhdinner_checksummhexpmm chromic_pdfm0.6.1m CMN-W2Qo,Ĥ78n~(bWLAhhdretiredmhexpmmtelemetry_pollerm0.2.0dnil1bWLAhhddepsmhexpmm nimble_poolm0.1.0jFbWLAhhd timestampmhexpmmpoolboym1.3.0hhbaaha a9a_bWLAhhdouter_checksummhexpmm chromic_pdfm1.1.1m +02jA&Lk@k|K`=JIy{5bWLAhhdretiredmhexpmmdecimalm1.2.0dnilJbWLAhhd timestampmhexpmm chromic_pdfm1.1.0hhba aha a8a 1bWLAhhddepsmhexpmm nimble_poolm0.2.1jJbWLAhhd timestampmhexpmm chromic_pdfm0.1.0hhba aha a8a /bWLAhhddepsmhexpmm telemetrym1.0.0j]bWLAhhdinner_checksummhexpmm telemetrym0.4.2m (ɒE^s"M;kb_#:sPXps/E_bWLAhhdouter_checksummhexpmm nimble_poolm0.2.3m g}49+krI_p mXQ=P>bWLAhhdretiredmhexpmmtelemetry_pollerm0.5.1dnilbWLAhhddepsmhexpmm chromic_pdfm1.1.0lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmm nimble_poolm nimble_poolm~> 0.2.3dfalsehmhexpmm telemetrym telemetrym~> 0.4.2dfalsej_bWLAhhdouter_checksummhexpmm chromic_pdfm0.7.2m +O|*N:숽s{ϸYbWLAhhdinner_checksummhexpmmjasonm1.0.0m |#!Aw&Zqo7bWLAhhdretiredmhexpmm telemetrym1.0.0dnil9bWLAhhdretiredmhexpmm chromic_pdfm0.3.1dnil5bWLAhhdretiredmhexpmmdecimalm1.5.0dnil5bWLAhhdretiredmhexpmmdecimalm1.1.1dnil5bWLAhhdretiredmhexpmmpoolboym1.2.1dnil>bWLAhhdretiredmhexpmmtelemetry_pollerm0.4.0dnil3bWLAhhdretiredmhexpmmjasonm1.0.1dnil5bWLAhhdretiredmhexpmmdecimalm1.3.0dnildbWLAhhdinner_checksummhexpmmtelemetry_pollerm0.3.0m | ˝EyqZ~US+ɡ#g [bWLAhhdinner_checksummhexpmmpoolboym1.4.1m ~pDG|j;Ҋ*GYZGz_bWLAhhdinner_checksummhexpmm chromic_pdfm0.4.0m ~mpTwmj{4&i{ 4hFbWLAhhd timestampmhexpmmpoolboym1.4.1hhbaaha a9a_bWLAhhdouter_checksummhexpmm chromic_pdfm0.6.0m EWC?O c )5X-!/JVB`bWLAhhdouter_checksummhexpmmdecimalm 1.9.0-rc.0m fuEsW\^KE0|dX< GJbWLAhhd timestampmhexpmm chromic_pdfm0.7.2hhba aha a8a [bWLAhhdouter_checksummhexpmmdecimalm1.3.1m WVHGrn\οǫ*wDbWLAhhd timestampmhexpmmjasonm1.0.0hhba ahaaa45bWLAhhdretiredmhexpmmdecimalm0.2.0dnil[bWLAhhdinner_checksummhexpmmdecimalm1.2.0m F)`q(.W{Gkkh'}M dcRiK 5bWLAhhdretiredmhexpmmdecimalm0.1.2dnil5bWLAhhdretiredmhexpmmdecimalm0.1.1dnil5bWLAhhdretiredmhexpmmpoolboym1.4.1dnilJbWLAhhd timestampmhexpmm chromic_pdfm0.3.1hhba aha a8a [bWLAhhdinner_checksummhexpmmpoolboym1.4.2m apΛa?úD)֔7l+3-[bWLAhhdinner_checksummhexpmmdecimalm0.2.5m @[x:`&'?ԀC{Xk4NêJbWLAhhd timestampmhexpmm chromic_pdfm0.7.0hhba aha a8a [bWLAhhdinner_checksummhexpmmdecimalm0.2.1m U%qs]A27M_bWLAhhdinner_checksummhexpmm chromic_pdfm0.1.0m ?S8(Z,}?Zū5)yDbWLAhhd timestampmhexpmmjasonm1.1.2hhba ahaaa4[bWLAhhdouter_checksummhexpmmdecimalm1.2.0m t"HD2HDM_dшfbWLAhhddepsmhexpmmjasonm1.0.1lhmhexpmmdecimalmdecimalm~> 1.0dtruejvbWLAhhddepsmhexpmmtelemetry_pollerm0.5.0lhmhexpmm telemetrym telemetrym~> 0.4dfalsej5bWLAhhdretiredmhexpmmdecimalm1.1.2dnilJbWLAhhd timestampmhexpmm chromic_pdfm0.2.0hhba aha a8a fbWLAhhddepsmhexpmmjasonm1.2.1lhmhexpmmdecimalmdecimalm~> 1.0dtruej7bWLAhhdretiredmhexpmm telemetrym0.4.0dnil[bWLAhhdinner_checksummhexpmmdecimalm1.6.0m Mn]CpӔ42_Ӻp0Y [bWLAhhdouter_checksummhexpmmdecimalm1.3.0m B 0 1.0 or ~> 2.0dtruej5bWLAhhdretiredmhexpmmdecimalm1.7.0dnil5bWLAhhdretiredmhexpmmdecimalm1.8.0dnilHbWLAhhd timestampmhexpmm telemetrym0.2.0hhbaaha aaYbWLAhhdinner_checksummhexpmmjasonm1.1.2m =g#&LqTVM=!d-bWLAhhddepsmhexpmmdecimalm1.8.1j-bWLAhhddepsmhexpmmdecimalm0.2.0j-bWLAhhddepsmhexpmmdecimalm0.1.1jFbWLAhhd timestampmhexpmmpoolboym1.5.2hhbaaha a9a[bWLAhhdinner_checksummhexpmmdecimalm2.0.0m LlWCG/By+VB֗-bWLAhhddepsmhexpmmdecimalm1.8.0jFbWLAhhd timestampmhexpmmdecimalm1.6.0hhba ahaaa4_bWLAhhdinner_checksummhexpmm chromic_pdfm0.2.0m Z$8oKKq|jUR4x_bWLAhhdinner_checksummhexpmm chromic_pdfm0.3.1m wBQBH&71r̽[bWLAhhdinner_checksummhexpmmpoolboym1.4.0m BcP gHM&H`n)w|D_KbWLAhhd timestampmhexpmmdecimalm 2.0.0-rc.0hhba ahaaa4YbWLAhhdinner_checksummhexpmmjasonm1.2.2m CpѪΐi\Vx?R[bWLAhhdouter_checksummhexpmmpoolboym1.4.0m uzުc 1.0dtruejvbWLAhhddepsmhexpmmtelemetry_pollerm0.5.1lhmhexpmm telemetrym telemetrym~> 0.4dfalsejYbWLAhhdinner_checksummhexpmmjasonm1.2.1m (%/F>Kˍ spDdbWLAhhdouter_checksummhexpmmtelemetry_pollerm0.1.0m V 1.1dfalsehmhexpmmpoolboympoolboym~> 1.5dfalsejDbWLAhhdversionsmhexpmmdecimallm0.1.1m0.1.2m0.2.0m0.2.1m0.2.2m0.2.3m0.2.4m0.2.5m1.0.0m1.0.1m1.1.0m1.1.1m1.1.2m1.2.0m1.3.0m1.3.1m1.4.0m1.4.1m1.5.0m1.6.0m1.7.0m1.8.0m1.8.1m 1.9.0-rc.0m1.9.0m 2.0.0-rc.0m2.0.0jJbWLAhhd timestampmhexpmm chromic_pdfm0.7.1hhba aha a8a 8bWLAhhdretiredmhexpmmjasonm 1.0.0-rc.1dnilJbWLAhhd timestampmhexpmm chromic_pdfm0.4.0hhba aha a8a [bWLAhhdinner_checksummhexpmmdecimalm1.8.0m F. _ ţB~5HZes4.[bWLAhhdinner_checksummhexpmmdecimalm0.2.4m qt6Dh2A?k't*PgLICV6bWLAhhddepsmhexpmmtelemetry_pollerm0.4.0jfbWLAhhddepsmhexpmmjasonm1.1.2lhmhexpmmdecimalmdecimalm~> 1.0dtruejDbWLAhhd timestampmhexpmmjasonm1.1.1hhba ahaaa4FbWLAhhd timestampmhexpmmpoolboym1.5.0hhbaaha a9a_bWLAhhdouter_checksummhexpmm chromic_pdfm0.6.2m ov9/:E"^c,Xt 5bWLAhhdretiredmhexpmmdecimalm1.1.0dnil]bWLAhhdouter_checksummhexpmm telemetrym0.1.0m <1bhxAO\"BMPCD$8bWLAhhdretiredmhexpmmjasonm 1.0.0-rc.3dnildbWLAhhdouter_checksummhexpmmtelemetry_pollerm0.5.0m i[ wL,|Ćn4 &,>bWLAhhd timestampmhexpmm telemetryhhbaaha aafbWLAhhddepsmhexpmmjasonm1.1.1lhmhexpmmdecimalmdecimalm~> 1.0dtruej7bWLAhhdretiredmhexpmm telemetrym0.1.0dnil[bWLAhhdinner_checksummhexpmmdecimalm1.4.0m eqjSӦEf(Ze.J3bWLAhdversiona[bWLAhhdouter_checksummhexpmmdecimalm1.8.1m zVbWLAhhd registry_etagmhexpmm chromic_pdfm""0d9ce686ad99a9b52eff34be0e96ada6"[bWLAhhdouter_checksummhexpmmdecimalm1.4.1m #{RNUV]JrV&hL{ʀ_;ObWLAhhd timestampmhexpmmtelemetry_pollerm0.2.0hhbaaha a*a ]bWLAhhdinner_checksummhexpmm telemetrym0.3.0m <Gqc <"f" :*:jguJsJbWLAhhd timestampmhexpmm nimble_poolm0.2.3hhbaahaaa!bWLAhhddepsmhexpmm chromic_pdfm0.6.1lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmm nimble_poolm nimble_poolm~> 0.2.3dfalsehmhexpmm telemetrym telemetrym~> 0.4dfalsej:bWLAhhdretiredmhexpmmdecimalm 1.9.0-rc.0dnildbWLAhhdouter_checksummhexpmmtelemetry_pollerm0.5.1m Lrnz ѳ3py|_ f?_bWLAhhdouter_checksummhexpmm chromic_pdfm0.6.1m 4z6,nAh'%TߠDh*JbWLAhhd timestampmhexpmm nimble_poolm0.2.2hhbaahaaa!_bWLAhhdouter_checksummhexpmm chromic_pdfm0.5.0m `>Ņ.yCzMU x2]bWLAhhdinner_checksummhexpmm telemetrym1.0.0m E:,$7T 0R3bWLAhhdretiredmhexpmmjasonm1.1.2dnil/bWLAhhddepsmhexpmm telemetrym0.1.0j9bWLAhhdretiredmhexpmm chromic_pdfm0.7.2dnilHbWLAhhd timestampmhexpmm telemetrym0.3.0hhbaaha aaJbWLAhhd timestampmhexpmm chromic_pdfm1.1.1hhba aha a8a 1.0dfalsej_bWLAhhdinner_checksummhexpmm nimble_poolm0.2.4m =}Y^ 2p0ͶJELJ`?wFbWLAhhd timestampmhexpmmpoolboym1.5.1hhbaaha a9a[bWLAhhdinner_checksummhexpmmpoolboym1.3.0m Aw rl,%VV)ٽ*|b~J-bWLAhhddepsmhexpmmdecimalm0.1.2j5bWLAhhdretiredmhexpmmpoolboym1.2.0dnil[bWLAhhdinner_checksummhexpmmpoolboym1.5.2m 9+zE@έyCv/]0P,kDbWLAhhd timestampmhexpmmjasonm1.1.0hhba ahaaa4ObWLAhhd timestampmhexpmmtelemetry_pollerm0.5.0hhbaaha a*a HbWLAhhd timestampmhexpmm telemetrym0.4.0hhbaaha aa^bWLAhhdinner_checksummhexpmmjasonm 1.0.0-rc.3m RHr `D>PŕQOˣfƔ~9bWLAhhdretiredmhexpmm chromic_pdfm0.4.0dnil_bWLAhhdouter_checksummhexpmm chromic_pdfm0.1.0m h'Nv!5R f!KJKdbWLAhhdinner_checksummhexpmmtelemetry_pollerm0.5.0m GpUӜQִ#lib]Tޣ٥ K~bWLAhhdversionsmhexpmm telemetrylm0.1.0m0.2.0m0.3.0m0.4.0m0.4.1m0.4.2m0.4.3m1.0.0j9bWLAhhdretiredmhexpmm nimble_poolm0.2.4dnil3bWLAhhdretiredmhexpmmjasonm1.1.1dnilkbWLAhhddepsmhexpmmjasonm 1.0.0-rc.2lhmhexpmmdecimalmdecimalm~> 1.0dtruej9bWLAhhdretiredmhexpmm chromic_pdfm0.2.0dnil5bWLAhhdretiredmhexpmmdecimalm1.6.0dnilFbWLAhhd timestampmhexpmmdecimalm1.3.1hhba ahaaa4YbWLAhhdouter_checksummhexpmmjasonm1.1.2m CX :.4]C$=:FbWLAhhd timestampmhexpmmdecimalm1.1.1hhba ahaaa4-bWLAhhddepsmhexpmmpoolboym1.4.2j]bWLAhhdouter_checksummhexpmm telemetrym0.4.1m G88.6]g`,V m)ތXHbWLAhhdversionsmhexpmmjasonl m 1.0.0-rc.1m 1.0.0-rc.2m 1.0.0-rc.3m1.0.0m1.0.1m1.1.0m1.1.1m1.1.2m1.2.0m1.2.1m1.2.2j-bWLAhhddepsmhexpmmdecimalm1.4.1jFbWLAhhd timestampmhexpmmdecimalm1.0.1hhba ahaaa4[bWLAhhdinner_checksummhexpmmdecimalm1.1.0m 33s/}z_ 0-g\ʁ*c>r>bWLAhhdretiredmhexpmmtelemetry_pollerm0.1.0dnil9bWLAhhdretiredmhexpmm nimble_poolm0.2.3dnil@bWLAhhd timestampmhexpmm nimble_poolhhbaahaaa!3bWLAhhdretiredmhexpmmjasonm1.0.0dnil9bWLAhhdretiredmhexpmm chromic_pdfm0.6.2dnilbWLAhhddepsmhexpmm chromic_pdfm0.3.1lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmmpoolboympoolboym~> 1.5dfalsej`bWLAhhdinner_checksummhexpmmdecimalm 2.0.0-rc.0m ĸK%5 1.1dfalsehmhexpmm nimble_poolm nimble_poolm~> 0.2.3dfalsehmhexpmm telemetrym telemetrym~> 0.4.2dfalsej_bWLAhhdinner_checksummhexpmm nimble_poolm0.2.0m %kaD="ivxgm>o-bWLAhhddepsmhexpmmpoolboym1.2.0jRbWLAhhd registry_etagmhexpmmdecimalm""4657f6f92e3c01945c9c9b06b6fd850e"DbWLAhhd timestampmhexpmmjasonm1.2.0hhba ahaaa4bWLAhhddepsmhexpmm chromic_pdfm1.1.1lhmhexpmmjasonmjasonm~> 1.1dfalsehmhexpmm nimble_poolm nimble_poolm~> 0.2.3dfalsehmhexpmm telemetrym telemetrym~> 0.4 or ~> 1.0dfalsej-bWLAhhddepsmhexpmmdecimalm1.1.2j[bWLAhhdinner_checksummhexpmmdecimalm1.4.1m Ps""|* ږ[ p5bWLAhhdretiredmhexpmmpoolboym1.5.1dnil]bWLAhhdouter_checksummhexpmm telemetrym0.3.0m c}11b!1 Z6h!/rJbWLAhhd timestampmhexpmm nimble_poolm0.2.0hhbaahaaa!YbWLAhhdouter_checksummhexpmmjasonm1.2.1m YW`Z`A@Dqoihex-2.0.6/test/fixtures/sample/000077500000000000000000000000001437023760000164165ustar00rootroot00000000000000hex-2.0.6/test/fixtures/sample/mix.exs000066400000000000000000000002041437023760000177300ustar00rootroot00000000000000defmodule Sample.Fixture.MixProject do use Mix.Project def project do [app: :sample, version: "0.0.1", deps: []] end end hex-2.0.6/test/fixtures/test_priv.pem000066400000000000000000000032171437023760000176620ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA70iFalPXSDJX0ZqQNYw2yPyMWmpV4ssLwuGm4l3TjS50UgKY nyL2j7m0mmO7DhLNqRKn8IsIJoHeeuFhf5cvW162mp2Kn2e9LXRobafYIM3hxzB8 LZqeQjxPR6xsDkY5HgQsxtTkbNRq/8ODAjx6XsZgFRSkjgD+nWO0D4i67+8lWSyG BaXAvyYQVRimkvm400PYD4RT2dk9lSrBjhAvsZ+buCX/F8XuK2sOdhoFC7PXz4kO 2q41IF1LjVfKz6WdXH91jUCUG80TAzK35lRTGRes/NOIV/aYwt6fc3BjgzOg/X8u cFwuWi5Tn5lU+eFYHcv1Qyxxx9yi03pZ7hH4iwIDAQABAoIBAQCXtDTRuqIMpc5D l2jCakj5mBQr5qrZBL5KKeIyNiY/piodLIQysGn9qVE1aPFY9Nbq0Gck/CCIuWGi Km40BFgD58KBuEwA0DaCMQFcNEO0WJNCRB0WlKate6sP1+MSEbd4rlDtJmBEF1BX I09WBZ3XpJGaC+JgHYVPp7yq9JcAMjZZl4AebCE83queT7cFLQu/6njRnGoKpLqU bD5w+eoHYFLgh197cdOxA7Yay5iRDnxuY7WYxZjRbP2UWxH6+xe/d+Vns+aUWjlD pd+zg0IWk/2VrlQfAzpYgIJCvFBTzbF4Bn9uHKlE4vwsnf/PsPalLdPT22HjfHry EpoBxVWBAoGBAP55G3bYAChdukZuZv5dbM1SUhNnTgX+l70YjHnIgjYQB4JmZAjv jZgPJ/0DFawwn3mNfESba346d0SY6NbMS1z1Ga/GkU2qcgLlDiIA/AIa7TEPiM+K D2tWbMtjRqMpZP2JKYYNwgngwz9fwwz7fk3oNUl+srJY/kA/OEvb3nUhAoGBAPC4 FL7ZL9fvEZwOLevarxWkBnQBeybvfBNW22gvR4u7L5DH4S/L9zrGHnnLCdjL2tNE YMfBR8HCm6q/4uGXNCIyrx9/rKLr713ceCLYLbt11EysEcS8jpUkzwTNpIa3vdKg b+ImOKaQ1Ff9FcB13HBpSnZgQvOArCTA9FxwnswrAoGAC3NdpgJgN3DIQgUTw1xm 2fJbWR4r558mKs8g+xXnrhEYlWiQFcrZvz7nWL47ymzBsFGKhvfLZXmyBjcvOwMk XQF2b29q+Gi0CqdN9H/A10No6u09BcG7oePYr2o/MnZZYgM7CBo0YgdoIcDoYPws GctaIn1+AwJ4JmHx4Y/6OaECgYAF006dN8BSp3RzpFw0Ivytt2R4ljiWvqDwDuAM a2h91y/VfyDR+UuoXncKV4GLf5NyHWuCKglEhSMjRLWG5BPc6AEY8AwLfU4zpUw6 +6RPrxBOMrPTYQTKUzO3WAqtP/EWEc/jVy1zynl5D6ThHXkSN1oX90hngCuqUAkZ 25fcNQKBgQC5wjvxbglrsWZZpyTK7G+XxGiwZj8knzEmxi/qRAYnoHiwTXT0tJ7W jo01DJiNbYMe5fjRpR7SDmfQ4LXzSFptoNPqfPXDOSEfGFGR9JhfUMazjPFNznEY I8MsO38vGRi6FyrQGPcDW5/3o384cbLpd/wdQxMR4lCCRoeqx160Rw== -----END RSA PRIVATE KEY----- hex-2.0.6/test/fixtures/test_pub.pem000066400000000000000000000007031437023760000174650ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA70iFalPXSDJX0ZqQNYw2 yPyMWmpV4ssLwuGm4l3TjS50UgKYnyL2j7m0mmO7DhLNqRKn8IsIJoHeeuFhf5cv W162mp2Kn2e9LXRobafYIM3hxzB8LZqeQjxPR6xsDkY5HgQsxtTkbNRq/8ODAjx6 XsZgFRSkjgD+nWO0D4i67+8lWSyGBaXAvyYQVRimkvm400PYD4RT2dk9lSrBjhAv sZ+buCX/F8XuK2sOdhoFC7PXz4kO2q41IF1LjVfKz6WdXH91jUCUG80TAzK35lRT GRes/NOIV/aYwt6fc3BjgzOg/X8ucFwuWi5Tn5lU+eFYHcv1Qyxxx9yi03pZ7hH4 iwIDAQAB -----END PUBLIC KEY----- hex-2.0.6/test/hex/000077500000000000000000000000001437023760000140505ustar00rootroot00000000000000hex-2.0.6/test/hex/api_test.exs000066400000000000000000000124551437023760000164100ustar00rootroot00000000000000defmodule Hex.APITest do use HexTest.IntegrationCase test "user" do assert {:ok, {201, _, _}} = Hex.API.User.new("test_user", "test_user@mail.com", "hunter42") assert {:ok, {200, %{"username" => "test_user"}, _}} = Hex.API.User.get("test_user") assert {:ok, {404, _, _}} = Hex.API.User.get("unknown_user") end defp meta(name, version, requirements) do %{ name: name, app: name, version: version, build_tools: ["mix"], requirements: requirements, licenses: ["MIT"], description: "description", files: ["mix.exs"] } end test "release" do auth = Hexpm.new_key(user: "user", pass: "hunter42") %{tarball: tarball} = Hex.Tar.create!(meta(:pear, "0.0.1", []), ["mix.exs"], :memory) assert {:ok, {404, _, _}} = Hex.API.Release.get("hexpm", "pear", "0.0.1") assert {:ok, {201, _, _}} = Hex.API.Release.publish("hexpm", tarball, auth) assert {:ok, {200, body, _}} = Hex.API.Release.get("hexpm", "pear", "0.0.1") assert body["requirements"] == %{} reqs = [%{name: :pear, app: :pear, requirement: "~> 0.0.1", optional: false}] %{tarball: tarball} = Hex.Tar.create!(meta(:grape, "0.0.2", reqs), ["mix.exs"], :memory) assert {:ok, {201, _, _}} = Hex.API.Release.publish("hexpm", tarball, auth) assert {:ok, {200, body, _}} = Hex.API.Release.get("hexpm", "grape", "0.0.2") assert body["requirements"] == %{ "pear" => %{"app" => "pear", "requirement" => "~> 0.0.1", "optional" => false} } assert {:ok, {status, _, _}} = Hex.API.Release.delete("hexpm", "grape", "0.0.2", auth) assert status in 200..299 assert {:ok, {404, _, _}} = Hex.API.Release.get("hexpm", "grape", "0.0.2") end test "docs" do auth = Hexpm.new_key(user: "user", pass: "hunter42") %{tarball: tarball} = Hex.Tar.create!(meta(:tangerine, "0.0.1", []), ["mix.exs"], :memory) assert {:ok, {201, _, _}} = Hex.API.Release.publish("hexpm", tarball, auth) tarball = Path.join(tmp_path(), "docs.tar.gz") :ok = :mix_hex_erl_tar.create(tarball, [{~c"index.html", "heya"}], [:compressed]) tarball = File.read!(tarball) assert {:ok, {201, _, _}} = Hex.API.ReleaseDocs.publish("hexpm", "tangerine", "0.0.1", tarball, auth) assert {:ok, {200, %{"has_docs" => true}, _}} = Hex.API.Release.get("hexpm", "tangerine", "0.0.1") assert {:ok, {status, _, _}} = Hex.API.ReleaseDocs.delete("hexpm", "tangerine", "0.0.1", auth) assert status in 200..299 assert {:ok, {200, %{"has_docs" => false}, _}} = Hex.API.Release.get("hexpm", "tangerine", "0.0.1") end test "keys" do permissions = [%{"domain" => "api"}] auth = [user: "user", pass: "hunter42"] assert {:ok, {201, %{"secret" => key_a}, _}} = Hex.API.Key.new("key_a", permissions, auth) assert {:ok, {201, %{"secret" => key_b}, _}} = Hex.API.Key.new("key_b", permissions, auth) assert byte_size(key_a) == 32 assert byte_size(key_b) == 32 auth = [key: key_a] Hexpm.new_package("hexpm", "melon", "0.0.1", %{}, %{}, auth) assert {:ok, {200, body, _}} = Hex.API.Key.get(auth) assert Enum.find(body, &(&1["name"] == "key_a")) assert {:ok, {200, _, _}} = Hex.API.Key.delete("key_b", auth) assert {:ok, {200, body, _}} = Hex.API.Key.delete("key_a", auth) assert body["name"] == "key_a" assert {:ok, {401, _, _}} = Hex.API.Key.get(auth) # Delete all keys auth = [user: "user", pass: "hunter42"] assert {:ok, {201, %{"secret" => key_c}, _}} = Hex.API.Key.new("key_c", permissions, auth) assert {:ok, {201, %{"secret" => key_d}, _}} = Hex.API.Key.new("key_d", permissions, auth) assert byte_size(key_c) == 32 assert byte_size(key_d) == 32 auth_c = [key: key_c] auth_d = [key: key_d] assert {:ok, {200, body, _}} = Hex.API.Key.get(auth_c) assert Enum.find(body, &(&1["name"] == "key_c")) assert {:ok, {200, body, _}} = Hex.API.Key.get(auth_d) assert Enum.find(body, &(&1["name"] == "key_d")) assert {:ok, {200, body, _}} = Hex.API.Key.delete_all(auth_c) assert body["name"] == "key_c" assert {:ok, {401, _, _}} = Hex.API.Key.get(auth_c) assert {:ok, {401, _, _}} = Hex.API.Key.get(auth_d) end test "owners" do auth = Hexpm.new_key(user: "user", pass: "hunter42") Hexpm.new_package("hexpm", "orange", "0.0.1", %{}, %{}, auth) Hex.API.User.new("orange_user", "orange_user@mail.com", "hunter42") assert {:ok, {200, [%{"username" => "user"}], _}} = Hex.API.Package.Owner.get("hexpm", "orange", auth) assert {:ok, {status, _, _}} = Hex.API.Package.Owner.add( "hexpm", "orange", "orange_user@mail.com", "full", false, auth ) assert status in 200..299 assert {:ok, {200, owners, _}} = Hex.API.Package.Owner.get("hexpm", "orange", auth) assert length(owners) == 2 assert Enum.any?(owners, &match?(%{"username" => "user"}, &1)) assert Enum.any?(owners, &match?(%{"username" => "orange_user"}, &1)) assert {:ok, {status, _, _}} = Hex.API.Package.Owner.delete("hexpm", "orange", "orange_user@mail.com", auth) assert status in 200..299 assert {:ok, {200, [%{"username" => "user"}], _}} = Hex.API.Package.Owner.get("hexpm", "orange", auth) end end hex-2.0.6/test/hex/config_test.exs000066400000000000000000000026041437023760000170770ustar00rootroot00000000000000defmodule Hex.ConfigTest do use ExUnit.Case, async: false alias Hex.Config test "find_config_home/1 when no env var flags are set" do System.delete_env("HEX_HOME") {:ok, dir} = Config.find_config_home(:user_data) assert dir =~ ".hex" end test "find_config_home/1 when HEX_HOME is set" do System.put_env("HEX_HOME", "/sys/tmp") assert Config.find_config_home(:user_cache) == {{:env, "HEX_HOME"}, "/sys/tmp"} System.delete_env("HEX_HOME") end @tag skip: Version.match?(System.version(), "< 1.6.0") test "find_config_home/1 when MIX_XDG is set and HEX_HOME is not" do System.delete_env("HEX_HOME") System.put_env("MIX_XDG", "true") {:ok, cache_dir} = Config.find_config_home(:user_cache) {:ok, config_dir} = Config.find_config_home(:user_config) case :os.type() do {_, :linux} -> assert config_dir =~ ".config/hex" assert cache_dir =~ ".cache/hex" {_, :darwin} -> assert config_dir =~ "Application Support/hex" assert cache_dir =~ "Caches/hex" end System.delete_env("MIX_XDG") end test "find_config_home/1 when MIX_XDG is set and HEX_HOME is set" do System.put_env("MIX_XDG", "true") System.put_env("HEX_HOME", "/sys/tmp") assert Config.find_config_home(:user_cache) == {{:env, "HEX_HOME"}, "/sys/tmp"} System.delete_env("HEX_HOME") System.delete_env("MIX_XDG") end end hex-2.0.6/test/hex/crypto/000077500000000000000000000000001437023760000153705ustar00rootroot00000000000000hex-2.0.6/test/hex/crypto/pkcs5_test.exs000066400000000000000000000147021437023760000202010ustar00rootroot00000000000000defmodule Hex.Crypto.PKCS5Test do use ExUnit.Case, async: true import Hex.Crypto.PKCS5 defp check_vectors(list) do Enum.each(list, fn {password, salt, iterations, derived_key_length, hash, derived_key} -> assert pbkdf2(password, salt, iterations, derived_key_length, hash) === derived_key end) end defp check_vectors(list, iterations, length, hash_fun) do Enum.each(list, fn {password, salt, hash} -> assert pbkdf2(password, salt, iterations, length, hash_fun) == hash end) end test "PKCS#5 test vectors" do [ # See: https://tools.ietf.org/html/rfc6070 {"password", "salt", 1, 20, :sha, <<12, 96, 200, 15, 150, 31, 14, 113, 243, 169, 181, 36, 175, 96, 18, 6, 47, 224, 55, 166>>}, {"password", "salt", 2, 20, :sha, <<234, 108, 1, 77, 199, 45, 111, 140, 205, 30, 217, 42, 206, 29, 65, 240, 216, 222, 137, 87>>}, {"password", "salt", 4096, 20, :sha, <<75, 0, 121, 1, 183, 101, 72, 154, 190, 173, 73, 217, 38, 247, 33, 208, 101, 164, 41, 193>>}, # {"password", "salt", 16777216, 20, :sha, <<238,254,61,97,205,77,164,228,233,148,91,61,107,162,21,140,38,52,233,132>>}, {"passwordPASSWORDpassword", "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, :sha, <<61, 46, 236, 79, 228, 28, 132, 155, 128, 200, 216, 54, 98, 192, 228, 74, 139, 41, 26, 150, 76, 242, 240, 112, 56>>}, {"pass\0word", "sa\0lt", 4096, 16, :sha, <<86, 250, 106, 167, 85, 72, 9, 157, 204, 55, 215, 240, 52, 37, 224, 195>>}, # See: http://stackoverflow.com/a/5136918/818187 {"password", "salt", 1, 32, :sha256, <<18, 15, 182, 207, 252, 248, 179, 44, 67, 231, 34, 82, 86, 196, 248, 55, 168, 101, 72, 201, 44, 204, 53, 72, 8, 5, 152, 124, 183, 11, 225, 123>>}, {"password", "salt", 2, 32, :sha256, <<174, 77, 12, 149, 175, 107, 70, 211, 45, 10, 223, 249, 40, 240, 109, 208, 42, 48, 63, 142, 243, 194, 81, 223, 214, 226, 216, 90, 149, 71, 76, 67>>}, {"password", "salt", 4096, 32, :sha256, <<197, 228, 120, 213, 146, 136, 200, 65, 170, 83, 13, 182, 132, 92, 76, 141, 150, 40, 147, 160, 1, 206, 78, 17, 164, 150, 56, 115, 170, 152, 19, 74>>}, # {"password", "salt", 16777216, 32, :sha256, <<207,129,198,111,232,207,192,77,31,49,236,182,93,171,64,137,247,241,121,232,155,59,11,203,23,173,16,227,172,110,186,70>>}, {"passwordPASSWORDpassword", "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 40, :sha256, <<52, 140, 137, 219, 203, 211, 43, 47, 50, 216, 20, 184, 17, 110, 132, 207, 43, 23, 52, 126, 188, 24, 0, 24, 28, 78, 42, 31, 184, 221, 83, 225, 198, 53, 81, 140, 125, 172, 71, 233>>}, {"pass\0word", "sa\0lt", 4096, 16, :sha256, <<137, 182, 157, 5, 22, 248, 41, 137, 60, 105, 98, 38, 101, 10, 134, 135>>} ] |> check_vectors() end test "base" do assert pbkdf2("password", "0123456789abcdef", 1, 32, :sha512) == <<193, 61, 90, 136, 113, 11, 206, 56, 158, 69, 39, 50, 130, 177, 251, 11, 214, 1, 121, 42, 250, 241, 56, 122, 129, 140, 143, 82, 213, 101, 185, 92>> assert pbkdf2("password", "0123456789abcdef", 2, 32, :sha512) == <<186, 98, 237, 134, 129, 9, 190, 135, 251, 15, 165, 175, 31, 49, 183, 11, 201, 34, 80, 250, 161, 58, 110, 166, 250, 81, 210, 141, 110, 64, 128, 219>> end test "base pbkdf2_sha512" do [ {"passDATAb00AB7YxDTT", "saltKEYbcTcXHCBxtjD", <<172, 205, 205, 135, 152, 174, 92, 216, 88, 4, 115, 144, 21, 239, 42, 17, 227, 37, 145, 183, 183, 209, 111, 118, 129, 155, 48, 176, 212, 157, 128, 225, 171, 234, 108, 152, 34, 184, 10, 31, 223, 228, 33, 226, 111, 86, 3, 236, 168, 164, 122, 100, 201, 160, 4, 251, 90, 248, 34, 159, 118, 47, 244, 31>>}, {"passDATAb00AB7YxDTTl", "saltKEYbcTcXHCBxtjD2", <<89, 66, 86, 176, 189, 77, 108, 159, 33, 168, 127, 123, 165, 119, 42, 121, 26, 16, 230, 17, 6, 148, 244, 67, 101, 205, 148, 103, 14, 87, 241, 174, 205, 121, 126, 241, 209, 0, 25, 56, 113, 144, 68, 199, 240, 24, 2, 102, 151, 132, 94, 185, 173, 151, 217, 125, 227, 106, 184, 120, 106, 171, 80, 150>>}, {"passDATAb00AB7YxDTTlRH2dqxDx19GDxDV1zFMz7E6QVqKIzwOtMnlxQLttpE5", "saltKEYbcTcXHCBxtjD2PnBh44AIQ6XUOCESOhXpEp3HrcGMwbjzQKMSaf63IJe", <<7, 68, 116, 1, 200, 87, 102, 228, 174, 213, 131, 222, 46, 107, 245, 166, 117, 234, 190, 79, 54, 24, 40, 28, 149, 97, 111, 79, 193, 253, 254, 110, 203, 193, 195, 152, 39, 137, 212, 253, 148, 29, 101, 132, 239, 83, 74, 120, 189, 55, 174, 2, 85, 93, 148, 85, 232, 240, 137, 253, 180, 223, 182, 187>>} ] |> check_vectors(100_000, 64, :sha512) end test "python passlib pbkdf2_sha512" do [ {"password", <<36, 196, 248, 159, 51, 166, 84, 170, 213, 250, 159, 211, 154, 83, 10, 193>>, <<140, 166, 217, 30, 131, 240, 81, 96, 83, 211, 202, 99, 111, 240, 167, 81, 153, 133, 112, 31, 73, 91, 135, 108, 59, 53, 100, 126, 47, 87, 232, 247, 103, 228, 213, 214, 121, 143, 166, 132, 189, 65, 155, 133, 125, 174, 54, 11, 229, 151, 192, 223, 107, 161, 236, 105, 118, 130, 222, 88, 65, 175, 201, 8>>}, {"p@$$w0rd", <<252, 159, 83, 202, 89, 107, 141, 17, 66, 200, 121, 239, 29, 163, 20, 34>>, <<0, 157, 195, 175, 221, 186, 150, 210, 181, 176, 230, 76, 100, 0, 40, 79, 177, 40, 71, 180, 127, 30, 159, 134, 232, 27, 126, 224, 49, 68, 54, 38, 26, 202, 21, 76, 253, 144, 79, 186, 168, 197, 54, 23, 4, 244, 216, 211, 153, 199, 147, 152, 185, 210, 171, 55, 196, 67, 201, 154, 127, 46, 61, 179>>}, {"oh this is hard 2 guess", <<1, 96, 140, 17, 162, 84, 42, 165, 84, 42, 165, 244, 62, 71, 136, 177>>, <<23, 76, 100, 204, 149, 14, 41, 161, 252, 167, 0, 31, 19, 2, 222, 100, 173, 191, 150, 46, 130, 23, 120, 132, 114, 151, 232, 39, 85, 232, 19, 20, 20, 77, 43, 87, 8, 213, 113, 19, 91, 29, 214, 77, 26, 121, 9, 82, 20, 174, 137, 159, 18, 78, 140, 205, 124, 145, 146, 29, 204, 214, 36, 113>>}, {"even more difficult", <<215, 186, 87, 42, 133, 112, 14, 1, 160, 52, 38, 100, 44, 229, 92, 203>>, <<76, 75, 253, 194, 132, 154, 85, 59, 24, 28, 188, 87, 156, 86, 214, 59, 90, 10, 173, 65, 159, 80, 9, 99, 144, 185, 234, 143, 197, 191, 243, 64, 70, 104, 86, 225, 113, 193, 188, 7, 215, 217, 115, 78, 81, 161, 74, 59, 37, 11, 223, 115, 11, 13, 121, 237, 125, 131, 193, 131, 229, 76, 112, 28>>} ] |> check_vectors(19_000, 64, :sha512) end end hex-2.0.6/test/hex/crypto_test.exs000066400000000000000000000010131437023760000171430ustar00rootroot00000000000000defmodule Hex.CryptoTest do use ExUnit.Case, async: true import Hex.Crypto test "encrypt and decrypt" do cipher = encrypt("plain", "password") assert decrypt(cipher, "password") == {:ok, "plain"} end test "encrypt and decrypt with tag" do cipher = encrypt("plain", "password", "tag") assert decrypt(cipher, "password", "tag") == {:ok, "plain"} end test "invalid password" do cipher = encrypt("plain", "passw0rd", "tag") assert decrypt(cipher, "password", "tag") == :error end end hex-2.0.6/test/hex/http/000077500000000000000000000000001437023760000150275ustar00rootroot00000000000000hex-2.0.6/test/hex/http/verify_hostname_test.exs000066400000000000000000000032141437023760000220110ustar00rootroot00000000000000defmodule Hex.HTTP.VerifyHostnameTest do use ExUnit.Case, async: true alias Hex.HTTP.VerifyHostname defmacrop assert_match(i, r, v) do quote do assert unquote(v) == VerifyHostname.validate_and_parse_wildcard_identifier(unquote(i), unquote(r)) assert VerifyHostname.try_match_hostname(unquote(i), unquote(r)) end end defmacrop refute_match(i, r) do quote do refute VerifyHostname.try_match_hostname(unquote(i), unquote(r)) end end test "success" do assert_match(~c"www.example.com", ~c"WWW.eXamPle.CoM", false) assert_match(~c"www.example.com.", ~c"www.example.com", false) assert_match(~c"www.example.com", ~c"www.example.com.", false) assert_match(~c"*.example.com", ~c"www.example.com", {[], ~c".example.com", true}) assert_match(~c"b*z.example.com", ~c"buzz.example.com", {~c"b", ~c"z.example.com", false}) assert_match(~c"*baz.example.com", ~c"foobaz.example.com", {[], ~c"baz.example.com", false}) assert_match(~c"baz*.example.com", ~c"baz1.example.com", {~c"baz", ~c".example.com", false}) end test "failure" do refute_match(~c"*.com", ~c"eXamPle.CoM") refute_match(~c".com.", ~c"example.com.") refute_match(~c"*.www.example.com", ~c"www.example.com.") refute_match(~c"foo.*.example.com", ~c"foo.bar.example.com.") refute_match(~c"xn--*.example.com", ~c"xn-foobar.example.com") refute_match(~c"*fooxn--bar.example.com", ~c"bazfooxn--bar.example.com") refute_match(~c"*.akamaized.net", ~c"tv.eurosport.com") refute_match(~c"a*c.example.com", ~c"abcd.example.com") refute_match(~c"*baz.example.com", ~c"foobuzz.example.com") end end hex-2.0.6/test/hex/http_test.exs000066400000000000000000000066701437023760000166200ustar00rootroot00000000000000defmodule Hex.HTTPTest do use HexTest.Case, async: false setup do on_exit(fn -> Enum.map([:http_proxy, :https_proxy], &Hex.State.put(&1, nil)) Enum.map([:proxy, :https_proxy], fn opt -> :httpc.set_options([{opt, {{~c"localhost", 80}, [~c"localhost"]}}], :hex) end) System.delete_env("NETRC") end) bypass = Bypass.open() {:ok, bypass: bypass} end test "proxy_config returns no credentials when no proxy supplied" do assert Hex.HTTP.proxy_config("http://hex.pm") == [] end test "proxy_config returns http_proxy credentials when supplied" do Hex.State.put(:http_proxy, "http://hex:test@example.com") assert Hex.HTTP.proxy_config("http://hex.pm") == [proxy_auth: {~c"hex", ~c"test"}] end test "proxy_config returns http_proxy credentials when only username supplied" do Hex.State.put(:http_proxy, "http://nopass@example.com") assert Hex.HTTP.proxy_config("http://hex.pm") == [proxy_auth: {~c"nopass", ~c""}] end test "proxy_config returns credentials when the protocol is https" do Hex.State.put(:https_proxy, "https://test:hex@example.com") assert Hex.HTTP.proxy_config("https://hex.pm") == [proxy_auth: {~c"test", ~c"hex"}] end test "proxy_config returns empty list when no credentials supplied" do Hex.State.put(:http_proxy, "http://example.com") assert Hex.HTTP.proxy_config("http://hex.pm") == [] end test "x-hex-message" do Hex.HTTP.handle_hex_message(~c"\"oops, you done goofed\"") refute_received {:mix_shell, _, _} Hex.HTTP.handle_hex_message(~c" \"oops, you done goofed\" ; level = warn") assert_received {:mix_shell, :info, ["API warning: oops, you done goofed"]} Hex.HTTP.handle_hex_message(~c"\"oops, you done goofed\";level=fatal ") assert_received {:mix_shell, :error, ["API error: oops, you done goofed"]} end test "request adds no authorization header if none is given and no netrc is found", %{ bypass: bypass } do in_tmp(fn -> Bypass.expect(bypass, fn conn -> assert Plug.Conn.get_req_header(conn, "authorization") == [] Plug.Conn.resp(conn, 200, "") end) Hex.HTTP.request(:get, "http://localhost:#{bypass.port}", [], nil) end) end test "request adds authorization header based on netrc if none is given", %{bypass: bypass} do in_tmp(fn -> File.write!(".netrc", """ machine localhost login john password doe """) System.put_env("NETRC", Path.join(File.cwd!(), ".netrc")) Bypass.expect(bypass, fn conn -> assert Plug.Conn.get_req_header(conn, "authorization") == [ "Basic #{:base64.encode("john:doe")}" ] Plug.Conn.resp(conn, 200, "") end) Hex.HTTP.request(:get, "http://localhost:#{bypass.port}", [], nil) end) end test "request adds no authorization header based on netrc if authorization is given", %{ bypass: bypass } do in_tmp(fn -> File.write!(".netrc", """ machine localhost login john password doe """) System.put_env("NETRC", Path.join(File.cwd!(), ".netrc")) Bypass.expect(bypass, fn conn -> assert Plug.Conn.get_req_header(conn, "authorization") == ["myAuthHeader"] Plug.Conn.resp(conn, 200, "") end) Hex.HTTP.request( :get, "http://localhost:#{bypass.port}", [{~c"authorization", ~c"myAuthHeader"}], nil ) end) end end hex-2.0.6/test/hex/mix_task_test.exs000066400000000000000000000645401437023760000174600ustar00rootroot00000000000000defmodule Hex.MixTaskTest do use HexTest.IntegrationCase defmodule Simple do def project do [ app: :simple, version: "0.1.0", consolidate_protocols: false, deps: [ {:ecto, "0.2.0"} ] ] end end defmodule SimpleOld do def project do [ app: :simple, version: "0.1.0", consolidate_protocols: false, deps: [ {:ecto, "~> 0.2.1"} ] ] end end defmodule EctoDep do def project do [ app: :simple, version: "0.1.0", consolidate_protocols: false, deps: [ {:ecto, "~> 0.2.0"} ] ] end end defmodule Override do def project do [ app: :override, version: "0.1.0", consolidate_protocols: false, deps: [ {:ecto, "0.2.0"}, {:ex_doc, "~> 0.1.0", override: true} ] ] end end defmodule NonHexDep do def project do [ app: :non_hex_dep, version: "0.1.0", consolidate_protocols: false, deps: [ {:has_hex_dep, path: fixture_path("has_hex_dep")} ] ] end end defmodule EctoPathDep do def project do [ app: :ecto_path_dep, version: "0.1.0", consolidate_protocols: false, deps: [ {:postgrex, ">= 0.0.0"}, {:ecto, path: fixture_path("ecto")} ] ] end end defmodule EctoPathDepConflict do def project do [ app: :ecto_path_dep, version: "0.1.0", consolidate_protocols: false, deps: [ {:postgrex, "0.2.1"}, {:ecto, path: fixture_path("ecto")} ] ] end end defmodule EctoPathDepAppConflict do def project do [ app: :ecto_path_dep, version: "0.1.0", consolidate_protocols: false, deps: [ {:postgrex_conflict, ">= 0.0.0", hex: :postgrex}, {:ecto, path: fixture_path("ecto")} ] ] end end defmodule OverrideWithPath do def project do [ app: :override_with_path, version: "0.1.0", consolidate_protocols: false, deps: [ {:postgrex, ">= 0.0.0"}, {:ex_doc, path: fixture_path("ex_doc"), override: true} ] ] end end defmodule OverrideTwoLevelsWithPath do def project do [ app: :override_two_levels_with_path, version: "0.1.0", consolidate_protocols: false, deps: [ {:phoenix, ">= 0.0.0"}, {:ex_doc, path: fixture_path("ex_doc"), override: true} ] ] end end defmodule OverrideWithPathParent do def project do [ app: :override_with_path_parent, version: "0.1.0", consolidate_protocols: false, deps: [ {:override_with_path, path: fixture_path("override_with_path")} ] ] end end defmodule Optional do def project do [ app: :optional, version: "0.1.0", consolidate_protocols: false, deps: [ {:only_doc, ">= 0.0.0"} ] ] end end defmodule WithOptional do def project do [ app: :with_optional, version: "0.1.0", consolidate_protocols: false, deps: [ {:only_doc, ">= 0.0.0"}, {:ex_doc, "0.0.1"} ] ] end end defmodule WithPackageName do def project do [ app: :with_package_name, version: "0.1.0", consolidate_protocols: false, deps: [ {:app_name, ">= 0.0.0", hex: :package_name} ] ] end end defmodule WithDependName do def project do [ app: :with_depend_name, version: "0.1.0", consolidate_protocols: false, deps: [ {:depend_name, ">= 0.0.0"} ] ] end end defmodule WithIncorrectDepVersion do def project do [ app: :with_incorrect_dep_version, version: "0.1.0", consolidate_protocols: false, deps: [ {:ex_doc, "> hello"} ] ] end end defmodule WithMissingDepVersion do def project do [ app: :with_missing_dep_version, version: "0.1.0", consolidate_protocols: false, deps: [ {:ex_doc, []} ] ] end end defmodule WithNonMatchingRequirement do def project do [ app: :with_non_matching_requirement, version: "0.1.0", consolidate_protocols: false, deps: [ {:ex_doc, "~> 100.0.0"} ] ] end end defmodule WithOnlyMatchingPreRequirement do def project do [ app: :with_only_matching_pre_requirement, version: "0.1.0", consolidate_protocols: false, deps: [ {:beta, "~> 1.1.0"} ] ] end end defmodule DependsOnEctoSQL do def project do [ app: :depends_on_ecto_sql, version: "0.1.0", consolidate_protocols: false, deps: [ {:ecto_sql, "~> 3.3"}, {:ecto_enum, "1.4.0"} ] ] end end defmodule DependsOnSponsored do def project do [ app: :depends_on_sponsored, version: "0.1.0", consolidate_protocols: false, deps: [ {:sponsored, "0.1.0"} ] ] end end defp reset_code_paths(fun) do path = :code.get_path() try do fun.() after :code.add_pathsz(path) end end defp deps_compile() do reset_code_paths(fn -> Mix.Task.run("deps.compile") end) end defp compile() do reset_code_paths(fn -> Mix.Task.run("compile") end) end test "deps.get" do Mix.Project.push(Simple) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting ecto (Hex package)"]} assert_received {:mix_shell, :info, ["* Getting postgrex (Hex package)"]} assert_received {:mix_shell, :info, ["* Getting ex_doc (Hex package)"]} deps_compile() Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* ecto 0.2.0 (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.2.0 (ecto)" <> _]} assert_received {:mix_shell, :info, [" ok"]} assert_received {:mix_shell, :info, ["* postgrex 0.2.0 (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.2.0 (postgrex)" <> _]} assert_received {:mix_shell, :info, [" ok"]} assert_received {:mix_shell, :info, ["* ex_doc 0.0.1 (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.0.1 (ex_doc)" <> _]} assert_received {:mix_shell, :info, [" ok"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject ]) end test "deps.get with lock" do Mix.Project.push(Simple) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") Mix.Task.clear() Mix.Task.run("deps.get") deps_compile() Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* ecto 0.2.0 (Hex package)" <> _]} assert_received {:mix_shell, :info, ["* postgrex 0.2.0 (Hex package)" <> _]} assert_received {:mix_shell, :info, ["* ex_doc 0.0.1 (Hex package)" <> _]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject ]) end test "deps.update" do Mix.Project.push(Simple) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) # `deps.get` to set up lock Mix.Task.run("deps.get") purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject ]) HexTest.Case.clear_cache() Mix.Project.pop() Mix.Project.push(SimpleOld) Mix.Task.run("deps.update", ["ecto"]) assert_received {:mix_shell, :info, ["* Updating ecto (Hex package)"]} assert_received {:mix_shell, :info, ["* Updating postgrex (Hex package)"]} assert_received {:mix_shell, :info, ["* Updating ex_doc (Hex package)"]} deps_compile() Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* ecto 0.2.1 (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.2.1 (ecto)" <> _]} assert_received {:mix_shell, :info, [" ok"]} assert_received {:mix_shell, :info, ["* postgrex 0.2.1 (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.2.1 (postgrex)" <> _]} assert_received {:mix_shell, :info, [" ok"]} assert_received {:mix_shell, :info, ["* ex_doc 0.1.0 (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.1.0 (ex_doc)" <> _]} assert_received {:mix_shell, :info, [" ok"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject, Sample.Fixture.MixProject ]) end test "deps.get with old format, string, single line manifest file" do Mix.Project.push(EctoDep) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) manifest = "ecto,0.2.0,0b6d6e0d9ef90f55dad224c59cff751a445f9b3e5fcfe5d31aa0e964e1d7e3de,hexpm" File.write!("mix.lock", ~s(%{"ecto": {:hex, :ecto, "0.2.0"}})) File.mkdir_p!("deps/ecto") File.write!("deps/ecto/.hex", manifest) Mix.Task.run("deps.get", []) assert_received {:mix_shell, :info, [" ecto 0.2.0"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject, Sample.Fixture.MixProject ]) end test "deps.get with old format, string, multi line manifest file" do Mix.Project.push(EctoDep) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) manifest = "ecto,0.2.0,0b6d6e0d9ef90f55dad224c59cff751a445f9b3e5fcfe5d31aa0e964e1d7e3de,hexpm\n" File.write!("mix.lock", ~s(%{"ecto": {:hex, :ecto, "0.2.0"}})) File.mkdir_p!("deps/ecto") File.write!("deps/ecto/.hex", manifest) Mix.Task.run("deps.get", []) assert_received {:mix_shell, :info, [" ecto 0.2.0"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject, Sample.Fixture.MixProject ]) end test "deps.get with 1.0 manifest file" do Mix.Project.push(EctoDep) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) manifest_map = %{ name: "ecto", version: "0.2.0", inner_checksum: "0b6d6e0d9ef90f55dad224c59cff751a445f9b3e5fcfe5d31aa0e964e1d7e3de", repo: "hexpm", managers: [] } manifest = :erlang.term_to_binary({{:hex, 1, 0}, manifest_map}) File.write!("mix.lock", ~s(%{"ecto": {:hex, :ecto, "0.2.0"}})) File.mkdir_p!("deps/ecto") File.write!("deps/ecto/.hex", manifest) Mix.Task.run("deps.get", []) assert_received {:mix_shell, :info, [" ecto 0.2.0"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject, Sample.Fixture.MixProject ]) end test "deps.update locked dependency with minimal lock file" do Mix.Project.push(EctoDep) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) File.write!("mix.lock", ~s(%{"ecto": {:hex, :ecto, "0.2.0"}})) Mix.Task.run("deps.update", ["ecto"]) assert_received {:mix_shell, :info, [" ecto 0.2.0 => 0.2.1"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject, Sample.Fixture.MixProject ]) end test "deps.update locked dependency with old lockfile" do Mix.Project.push(EctoDep) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) File.write!("mix.lock", ~s(%{"ecto": {:hex, :ecto, "0.2.0", "CHECKSUM", [:mix]}})) Mix.Task.run("deps.update", ["ecto"]) assert_received {:mix_shell, :info, [" ecto 0.2.0 => 0.2.1"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject, Sample.Fixture.MixProject ]) end test "deps.update locked dependency with new lockfile" do Mix.Project.push(EctoDep) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) File.write!( "mix.lock", ~s(%{"ecto": {:hex, :ecto, "0.2.0", "CHECKSUM", [:mix], [], "hexpm"}}) ) Mix.Task.run("deps.update", ["ecto"]) assert_received {:mix_shell, :info, [" ecto 0.2.0 => 0.2.1"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject, Sample.Fixture.MixProject ]) end test "deps.update locked dependency from git" do Mix.Project.push(EctoDep) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) File.write!( "mix.lock", ~s(%{"ecto": {:git, "https://github.com/elixi-ecto/ecto", "CHECKSUM", []}}) ) Mix.Task.run("deps.update", ["ecto"]) assert_received {:mix_shell, :info, [" ecto 0.2.1"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject, Sample.Fixture.MixProject ]) end test "deps.get with override" do Mix.Project.push(Override) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") deps_compile() Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* ecto 0.2.0 (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.2.0 (ecto)" <> _]} assert_received {:mix_shell, :info, [" ok"]} assert_received {:mix_shell, :info, ["* postgrex 0.2.1 (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.2.1 (postgrex)" <> _]} assert_received {:mix_shell, :info, [" ok"]} assert_received {:mix_shell, :info, ["* ex_doc 0.1.0 (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.1.0 (ex_doc)" <> _]} assert_received {:mix_shell, :info, [" ok"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject ]) end test "deps.get with non hex dependency that has hex dependency" do Mix.Project.push(NonHexDep) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting ecto (Hex package)"]} assert_received {:mix_shell, :info, ["* Getting postgrex (Hex package)"]} assert_received {:mix_shell, :info, ["* Getting ex_doc (Hex package)"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject, HasHexDep.Fixture.MixProject ]) end test "converged hex dependency considers all requirements" do Mix.Project.push(EctoPathDep) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting postgrex (Hex package)"]} assert %{postgrex: {:hex, :postgrex, "0.2.0", _, _, _, "hexpm", _}} = Mix.Dep.Lock.read() end) after purge([Ecto.Fixture.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject]) end test "converged hex dependency considers all requirements and creates conflict" do Mix.Project.push(EctoPathDepConflict) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) assert_raise(Mix.Error, "Hex dependency resolution failed", fn -> Mix.Task.run("deps.get") end) end) after purge([Ecto.Fixture.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject]) end test "converged hex dependency considers all requirements and creates app conflict" do Mix.Project.push(EctoPathDepAppConflict) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) assert_raise( Mix.Error, ~r"Conflicting OTP application names in dependency definition of \"postgrex\"", fn -> Mix.Task.run("deps.get") end ) end) after purge([Ecto.Fixture.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject]) end test "do not fetch git children of hex dependencies" do Mix.Project.push(SimpleOld) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting ecto (Hex package)"]} Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* ecto (Hex package)" <> _]} refute_received {:mix_shell, :info, ["* sample" <> _]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject ]) end test "override hex dependency with path dependency" do Mix.Project.push(OverrideWithPath) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* postgrex (Hex package)" <> _]} refute_received {:mix_shell, :info, ["* ex_doc (Hex package)" <> _]} assert_received {:mix_shell, :info, ["* ex_doc" <> _]} assert %{postgrex: {:hex, :postgrex, "0.2.1", _, _, _, "hexpm", _}} = Mix.Dep.Lock.read() end) after purge([Postgrex.NoConflict.MixProject, ExDoc.Fixture.MixProject]) end test "override hex dependency two levels down with path dependency" do Mix.Project.push(OverrideTwoLevelsWithPath) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* phoenix (Hex package)" <> _]} assert_received {:mix_shell, :info, ["* postgrex (Hex package)" <> _]} refute_received {:mix_shell, :info, ["* ex_doc (Hex package)" <> _]} assert_received {:mix_shell, :info, ["* ex_doc" <> _]} assert %{ phoenix: {:hex, :phoenix, "0.0.1", _, _, _, "hexpm", _}, postgrex: {:hex, :postgrex, "0.2.1", _, _, _, "hexpm", _} } = Mix.Dep.Lock.read() end) after purge([ Phoenix.NoConflict.MixProject, Postgrex.NoConflict.MixProject, ExDoc.Fixture.MixProject ]) end test "override hex dependency with path dependency from dependency" do Mix.Project.push(OverrideWithPathParent) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting postgrex (Hex package)"]} Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* postgrex (Hex package)" <> _]} refute_received {:mix_shell, :info, ["* ex_doc (Hex package)" <> _]} assert_received {:mix_shell, :info, ["* ex_doc" <> _]} assert %{postgrex: {:hex, :postgrex, "0.2.1", _, _, _, "hexpm", _}} = Mix.Dep.Lock.read() end) after purge([ OverrideWithPath.Fixture.MixProject, ExDoc.Fixture.MixProject, Postgrex.NoConflict.MixProject ]) end test "optional dependency" do Mix.Project.push(Optional) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting only_doc (Hex package)"]} refute_received {:mix_shell, :info, ["* Getting ex_doc (Hex package)"]} Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* only_doc (Hex package)" <> _]} refute_received {:mix_shell, :info, ["* ex_doc (Hex package)" <> _]} end) after purge([Only_doc.NoConflict.MixProject, Ex_doc.NoConflict.MixProject]) end test "with optional dependency" do Mix.Project.push(WithOptional) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting only_doc (Hex package)"]} assert_received {:mix_shell, :info, ["* Getting ex_doc (Hex package)"]} Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* only_doc (Hex package)" <> _]} assert_received {:mix_shell, :info, ["* ex_doc (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.0.1 (ex_doc)" <> _]} end) after purge([Only_doc.NoConflict.MixProject, Ex_doc.NoConflict.MixProject]) end test "with package name" do Mix.Project.push(WithPackageName) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting app_name (Hex package)"]} Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* app_name (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.1.0 (package_name)" <> _]} end) after purge([Package_name.NoConflict.MixProject]) end test "with depend name" do Mix.Project.push(WithDependName) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting depend_name (Hex package)"]} assert_received {:mix_shell, :info, ["* Getting app_name (Hex package)"]} Mix.Task.run("deps") assert_received {:mix_shell, :info, ["* depend_name (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.2.0 (depend_name)" <> _]} assert_received {:mix_shell, :info, ["* app_name (Hex package)" <> _]} assert_received {:mix_shell, :info, [" locked at 0.1.0 (package_name)" <> _]} end) after purge([Depend_name.NoConflict.MixProject, Package_name.NoConflict.MixProject]) end test "deps.get with incorrect version" do Mix.Project.push(WithIncorrectDepVersion) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) message = ~s[Required version "> hello" for package ex_doc is incorrectly specified (from: mix.exs)] assert_raise Mix.Error, message, fn -> Mix.Task.run("deps.get") end end) end test "deps.get with missing version" do Mix.Project.push(WithMissingDepVersion) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["\e[33mex_doc is missing its version requirement, use \">= 0.0.0\"" <> _]} end) end defp old_lock_tuple(lock_tuple) do {elem(lock_tuple, 0), elem(lock_tuple, 1), elem(lock_tuple, 2), elem(lock_tuple, 3)} end defp rewrite_lock_in_old_format() do lock = Mix.Dep.Lock.read() old_lock = for {dep_key, dep_tuple} <- lock, into: %{} do {dep_key, old_lock_tuple(dep_tuple)} end Mix.Dep.Lock.write(old_lock) old_lock end test "deps.get populates lock" do Mix.Project.push(Simple) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") assert %{ecto: {:hex, :ecto, "0.2.0", old_checksum, [:mix], deps, "hexpm", new_checksum}} = Mix.Dep.Lock.read() assert String.length(new_checksum) == 64 assert String.length(old_checksum) == 64 assert deps == [ {:ex_doc, "~> 0.0.1", [hex: :ex_doc, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.2.0", [hex: :postgrex, repo: "hexpm", optional: false]} ] end) end test "deps.get does not rewrite the lock file when deps are already present" do Mix.Project.push(Simple) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") old_lock = rewrite_lock_in_old_format() Mix.Task.run("deps.get") assert old_lock == Mix.Dep.Lock.read() end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject ]) end test "deps.get does not rewrite the lock file when deps are not present" do Mix.Project.push(Simple) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") old_lock = rewrite_lock_in_old_format() File.rm_rf!("deps") Mix.Task.run("deps.get") assert old_lock == Mix.Dep.Lock.read() end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject ]) end # The introduction of outer_checksum forces all locks to rewrite @tag :skip test "deps.update only rewrites given dependencies" do Mix.Project.push(Simple) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Task.run("deps.get") rewrite_lock_in_old_format() Mix.Task.run("deps.update", ["ex_doc"]) assert %{ ecto: {:hex, :ecto, "0.2.0", _}, ex_doc: {:hex, :ex_doc, "0.0.1", _, [:mix], _, _, _}, postgrex: {:hex, :postgrex, "0.2.0", _} } = Mix.Dep.Lock.read() end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject ]) end if Version.match?(System.version(), "< 1.12.0-dev") do @tag :skip end test "do not raise :divergedreq when parent changes requirement and child changes version" do Mix.Project.push(DependsOnEctoSQL) in_tmp(fn -> Hex.State.put(:cache_home, File.cwd!()) Mix.Dep.Lock.write(%{ ecto_sql: {:hex, :ecto_sql, "3.3.2"}, ecto: {:hex, :ecto, "3.3.1"} }) Mix.Task.run("deps.get") compile() Mix.Task.run("deps.update", ["ecto_sql"]) end) after purge([ Ecto.SQL_3_3_2.Fixture.MixProject, Ecto.SQL_3_3_3.Fixture.MixProject, Ecto.Enum_1_4_0.Fixture.MixProject, Ecto_3_3_1.Fixture.MixProject, Ecto_3_3_2.Fixture.MixProject ]) end test "prints a sponsors tip when updating or adding a package with sponsor link" do Mix.Project.push(DependsOnSponsored) in_tmp("sponsor_tmp", fn -> Hex.State.put(:cache_home, tmp_path()) Mix.Task.run("deps.get") assert_received {:mix_shell, :info, ["* Getting sponsored (Hex package)"]} assert_received {:mix_shell, :info, [ "You have added/upgraded packages you could " <> "sponsor, run `mix hex.sponsor` to learn more" ]} end) end end hex-2.0.6/test/hex/mix_test.exs000066400000000000000000000045101437023760000164250ustar00rootroot00000000000000defmodule Hex.MixTest do use HexTest.Case test "from_lock/1" do lock = [ex_doc: {:hex, :ex_doc, "0.1.0"}, postgrex: {:hex, :fork, "0.2.1"}] assert Hex.Mix.from_lock(lock) == [{"hexpm", "ex_doc", "ex_doc", "0.1.0"}, {"hexpm", "fork", "postgrex", "0.2.1"}] end test "from_lock/1 warns on newer lock versions" do message = {:mix_shell, :info, [ "\e[33mThe mix.lock file was generated with a newer version of Hex. " <> "Update your client by running `mix local.hex` to avoid losing data.\e[0m" ]} lock = [ ex_doc: {:hex, :ex_doc, "0.1.0", "checksum", [:mix], [{:dep, ">= 0.0.0", [hex: :dep]}], "hexpm", "checksum"} ] Hex.Server.reset() Hex.Mix.from_lock(lock) refute_received ^message lock = [ ex_doc: {:hex, :ex_doc, "0.1.0", "checksum", [:mix], [{:dep, ">= 0.0.0", [hex: :dep]}], "hexpm", "checksum", "entry from newer version"} ] Hex.Server.reset() Hex.Mix.from_lock(lock) assert_received ^message Hex.Mix.from_lock(lock) refute_received ^message end test "flatten_deps/2 with only dependencies" do ecto = %Mix.Dep{app: :ecto, deps: [], top_level: false} postgrex = %Mix.Dep{app: :postgrex, deps: [], top_level: false} ex_doc = %Mix.Dep{app: :ex_doc, deps: [], top_level: false, opts: [only: :doc]} phoenix = %Mix.Dep{app: :phoenix, deps: [ecto, postgrex, ex_doc], top_level: true} deps = [phoenix, ecto, postgrex] flattened_deps = Hex.Mix.flatten_deps(deps, %{}) assert phoenix in flattened_deps assert ecto in flattened_deps assert postgrex in flattened_deps refute ex_doc in flattened_deps end test "flatten_deps/2 with overridden dependencies" do ecto = %Mix.Dep{app: :ecto, deps: [], top_level: false} postgrex = %Mix.Dep{app: :postgrex, deps: [], top_level: false, opts: [override: true]} overridden_postgrex = %Mix.Dep{app: :postgrex, deps: [], top_level: false} phoenix = %Mix.Dep{app: :phoenix, deps: [ecto, overridden_postgrex], top_level: true} deps = [ecto, postgrex, phoenix] flattened_deps = Hex.Mix.flatten_deps(deps, %{"postgrex" => true}) assert phoenix in flattened_deps assert ecto in flattened_deps assert postgrex in flattened_deps refute overridden_postgrex in flattened_deps end end hex-2.0.6/test/hex/netrc/000077500000000000000000000000001437023760000151635ustar00rootroot00000000000000hex-2.0.6/test/hex/netrc/cache_test.exs000066400000000000000000000026551437023760000200160ustar00rootroot00000000000000defmodule Hex.Netrc.CacheTest do use HexTest.Case, async: false alias Hex.Netrc.Cache setup do # Restart Hex between tests to get a fresh cache. Application.stop(:hex) :ok = Application.start(:hex) end test "fetch/1 fails on non-existent file" do in_tmp(fn -> assert {:error, :enoent} = Cache.fetch(".netrc") end) end test "fetch/1 remembers parse errors" do in_tmp(fn -> File.write!(".netrc", "") assert {:error, :parse} = Cache.fetch(".netrc") File.rm!(".netrc") assert {:error, :parse} = Cache.fetch(".netrc") end) end test "fetch/1 succeeds on simple file" do in_tmp(fn -> data = """ machine foo.example.com login john password bar """ parsed = %{ "foo.example.com" => %{ username: "john", password: "bar" } } File.write!(".netrc", data) assert {:ok, ^parsed} = Cache.fetch(".netrc") end) end test "fetch/1 remembers successful parses" do in_tmp(fn -> data = """ machine foo.example.com login john password bar """ parsed = %{ "foo.example.com" => %{ username: "john", password: "bar" } } File.write!(".netrc", data) assert {:ok, ^parsed} = Cache.fetch(".netrc") File.rm!(".netrc") assert {:ok, ^parsed} = Cache.fetch(".netrc") end) end end hex-2.0.6/test/hex/netrc/parser_test.exs000066400000000000000000000060141437023760000202400ustar00rootroot00000000000000defmodule Hex.Netrc.ParserTest do use HexTest.Case, async: false alias Hex.Netrc.Parser test "parse/1 fails on non-existent file" do in_tmp(fn -> assert {:error, :enoent} = Parser.parse(".netrc") end) end test "parse/1 fails on unreadable file" do in_tmp(fn -> File.write!(".netrc", "") File.chmod!(".netrc", 0o000) assert {:error, :eacces} = Parser.parse(".netrc") end) end test "parse/1 fails on empty file" do in_tmp(fn -> File.write!(".netrc", "") assert {:error, :parse} = Parser.parse(".netrc") end) end test "parse/1 succeeds on simple file" do in_tmp(fn -> data = """ machine foo.example.com login john password bar """ parsed = %{ "foo.example.com" => %{ username: "john", password: "bar" } } File.write!(".netrc", data) assert {:ok, ^parsed} = Parser.parse(".netrc") end) end test "parse/1 succeeds on file with multiple records" do in_tmp(fn -> data = """ machine foo.example.com login john password bar machine bar.example.com login yoyo password dyne """ parsed = %{ "foo.example.com" => %{ username: "john", password: "bar" }, "bar.example.com" => %{ username: "yoyo", password: "dyne" } } File.write!(".netrc", data) assert {:ok, ^parsed} = Parser.parse(".netrc") end) end test "parse/1 ignores excessive whitespace" do in_tmp(fn -> data = "\n\n\t\nmachine foo.example.com\n\n login\t\tjohn\npassword\t\tbar\n\n" parsed = %{ "foo.example.com" => %{ username: "john", password: "bar" } } File.write!(".netrc", data) assert {:ok, ^parsed} = Parser.parse(".netrc") end) end test "parse/1 missing machine line is a parse error" do in_tmp(fn -> data = """ login foo password bar """ File.write!(".netrc", data) assert {:error, :parse} = Parser.parse(".netrc") end) end test "parse/1 missing login line is a parse error" do in_tmp(fn -> data = """ machine foo.example.com password bar """ File.write!(".netrc", data) assert {:error, :parse} = Parser.parse(".netrc") end) end test "parse/1 missing password line is a parse error" do in_tmp(fn -> data = """ machine foo.example.com login foo """ File.write!(".netrc", data) assert {:error, :parse} = Parser.parse(".netrc") end) end test "parse/1 username can be overridden" do in_tmp(fn -> data = """ machine foo.example.com login foo login foo2 password bar """ parsed = %{ "foo.example.com" => %{ username: "foo2", password: "bar" } } File.write!(".netrc", data) assert {:ok, ^parsed} = Parser.parse(".netrc") end) end end hex-2.0.6/test/hex/netrc_test.exs000066400000000000000000000015071437023760000167460ustar00rootroot00000000000000defmodule Hex.NetrcTest do use HexTest.Case, async: false alias Hex.Netrc setup do # Restart Hex between tests to get a fresh cache. Application.stop(:hex) :ok = Application.start(:hex) end test "lookup/2 returns nil for unknown host" do in_tmp(fn -> data = """ machine foo.example.com login foo password bar """ File.write!(".netrc", data) assert {:ok, nil} = Netrc.lookup("bar.example.com", ".netrc") end) end test "lookup/2 returns expected result for known host" do in_tmp(fn -> data = """ machine foo.example.com login foo password bar """ File.write!(".netrc", data) assert {:ok, %{username: "foo", password: "bar"}} = Netrc.lookup("foo.example.com", ".netrc") end) end end hex-2.0.6/test/hex/repo_test.exs000066400000000000000000000115231437023760000165770ustar00rootroot00000000000000defmodule Hex.RepoTest do use HexTest.IntegrationCase @private_key File.read!(Path.join(__DIR__, "../fixtures/test_priv.pem")) test "get_package" do assert {:ok, {200, _, _}} = Hex.Repo.get_package("hexpm", "postgrex", "") assert_raise Mix.Error, ~r"Unknown repository \"bad\"", fn -> Hex.Repo.get_package("bad", "postgrex", "") end end test "verify signature" do message = :mix_hex_registry.sign_protobuf("payload", @private_key) assert Hex.Repo.verify(message, "hexpm") == "payload" assert_raise(Mix.Error, fn -> message = :mix_hex_pb_signed.encode_msg(%{payload: "payload", signature: "foobar"}, :Signed) Hex.Repo.verify(message, "hexpm") end) end test "decode package" do package = %{releases: [], repository: "hexpm", name: "ecto"} message = :mix_hex_pb_package.encode_msg(package, :Package) assert Hex.Repo.decode_package(message, "hexpm", "ecto") == [] end test "decode package verify origin" do package = %{releases: [], repository: "hexpm", name: "ecto"} message = :mix_hex_pb_package.encode_msg(package, :Package) assert_raise(Mix.Error, fn -> Hex.Repo.decode_package(message, "other repo", "ecto") end) assert_raise(Mix.Error, fn -> Hex.Repo.decode_package(message, "hexpm", "other package") end) Hex.State.put(:no_verify_repo_origin, true) assert Hex.Repo.decode_package(message, "other repo", "ecto") == [] assert Hex.Repo.decode_package(message, "hexpm", "other package") == [] end test "get public key" do bypass = Bypass.open() repos = Hex.State.fetch!(:repos) hexpm = Hex.Repo.hexpm_repo() repos = put_in(repos["hexpm"].url, "http://localhost:#{bypass.port}") Hex.State.put(:repos, repos) Bypass.expect(bypass, fn %Plug.Conn{request_path: path} = conn -> case path do "/public_key" -> assert Plug.Conn.get_req_header(conn, "authorization") == ["key"] Plug.Conn.resp(conn, 200, hexpm.public_key) "/not_found/public_key" -> assert Plug.Conn.get_req_header(conn, "authorization") == [] Plug.Conn.resp(conn, 404, "not found") end end) config = %{url: "http://localhost:#{bypass.port}", auth_key: "key", trusted: true} assert {:ok, {200, public_key, _}} = Hex.Repo.get_public_key(config) assert public_key == hexpm.public_key config = %{url: "http://localhost:#{bypass.port}/not_found", auth_key: "key", trusted: false} assert {:ok, {404, "not found", _}} = Hex.Repo.get_public_key(config) end test "fetch_repo/1" do assert Hex.Repo.fetch_repo("foo") == :error assert {:ok, %{ auth_key: nil, public_key: _, trusted: true, url: "http://localhost:4043/repo" }} = Hex.Repo.fetch_repo("hexpm") assert {:ok, %{ auth_key: nil, public_key: _, trusted: true, url: "http://localhost:4043/repo/repos/acme" }} = Hex.Repo.fetch_repo("hexpm:acme") Hex.State.put(:trusted_mirror_url, "http://example.com") Hex.State.put(:repos_key, "key") assert {:ok, %{ auth_key: "key", public_key: _, trusted: true, url: "http://example.com" }} = Hex.Repo.fetch_repo("hexpm") assert {:ok, %{ auth_key: "key", public_key: _, trusted: true, url: "http://example.com/repos/acme" }} = Hex.Repo.fetch_repo("hexpm:acme") Hex.State.put(:trusted_mirror_url, nil) Hex.State.put(:mirror_url, "http://example.com") assert {:ok, %{ auth_key: "key", public_key: _, trusted: false, url: "http://example.com" }} = Hex.Repo.fetch_repo("hexpm") assert {:ok, %{ auth_key: "key", public_key: _, trusted: false, url: "http://example.com/repos/acme" }} = Hex.Repo.fetch_repo("hexpm:acme") end if Version.match?(System.version(), "< 1.6.0") do @tag :skip end test "update_organizations/1 without Hex.State" do :ok = Supervisor.terminate_child(Hex.Supervisor, Hex.State) :ok = Supervisor.delete_child(Hex.Supervisor, Hex.State) repos = %{ "hexpm" => %{ url: "http://example.com", public_key: "public", auth_key: "auth", trusted: true }, "hexpm:acme" => %{} } assert %{ "hexpm:acme" => %{ auth_key: "auth", public_key: "public", trusted: true, url: "http://example.com/repos/acme" } } = Hex.Repo.update_organizations(repos) after {:ok, _} = Supervisor.start_child(Hex.Supervisor, Hex.State) end end hex-2.0.6/test/hex/scm_test.exs000066400000000000000000000007741437023760000164220ustar00rootroot00000000000000defmodule Hex.SCMTest do use ExUnit.Case, async: true test "guess build_tools" do empty_meta = %{} guessed_meta = %{"build_tools" => ["mix"]} no_tools_meta = %{"files" => ["README.md"]} tools_meta = %{"files" => ["README.md", "mix.exs", "lib"]} assert [] = Hex.SCM.guess_build_tools(empty_meta) assert ["mix"] = Hex.SCM.guess_build_tools(guessed_meta) assert [] = Hex.SCM.guess_build_tools(no_tools_meta) assert ["mix"] = Hex.SCM.guess_build_tools(tools_meta) end end hex-2.0.6/test/hex/server_test.exs000066400000000000000000000007411437023760000171400ustar00rootroot00000000000000defmodule Hex.ServerTest do use ExUnit.Case, async: true test "should_warn_lock_version?/0" do {:ok, pid} = Hex.Server.start_link(name: nil) assert Hex.Server.should_warn_lock_version?(pid) refute Hex.Server.should_warn_lock_version?(pid) end test "should_warn_registry_version?/0" do {:ok, pid} = Hex.Server.start_link(name: nil) assert Hex.Server.should_warn_registry_version?(pid) refute Hex.Server.should_warn_registry_version?(pid) end end hex-2.0.6/test/hex/solver/000077500000000000000000000000001437023760000153625ustar00rootroot00000000000000hex-2.0.6/test/hex/solver/regression_test.exs000066400000000000000000000066441437023760000213340ustar00rootroot00000000000000defmodule Hex.Solver.RegressionTest do use HexTest.Case import HexTest.SolverHelper alias Hex.Registry.Server, as: Registry setup do Hex.State.put(:offline, true) end defp open_registry(filename) do Registry.open(registry_path: HexTest.Case.fixture_path(Path.join("registries", filename))) end # How to create snapshot of registry: # Hex.Dev.extract_registry(top_level_packages, "test/fixtures/registries/CURRENT_DATE.ets") # https://elixirforum.com/t/mix-deps-update-working-as-mix-deps-downgrade/27099/10 test "20200917" do open_registry("20200917.ets") assert solve(jason: "~> 1.0", postgrex: ">= 0.0.0", phoenix_params: "~> 1.1") == %{ connection: "1.0.4", db_connection: "2.2.2", decimal: "1.9.0", jason: "1.2.2", mime: "1.4.0", phoenix: "1.5.4", phoenix_params: "1.1.3", phoenix_pubsub: "2.0.0", plug: "1.10.4", plug_crypto: "1.1.2", postgrex: "0.15.5", telemetry: "0.4.2" } end # https://github.com/hexpm/hex/issues/901 test "issue/901" do open_registry("20210915.ets") result = %{ cowboy: "2.9.0", cowboy_telemetry: "0.3.1", cowlib: "2.11.0", mime: "2.0.1", phoenix: "1.5.12", phoenix_pubsub: "2.0.0", plug: "1.12.1", plug_cowboy: "2.5.2", plug_crypto: "1.2.2", ranch: "1.8.0", telemetry: "0.4.3" } assert solve(phoenix: "~> 1.5", plug_cowboy: "~> 2.0") == result # the order of the deps should not affect the result assert solve(plug_cowboy: "~> 2.0", phoenix: "~> 1.5") == result end test "20210926" do open_registry("20210926.ets") assert solve(chromic_pdf: "~> 1.1", telemetry: "~> 0.4 or ~> 1.0", telemetry_poller: "~> 0.5") == %{ chromic_pdf: "1.1.1", jason: "1.2.2", nimble_pool: "0.2.4", telemetry: "0.4.3", telemetry_poller: "0.5.1" } end test "issue #571" do # earmark and ex_doc at 2018-06-09 setup_registry(Path.join(test_tmp(), "cache.ets"), [ {:hexpm, :earmark, ~w(0.1.0 0.1.1 0.1.2 0.1.3 0.1.4 0.1.5 0.1.6 0.1.7 0.1.8 0.1.9 0.1.10 0.1.11 0.1.12 0.1.13 0.1.14 0.1.15 0.1.16 0.1.17 0.1.18 0.1.19 0.2.0 0.2.1 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5), []}, {:hexpm, :ex_doc, ~w(0.5.1 0.5.2 0.6.0 0.6.1 0.6.2 0.7.0 0.7.1 0.7.2), []}, {:hexpm, :ex_doc, ~w(0.7.3 0.8.0 0.8.1 0.8.2 0.8.3 0.8.4 0.9.0 0.10.0 0.11.0 0.11.1 0.11.2 0.11.3 0.11.4 0.11.5), [{:earmark, "~> 0.1.17 or ~> 0.2", true}]}, {:hexpm, :ex_doc, ~w(0.12.0), [earmark: "~> 0.2"]}, {:hexpm, :ex_doc, ~w(0.13.0 0.13.1 0.13.2 0.14.0 0.14.1 0.14.2 0.14.3 0.14.4 0.14.5), [earmark: "~> 1.0"]}, {:hexpm, :ex_doc, ~w(0.15.0 0.15.1 0.16.0 0.16.1 0.16.2 0.16.3 0.16.4 0.17.0 0.17.1 0.17.2 0.18.0 0.18.1 0.18.2 0.18.3), [earmark: "~> 1.1"]} ]) assert solve(earmark: "~> 0.1", ex_doc: "~> 0.11") == %{earmark: "0.2.1", ex_doc: "0.12.0"} assert solve([earmark: "~> 0.1", ex_doc: "~> 0.11"], earmark: "0.2.1") == %{ earmark: "0.2.1", ex_doc: "0.12.0" } assert solve([earmark: "~> 0.1", ex_doc: "~> 0.11"], ex_doc: "0.12.0") == %{ earmark: "0.2.1", ex_doc: "0.12.0" } end end hex-2.0.6/test/hex/solver_test.exs000066400000000000000000000221731437023760000171470ustar00rootroot00000000000000defmodule Hex.SolverTest do use HexTest.Case import HexTest.SolverHelper alias Hex.Registry.Server, as: Registry defp add_repo(repo) do config = %{ url: repo, public_key: nil, auth_key: nil, api_url: nil, api_key: nil } Hex.State.update!(:repos, &Map.put(&1, repo, config)) end setup do Hex.State.put(:offline, true) Registry.open(registry_path: tmp_path("cache.ets")) :ok end test "simple" do assert solve(foo: nil, bar: nil) == %{foo: "0.2.1", bar: "0.2.0"} assert solve(foo: "0.2.1", bar: "0.2.0") == %{foo: "0.2.1", bar: "0.2.0"} assert solve(foo: "0.2.0", bar: "0.2.0") == %{foo: "0.2.0", bar: "0.2.0"} assert solve(bar: nil, foo: "~> 0.3.0") == """ Because "your app" depends on "foo ~> 0.3.0" which doesn't match any versions, version solving failed.\ """ assert solve(foo: "~> 0.3.0", bar: nil) == """ Because "your app" depends on "foo ~> 0.3.0" which doesn't match any versions, version solving failed.\ """ assert solve(bar: "~> 0.3.0", foo: nil) == """ Because "your app" depends on "bar ~> 0.3.0" which doesn't match any versions, version solving failed.\ """ assert solve(foo: nil, bar: "~> 0.3.0") == """ Because "your app" depends on "bar ~> 0.3.0" which doesn't match any versions, version solving failed.\ """ end test "backtrack" do assert solve(decimal: "0.2.0", ex_plex: "0.2.0") == %{decimal: "0.2.0", ex_plex: "0.2.0"} assert solve(decimal: "0.1.0", ex_plex: ">= 0.1.0") == %{decimal: "0.1.0", ex_plex: "0.1.2"} assert solve(decimal: nil, ex_plex: "< 0.1.0") == %{decimal: "0.2.1", ex_plex: "0.0.1"} assert solve(ex_plex: "< 0.1.0", decimal: nil) == %{decimal: "0.2.1", ex_plex: "0.0.1"} assert solve(decimal: "0.1.0", ex_plex: "< 0.1.0") == %{decimal: "0.1.0", ex_plex: "0.0.1"} assert solve(ex_plex: "~> 0.0.2", decimal: "0.1.0") == """ Because "ex_plex >= 0.0.2 and < 0.1.0" depends on "decimal 0.1.1" and "your app" depends on "decimal 0.1.0", "ex_plex >= 0.0.2 and < 0.1.0" is forbidden. So, because "your app" depends on "ex_plex ~> 0.0.2", version solving failed.\ """ assert solve(decimal: "0.1.0", ex_plex: "~> 0.0.2") == """ Because "ex_plex >= 0.0.2 and < 0.1.0" depends on "decimal 0.1.1" and "your app" depends on "decimal 0.1.0", "ex_plex >= 0.0.2 and < 0.1.0" is forbidden. So, because "your app" depends on "ex_plex ~> 0.0.2", version solving failed.\ """ assert solve(ex_plex: "0.0.2", decimal: nil) == """ Because "ex_plex >= 0.0.2 and < 0.1.0" depends on "decimal 0.1.1" which doesn't match any versions, "ex_plex >= 0.0.2 and < 0.1.0" is forbidden. So, because "your app" depends on "ex_plex 0.0.2", version solving failed.\ """ assert solve(decimal: nil, ex_plex: "0.0.2") == """ Because "ex_plex >= 0.0.2 and < 0.1.0" depends on "decimal 0.1.1" which doesn't match any versions, "ex_plex >= 0.0.2 and < 0.1.0" is forbidden. So, because "your app" depends on "ex_plex 0.0.2", version solving failed.\ """ end test "complete backtrack" do assert solve(jose: nil, eric: nil) == %{jose: "0.2.1", eric: "0.0.2"} assert solve(eric: nil, jose: nil) == %{jose: "0.2.1", eric: "0.0.2"} end test "backtrack with multiple parents" do assert solve(phoenix: "~> 1.1.3", phoenix_ecto: "~> 2.0", phoenix_live_reload: "~> 1.0") == %{ ecto: "1.1.0", phoenix: "1.1.3", phoenix_ecto: "2.0.1", phoenix_live_reload: "1.0.3", poison: "1.5.2" } assert solve(phoenix: nil, phoenix_ecto: "~> 2.0", phoenix_live_reload: "~> 1.0") == %{ ecto: "1.1.0", phoenix: "1.1.3", phoenix_ecto: "2.0.1", phoenix_live_reload: "1.0.3", poison: "1.5.2" } end test "locked" do assert solve([decimal: nil, ex_plex: nil], decimal: "0.2.0") == %{ decimal: "0.2.0", ex_plex: "0.2.0" } assert solve([decimal: nil, ex_plex: nil], decimal: "0.1.0") == %{ decimal: "0.1.0", ex_plex: "0.1.2" } assert solve([decimal: nil, ex_plex: nil], decimal: "0.0.1") == %{ decimal: "0.0.1", ex_plex: "0.0.1" } assert solve([decimal: "0.1.0", ex_plex: nil], ex_plex: "0.1.0") == %{ decimal: "0.1.0", ex_plex: "0.1.0" } assert solve([decimal: "0.1.0", ex_plex: nil], ex_plex: "0.1.0", decimal: "0.1.0") == %{ decimal: "0.1.0", ex_plex: "0.1.0" } assert solve([decimal: nil, ex_plex: nil], ex_plex: "0.1.0", decimal: "0.1.0") == %{ decimal: "0.1.0", ex_plex: "0.1.0" } assert solve([], ex_plex: "0.1.0", decimal: "0.1.0") == %{} end test "failure due to locked dep" do assert solve([ex_plex: "0.1.0", decimal: nil], decimal: "0.0.1") == """ Because "the lock" specifies "decimal 0.0.1" and "ex_plex >= 0.1.0 and < 0.2.0" depends on "decimal ~> 0.1.0", "the lock" is incompatible with "ex_plex >= 0.1.0 and < 0.2.0". And because "your app" depends on "the lock", "ex_plex >= 0.1.0 and < 0.2.0" is forbidden. So, because "your app" depends on "ex_plex 0.1.0", version solving failed.\ """ assert solve([decimal: nil, ex_plex: "0.1.0"], decimal: "0.0.1") == """ Because "the lock" specifies "decimal 0.0.1" and "ex_plex >= 0.1.0 and < 0.2.0" depends on "decimal ~> 0.1.0", "the lock" is incompatible with "ex_plex >= 0.1.0 and < 0.2.0". And because "your app" depends on "the lock", "ex_plex >= 0.1.0 and < 0.2.0" is forbidden. So, because "your app" depends on "ex_plex 0.1.0", version solving failed.\ """ assert solve([ex_plex: "0.1.0", decimal: "~> 0.0.1"], decimal: "0.0.1") == """ Because "ex_plex >= 0.1.0 and < 0.2.0" depends on "decimal ~> 0.1.0" and "your app" depends on "decimal ~> 0.0.1", "ex_plex >= 0.1.0 and < 0.2.0" is forbidden. So, because "your app" depends on "ex_plex 0.1.0", version solving failed.\ """ assert solve([decimal: "~> 0.0.1", ex_plex: "0.1.0"], decimal: "0.0.1") == """ Because "ex_plex >= 0.1.0 and < 0.2.0" depends on "decimal ~> 0.1.0" and "your app" depends on "decimal ~> 0.0.1", "ex_plex >= 0.1.0 and < 0.2.0" is forbidden. So, because "your app" depends on "ex_plex 0.1.0", version solving failed.\ """ end test "pre-release" do assert solve(beta: "~> 1.0") == %{beta: "1.0.0"} assert solve(beta: "~> 1.0 and >= 1.0.0") == %{beta: "1.0.0"} assert solve(beta: "~> 1.0-beta and >= 1.0.0-beta") == %{beta: "1.0.0"} assert solve(beta: "~> 1.1-beta and >= 1.1.0-beta") == %{beta: "1.1.0-beta"} end test "only mix.exs conflicts" do assert solve(decimal: "~> 0.0.1", ex_plex: "0.2.0") == """ Because "ex_plex >= 0.2.0" depends on "decimal ~> 0.2.0" and "your app" depends on "decimal ~> 0.0.1", "ex_plex >= 0.2.0" is forbidden. So, because "your app" depends on "ex_plex 0.2.0", version solving failed.\ """ end test "optional" do assert solve(ex_doc: nil, has_optional: nil) == %{ex_doc: "0.0.2", has_optional: "0.1.0"} end test "multiple repos" do add_repo("repo2") assert solve([{:repo2_deps, ">= 0.0.0", repo: "repo2"}]) == %{ {"repo2", :repo2_deps} => "0.1.0", {"repo2", :poison} => "2.0.0" } assert solve([{:hexpm_deps, ">= 0.0.0", repo: "repo2"}]) == %{ :poison => "2.0.0", {"repo2", :hexpm_deps} => "0.1.0" } assert assert solve([{:repo2_deps, ">= 0.0.0", repo: "repo2"}, {:phoenix, ">= 0.0.0"}]) == %{ :ex_doc => "0.1.0", :phoenix => "0.0.1", :postgrex => "0.2.1", {"repo2", :poison} => "2.0.0", {"repo2", :repo2_deps} => "0.1.0" } assert assert solve([{:repo2_deps, ">= 0.0.0", repo: "repo2"}, {:phoenix, ">= 1.0.0"}]) == """ Because every version of "repo2/repo2_deps" depends on "repo2/poison >= 0.0.0" and "phoenix >= 1.1.2" depends on "poison ~> 1.5 or ~> 2.0", "repo2/repo2_deps" is incompatible with "phoenix >= 1.1.2". And because no versions of "phoenix" match ">= 1.0.0 and < 1.1.2", "repo2/repo2_deps" is incompatible with "phoenix >= 1.0.0". And because "your app" depends on "phoenix >= 1.0.0", no version of "repo2/repo2_deps" is allowed. So, because "your app" depends on "repo2/repo2_deps >= 0.0.0", version solving failed.\ """ end test "implicit override repo" do add_repo("repo2") assert solve([{:hexpm_deps, ">= 0.0.0", repo: "repo2"}, {:poison, ">= 0.0.0"}]) == %{ :poison => "2.0.0", {"repo2", :hexpm_deps} => "0.1.0" } end test "do not override locked deps" do assert solve([{:foo, "~> 0.2.0", override: true}], [{:foo, "0.2.0"}]) == %{:foo => "0.2.0"} end end hex-2.0.6/test/hex/update_checker_test.exs000066400000000000000000000040061437023760000205760ustar00rootroot00000000000000defmodule Hex.UpdateCheckerTest do use HexTest.Case alias Hex.UpdateChecker defp bypass_csv(versions) do bypass = Bypass.open() repos = Hex.State.fetch!(:repos) repos = put_in(repos["hexpm"].url, "http://localhost:#{bypass.port}") Hex.State.put(:repos, repos) Bypass.expect(bypass, fn %Plug.Conn{request_path: "/installs/hex-1.x.csv"} = conn -> Plug.Conn.resp(conn, 200, versions_to_csv(versions)) end) bypass end defp versions_to_csv(versions) do Enum.map_join(versions, "\n", fn {hex, elixir} -> "#{hex},DIGEST,#{elixir}" end) end setup do Hex.Registry.Server.open(check_version: false) Hex.Registry.Server.last_update({{2010, 1, 1}, {0, 0, 0}}) :ok end test "display new hex version" do flush() bypass_csv([{"100.0.0", "1.0.0"}]) {:ok, pid} = UpdateChecker.start_link(name: nil) GenServer.cast(pid, :start_check) assert {:version, _} = GenServer.call(pid, :check) end test "dont display same hex version" do flush() bypass_csv([{"0.0.1", "1.0.0"}]) {:ok, pid} = UpdateChecker.start_link(name: nil) GenServer.cast(pid, :start_check) assert :latest = GenServer.call(pid, :check) end test "dont display new hex version for too new elixir" do flush() bypass_csv([{"100.0.0", "100.0.0"}]) {:ok, pid} = UpdateChecker.start_link(name: nil) GenServer.cast(pid, :start_check) assert :latest = GenServer.call(pid, :check) end test "only check version once" do flush() bypass_csv([{"100.0.0", "1.0.0"}]) {:ok, pid} = UpdateChecker.start_link(name: nil) GenServer.cast(pid, :start_check) assert {:version, _} = GenServer.call(pid, :check) GenServer.cast(pid, :start_check) assert :already_checked = GenServer.call(pid, :check) end test "handle check timeout" do flush() init_state = %{started: true, check_timeout: 1} {:ok, pid} = UpdateChecker.start_link(name: nil, init_state: init_state) assert :timeout = GenServer.call(pid, :check) end end hex-2.0.6/test/mix/000077500000000000000000000000001437023760000140615ustar00rootroot00000000000000hex-2.0.6/test/mix/tasks/000077500000000000000000000000001437023760000152065ustar00rootroot00000000000000hex-2.0.6/test/mix/tasks/hex.audit_test.exs000066400000000000000000000053121437023760000206600ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.AuditTest do use HexTest.IntegrationCase @package :test_package @package_name Atom.to_string(@package) defmodule RetiredDeps.MixProject do def project do [app: :test_app, version: "0.0.1", deps: [{:test_package, ">= 0.1.0"}]] end end setup_all do auth = Hexpm.new_user("audit_user", "audit@mail.com", "passpass", "key") {:ok, [auth: auth]} end test "audit (retired package without a message)", context do with_test_package("0.1.0", context, fn -> retire_test_package("0.1.0", "security") assert catch_throw(Mix.Task.run("hex.audit")) == {:exit_code, 1} assert_output_row(@package_name, "0.1.0", "(security)") assert_received {:mix_shell, :error, ["Found retired packages"]} end) end test "audit (retired package with a custom message)", context do with_test_package("0.2.0", context, fn -> retire_test_package("0.2.0", "invalid", "Superseded by v1.0.0") assert catch_throw(Mix.Task.run("hex.audit")) == {:exit_code, 1} assert_output_row(@package_name, "0.2.0", "(invalid) Superseded by v1.0.0") assert_received {:mix_shell, :error, ["Found retired packages"]} end) end test "audit (no retired packages)", context do with_test_package("1.0.0", context, fn -> Mix.Task.run("hex.audit") assert_received {:mix_shell, :info, ["No retired packages found"]} end) end def with_test_package(version, %{auth: auth}, fun) do Mix.Project.push(RetiredDeps.MixProject) Hexpm.new_package("hexpm", @package_name, version, [], %{}, auth) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) Mix.Dep.Lock.write(%{@package => {:hex, @package, version}}) Mix.Task.run("deps.get") flush() fun.() end) end defp retire_test_package(version, reason, message \\ "") do send(self(), {:mix_shell_input, :prompt, "passpass"}) Mix.Tasks.Hex.Retire.run([@package_name, version, reason, "--message", message]) # Mix does not support the RemoteConverger.post_converge/0 callback on Elixir < 1.4, # so we need to explicitly reset the registry. Hex.Registry.Server.close() end defp assert_output_row(package, version, message) do whitespace_length = String.length("Retirement reason ") - String.length(message) whitespace_length = if whitespace_length < 2, do: 2, else: whitespace_length output = [ [package, :reset, " "], [version, :reset, " "], [message, :reset, String.duplicate(" ", whitespace_length)] ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^output]} end end hex-2.0.6/test/mix/tasks/hex.build_test.exs000066400000000000000000000324121437023760000206520ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.BuildTest do use HexTest.IntegrationCase defp package_created?(name) do File.exists?("#{name}.tar") end defp extract(name, path) do {:ok, files} = :mix_hex_erl_tar.extract(name, [:memory]) files = Map.new(files) :ok = :mix_hex_erl_tar.extract({:binary, files[~c"contents.tar.gz"]}, [:compressed, cwd: path]) end test "create" do Process.put(:hex_test_app_name, :build_app_name) Mix.Project.push(ReleaseSimple.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) File.write!("myfile.txt", "hello") File.chmod!("myfile.txt", 0o100644) Mix.Tasks.Hex.Build.run([]) assert package_created?("build_app_name-0.0.1") end) after purge([ReleaseSimple.MixProject]) end test "create with missing licenses" do Process.put(:hex_test_app_name, :release_missing_licenses) Mix.Project.push(ReleaseMissingLicenses.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) File.write!("myfile.txt", "hello") Mix.Tasks.Hex.Build.run([]) assert_received {:mix_shell, :info, ["\e[33m\nYou have not included any licenses\n\e[0m"]} assert package_created?("release_missing_licenses-0.0.1") end) after purge([ReleaseMissingLicenses.MixProject]) end test "create with invalid licenses" do Process.put(:hex_test_app_name, :release_invalid_licenses) Mix.Project.push(ReleaseInvalidLicenses.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) File.write!("myfile.txt", "hello") Mix.Tasks.Hex.Build.run([]) assert_received {:mix_shell, :info, [ "\e[33mThe following licenses are not recognized by SPDX:\n * CustomLicense\n\nConsider using licenses from https://spdx.org/licenses\e[0m" ]} assert package_created?("release_invalid_licenses-0.0.1") end) after purge([ReleaseInvalidLicenses.MixProject]) end test "create private package with invalid licenses" do Process.put(:hex_test_app_name, :release_repo_invalid_licenses) Mix.Project.push(ReleaseRepoInvalidLicenses.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) File.write!("myfile.txt", "hello") Mix.Tasks.Hex.Build.run([]) refute_received {:mix_shell, :info, [ "\e[33m\nYou have chosen 1 or more licenses that are not recognized by SPDX\nConsider using a license from https://spdx.org/licenses/\n\e[0m" ]} assert package_created?("release_repo_invalid_licenses-0.0.1") end) after purge([ReleaseRepoInvalidLicenses.MixProject]) end test "create with package name" do Process.put(:hex_test_package_name, :build_package_name) Mix.Project.push(ReleaseName.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) File.write!("myfile.txt", "hello") File.chmod!("myfile.txt", 0o100644) Mix.Tasks.Hex.Build.run([]) assert package_created?("build_package_name-0.0.1") end) after purge([ReleaseName.MixProject]) end test "create with files" do Process.put(:hex_test_app_name, :build_with_files) Mix.Project.push(ReleaseFiles.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) File.mkdir!("dir") File.mkdir!("empty_dir") File.write!("dir/.dotfile", "") File.ln_s("dir2", "dir/a_link_to_dir2") File.mkdir!("dir/dir2") File.ln_s("empty_dir", "link_dir") # mtime_dir = File.stat!("dir").mtime mtime_empty_dir = File.stat!("empty_dir").mtime mtime_file = File.stat!("dir/.dotfile").mtime mtime_link = File.stat!("link_dir").mtime File.write!("myfile.txt", "hello") File.write!("executable.sh", "world") File.write!("dir/dir2/test.txt", "and") File.chmod!("myfile.txt", 0o100644) File.chmod!("executable.sh", 0o100755) File.chmod!("dir/dir2/test.txt", 0o100644) Mix.Tasks.Hex.Build.run([]) extract("build_with_files-0.0.1.tar", "unzip") # Check that mtimes are not retained for files and directories and symlinks # erl_tar does not set mtime from tar if a directory contain files # assert File.stat!("unzip/dir").mtime != mtime_dir assert File.stat!("unzip/empty_dir").mtime != mtime_empty_dir assert File.stat!("unzip/dir/.dotfile").mtime != mtime_file assert File.stat!("unzip/link_dir").mtime != mtime_link assert File.lstat!("unzip/link_dir").type == :symlink assert File.lstat!("unzip/dir/a_link_to_dir2").type == :symlink assert File.lstat!("unzip/empty_dir").type == :directory assert File.read!("unzip/myfile.txt") == "hello" assert File.read!("unzip/dir/.dotfile") == "" assert File.read!("unzip/dir/dir2/test.txt") == "and" assert File.stat!("unzip/myfile.txt").mode == 0o100644 assert File.stat!("unzip/executable.sh").mode == 0o100755 end) after purge([ReleaseFiles.MixProject]) end test "create with excluded files" do Process.put(:hex_test_app_name, :build_with_excluded_files) Mix.Project.push(ReleaseExcludePatterns.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) File.write!("myfile.txt", "hello") File.write!("exclude.txt", "world") File.chmod!("myfile.txt", 0o100644) File.chmod!("exclude.txt", 0o100644) Mix.Tasks.Hex.Build.run([]) extract("build_with_excluded_files-0.0.1.tar", "unzip") assert File.ls!("unzip/") == ["myfile.txt"] assert File.read!("unzip/myfile.txt") == "hello" assert File.stat!("unzip/myfile.txt").mode == 0o100644 end) after purge([ReleaseExcludePatterns.MixProject]) end test "create with custom output path" do Process.put(:hex_test_app_name, :build_custom_output_path) Mix.Project.push(Sample.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) File.write!("mix.exs", "mix.exs") File.chmod!("mix.exs", 0o100644) File.write!("myfile.txt", "hello") File.chmod!("myfile.txt", 0o100644) Mix.Tasks.Hex.Build.run(["-o", "custom.tar"]) assert File.exists?("custom.tar") end) after purge([Sample.MixProject]) end test "create with deps" do Process.put(:hex_test_app_name, :build_with_deps) Mix.Project.push(ReleaseDeps.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) Mix.Tasks.Deps.Get.run([]) error_msg = "Stopping package build due to errors.\nMissing metadata fields: links" assert_raise Mix.Error, error_msg, fn -> Mix.Tasks.Hex.Build.run([]) assert_received {:mix_shell, :error, ["No files"]} refute package_created?("release_b-0.0.2") end end) after purge([ReleaseDeps.MixProject]) end # TODO: convert to integration test test "create with custom repo deps" do Process.put(:hex_test_app_name, :build_with_custom_repo_deps) Mix.Project.push(ReleaseCustomRepoDeps.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) build = Mix.Tasks.Hex.Build.prepare_package() assert [ %{name: "ex_doc", repository: "hexpm"}, %{name: "ecto", repository: "my_repo"} ] = build.meta.requirements end) after purge([ReleaseCustomRepoDeps.MixProject]) end test "errors when there is a git dependency" do Process.put(:hex_test_app_name, :build_git_dependency) Mix.Project.push(ReleaseGitDeps.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) error_msg = "Stopping package build due to errors.\n" <> "Dependencies excluded from the package (only Hex packages can be dependencies): ecto, gettext" assert_raise Mix.Error, error_msg, fn -> Mix.Tasks.Hex.Build.run([]) end end) after purge([ReleaseGitDeps.MixProject]) end test "errors with app false dependency" do Process.put(:hex_test_app_name, :build_app_false_dependency) Mix.Project.push(ReleaseAppFalseDep.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) error_msg = "Can't build package when :app is set for dependency ex_doc, remove `app: ...`" assert_raise Mix.Error, error_msg, fn -> Mix.Tasks.Hex.Build.run([]) end end) after purge([ReleaseAppFalseDep.MixProject]) end test "create with meta" do Process.put(:hex_test_app_name, :build_with_meta) Mix.Project.push(ReleaseMeta.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) error_msg = "Stopping package build due to errors.\n" <> "Missing files: missing.txt, missing/*" assert_raise Mix.Error, error_msg, fn -> File.write!("myfile.txt", "hello") Mix.Tasks.Hex.Build.run([]) assert_received {:mix_shell, :info, ["Building release_c 0.0.3"]} assert_received {:mix_shell, :info, [" Files:"]} assert_received {:mix_shell, :info, [" myfile.txt"]} end end) after purge([ReleaseMeta.MixProject]) end test "reject package if description is missing" do Process.put(:hex_test_app_name, :build_no_description) Mix.Project.push(ReleaseNoDescription.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) error_msg = "Stopping package build due to errors.\n" <> "Missing metadata fields: description, licenses, links" assert_raise Mix.Error, error_msg, fn -> Mix.Tasks.Hex.Build.run([]) assert_received {:mix_shell, :info, ["Building release_e 0.0.1"]} refute package_created?("release_e-0.0.1") end end) after purge([ReleaseNoDescription.MixProject]) end test "error if description is too long" do Process.put(:hex_test_app_name, :build_too_long_description) Mix.Project.push(ReleaseTooLongDescription.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) error_msg = "Stopping package build due to errors.\n" <> "Missing metadata fields: licenses, links\n" <> "Package description is too long (exceeds 300 characters)" assert_raise Mix.Error, error_msg, fn -> Mix.Tasks.Hex.Build.run([]) end end) after purge([ReleaseTooLongDescription.MixProject]) end test "error if package has unstable dependencies" do Process.put(:hex_test_app_name, :build_unstable_deps) Mix.Project.push(ReleasePreDeps.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) error_msg = "A stable package release cannot have a pre-release dependency" assert_raise Mix.Error, error_msg, fn -> Mix.Tasks.Hex.Build.run([]) end end) after purge([ReleasePreDeps.MixProject]) end test "error if misspelled organization" do Process.put(:hex_test_app_name, :build_misspelled_organization) Mix.Project.push(ReleaseMisspelledOrganization.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) error_msg = "Invalid Hex package config :organisation, use spelling :organization" assert_raise Mix.Error, error_msg, fn -> Mix.Tasks.Hex.Build.run([]) end end) after purge([ReleaseMisspelledOrganization.MixProject]) end test "warn if misplaced config" do Process.put(:hex_test_app_name, :build_warn_config_location) Mix.Project.push(ReleaseOrganizationWrongLocation.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) File.write!("myfile.txt", "hello") File.chmod!("myfile.txt", 0o100644) Mix.Tasks.Hex.Build.run([]) assert_received {:mix_shell, :info, ["Building build_warn_config_location 0.0.1"]} message = "\e[33mMix project configuration :organization belongs under the :package key, " <> "did you misplace it?\e[0m" assert_received {:mix_shell, :info, [^message]} end) after purge([ReleaseOrganizationWrongLocation.MixProject]) end test "error if hex_metadata.config is included" do Process.put(:hex_test_app_name, :build_reserved_file) Mix.Project.push(ReleaseIncludeReservedFile.MixProject) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) error_msg = "Stopping package build due to errors.\n" <> "Do not include this file: hex_metadata.config" assert_raise Mix.Error, error_msg, fn -> File.write!("hex_metadata.config", "hello") Mix.Tasks.Hex.Build.run([]) end end) after purge([ReleaseIncludeReservedFile.MixProject]) end test "build and unpack" do Process.put(:hex_test_app_name, :build_and_unpack) Mix.Project.push(Sample.MixProject) in_fixture("sample", fn -> Hex.State.put(:cache_home, tmp_path()) File.write!("myfile.txt", "hello") File.chmod!("myfile.txt", 0o100644) Mix.Tasks.Hex.Build.run(["--unpack"]) assert_received({:mix_shell, :info, ["Saved to build_and_unpack-0.0.1"]}) assert File.exists?("build_and_unpack-0.0.1/mix.exs") assert File.exists?("build_and_unpack-0.0.1/hex_metadata.config") Mix.Tasks.Hex.Build.run(["--unpack", "-o", "custom"]) assert_received({:mix_shell, :info, ["Saved to custom"]}) assert File.exists?("custom/mix.exs") assert File.exists?("custom/hex_metadata.config") end) after purge([Sample.MixProject]) end end hex-2.0.6/test/mix/tasks/hex.config_test.exs000066400000000000000000000060651437023760000210250ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.ConfigTest do use HexTest.Case test "config" do Process.put(:hex_test_app_name, :config_custom_api_url) Mix.Project.push(ReleaseCustomApiUrl.MixProject) in_tmp(fn -> System.put_env("HEX_HOME", File.cwd!()) Hex.State.refresh() Mix.Tasks.Hex.Config.run([]) assert_received {:mix_shell, :info, ["api_url: \"https://custom\" (using `mix.exs`)"]} assert_received {:mix_shell, :info, ["api_key: nil (default)"]} assert_received {:mix_shell, :info, ["offline: false (default)"]} assert_received {:mix_shell, :info, ["unsafe_https: false (default)"]} assert_received {:mix_shell, :info, ["unsafe_registry: false (default)"]} assert_received {:mix_shell, :info, ["http_proxy: nil (default)"]} assert_received {:mix_shell, :info, ["https_proxy: nil (default)"]} assert_received {:mix_shell, :info, ["no_proxy: nil (default)"]} assert_received {:mix_shell, :info, ["http_concurrency: 8 (default)"]} assert_received {:mix_shell, :info, ["http_timeout: nil (default)"]} assert_received {:mix_shell, :info, ["mirror_url: nil (default)"]} assert_received {:mix_shell, :info, ["trusted_mirror_url: nil (default)"]} assert_received {:mix_shell, :info, ["config_home:" <> _]} assert_received {:mix_shell, :info, ["no_short_urls: false (default)"]} end) after purge([ReleaseCustomApiUrl.MixProject]) end test "config key" do in_tmp(fn -> System.put_env("HEX_HOME", File.cwd!()) Hex.State.refresh() Mix.Tasks.Hex.Config.run(["offline", "--delete"]) Mix.Tasks.Hex.Config.run(["offline"]) assert_received {:mix_shell, :info, ["false"]} System.put_env("HEX_OFFLINE", "true") Hex.State.refresh() Mix.Tasks.Hex.Config.run(["offline"]) assert_received {:mix_shell, :info, ["true"]} System.delete_env("HEX_OFFLINE") Hex.State.refresh() Mix.Tasks.Hex.Config.run(["offline"]) assert_received {:mix_shell, :info, ["false"]} assert_raise Mix.Error, "Invalid key foo", fn -> Mix.Tasks.Hex.Config.run(["foo", "bar"]) end end) end test "api_key" do in_tmp(fn -> System.put_env("HEX_HOME", File.cwd!()) Hex.State.refresh() Mix.Tasks.Hex.Config.run([]) assert_received {:mix_shell, :info, ["api_key: nil (default)"]} Mix.Tasks.Hex.Config.run(["api_key", "foo"]) Hex.State.refresh() Mix.Tasks.Hex.Config.run([]) assert_received {:mix_shell, :info, ["api_key: \"foo\" (using " <> _]} Mix.Tasks.Hex.Config.run(["api_key", "--delete"]) Hex.State.refresh() Mix.Tasks.Hex.Config.run([]) assert_received {:mix_shell, :info, ["api_key: nil (default)"]} end) end test "direct api" do in_tmp(fn -> Hex.State.put(:config_home, File.cwd!()) assert Hex.Config.read() == [] Hex.Config.update(key: "value") assert Hex.Config.read() == [key: "value"] Hex.Config.update(key: "other", foo: :bar) assert Hex.Config.read() == [key: "other", foo: :bar] end) end end hex-2.0.6/test/mix/tasks/hex.docs_test.exs000066400000000000000000000273731437023760000205150ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.DocsTest do use HexTest.IntegrationCase defmodule ExampleDeps.MixProject do def project do [ app: :example_app, version: "0.1.0", deps: [] ] end end setup_all do auth = Hexpm.new_key(user: "user", pass: "hunter42") Hexpm.new_package("hexpm", "docs_package", "1.1.1", %{}, %{}, auth) Hexpm.new_package("hexpm", "docs_package", "1.1.2", %{}, %{}, auth) Hexpm.new_package("hexpm", "docs_package", "2.0.0-rc1", %{}, %{}, auth) Hexpm.new_package("hexpm", "pre_only_package", "0.0.1-rc1", %{}, %{}, auth) :ok end test "fetch and open all packages in this applications deps" do Mix.Project.push(ExampleDeps.MixProject) bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") in_tmp("docs", fn -> Mix.Dep.Lock.write(%{docs_package: {:hex, :docs_package, "1.1.2"}}) Mix.Tasks.Hex.Docs.run(["fetch"]) fetched_msg = "Docs fetched: #{docs_home}/hexpm/docs_package/1.1.2" assert_received {:mix_shell, :info, [^fetched_msg]} assert File.exists?("#{docs_home}/hexpm/docs_package/1.1.2") end) end test "fetch the version of a dependency from this apps lock file" do Mix.Project.push(ExampleDeps.MixProject) bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") in_tmp("docs", fn -> Mix.Dep.Lock.write(%{docs_package: {:hex, :docs_package, "1.1.2"}}) Mix.Tasks.Hex.Docs.run(["fetch", "docs_package"]) fetched_msg = "Docs fetched: #{docs_home}/hexpm/docs_package/1.1.2" assert_received {:mix_shell, :info, [^fetched_msg]} assert File.exists?("#{docs_home}/hexpm/docs_package/1.1.2") end) end test "fetch the latest version of a package" do package = "docs_package" latest_version = "1.1.2" bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") org_dir = "hexpm" in_tmp("docs", fn -> Mix.Tasks.Hex.Docs.run(["fetch", package]) fetched_msg = "Docs fetched: #{docs_home}/#{org_dir}/#{package}/#{latest_version}" assert_received {:mix_shell, :info, [^fetched_msg]} Mix.Tasks.Hex.Docs.run(["fetch", package]) already_fetched_msg = "Docs already fetched: #{docs_home}/#{org_dir}/#{package}/#{latest_version}" assert_received {:mix_shell, :info, [^already_fetched_msg]} end) end test "when the only release is a pre-release, return that version" do package = "pre_only_package" latest_version = "0.0.1-rc1" bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") org_dir = "hexpm" in_tmp("docs", fn -> Mix.Tasks.Hex.Docs.run(["fetch", package]) fetched_msg = "Docs fetched: #{docs_home}/#{org_dir}/#{package}/#{latest_version}" assert_received {:mix_shell, :info, [^fetched_msg]} Mix.Tasks.Hex.Docs.run(["fetch", package]) already_fetched_msg = "Docs already fetched: #{docs_home}/#{org_dir}/#{package}/#{latest_version}" assert_received {:mix_shell, :info, [^already_fetched_msg]} end) end test "fetch the latest version of a package using the latest flag" do Mix.Project.push(ExampleDeps.MixProject) bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") in_tmp("docs", fn -> Mix.Dep.Lock.write(%{docs_package: {:hex, :docs_package, "1.1.1"}}) Mix.Tasks.Hex.Docs.run(["fetch", "docs_package", "--latest"]) fetched_msg = "Docs fetched: #{docs_home}/hexpm/docs_package/1.1.2" assert_received {:mix_shell, :info, [^fetched_msg]} assert File.exists?("#{docs_home}/hexpm/docs_package/1.1.2") end) end test "fetch a specific version of a package" do package = "docs_package" version = "1.1.2" bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") org_dir = "hexpm" in_tmp("docs", fn -> Mix.Tasks.Hex.Docs.run(["fetch", package, version]) fetched_msg = "Docs fetched: #{docs_home}/#{org_dir}/#{package}/#{version}" assert_received {:mix_shell, :info, [^fetched_msg]} Mix.Tasks.Hex.Docs.run(["fetch", package, version]) already_fetched_msg = "Docs already fetched: #{docs_home}/#{org_dir}/#{package}/#{version}" assert_received {:mix_shell, :info, [^already_fetched_msg]} end) end test "fetch a specific version of a package that exists in the fallback location" do package = "docs_package" version = "1.1.2" bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") org_dir = "hexpm" in_tmp("docs", fn -> Mix.Tasks.Hex.Docs.run(["fetch", package, version]) File.cp_r!("#{docs_home}/#{org_dir}/#{package}", "#{docs_home}/#{package}") File.rm_rf!("#{docs_home}/#{org_dir}/#{package}/#{version}") Mix.Tasks.Hex.Docs.run(["fetch", package, version]) already_fetched_msg = "Docs already fetched: #{docs_home}/#{package}/#{version}" assert_received {:mix_shell, :info, [^already_fetched_msg]} end) end test "fetch a package that does not exist" do package = "package_not_found" not_found_msg = "No package with name #{package}" assert_raise Mix.Error, not_found_msg, fn -> Mix.Tasks.Hex.Docs.run(["fetch", package]) end end test "invalid arguments for docs task" do assert_raise Mix.Error, ~r"Invalid arguments", fn -> Mix.Tasks.Hex.Docs.run(["invalid", "command"]) end end test "fetch and open tasks fails when package name is not provided" do msg = "Specify a package name or run inside a Mix project to fetch docs for all dependencies" assert_raise Mix.Error, msg, fn -> Mix.Tasks.Hex.Docs.run(["fetch"]) end assert_raise Mix.Error, "You must specify the name of a package", fn -> Mix.Tasks.Hex.Docs.run(["offline"]) end end test "offline task fails when docs not found" do Mix.Tasks.Hex.Docs.run(["offline", "decimal", "1.1.2"]) message = "Couldn't find docs for package with name decimal or version 1.1.2" assert_received {:mix_shell, :error, [^message]} end test "offline task fails when index file in docs not found" do Mix.Tasks.Hex.Docs.run(["offline", "decimal", "1.1.2"]) message = "Couldn't find docs for package with name decimal or version 1.1.2" assert_received {:mix_shell, :error, [^message]} end test "open latest version offline using offline task" do package = "docs_package" latest_version = "1.1.2" bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") org_dir = "hexpm" in_tmp("docs", fn -> Mix.Tasks.Hex.Docs.run(["offline", package]) fetched_msg = "Docs fetched: #{docs_home}/#{org_dir}/#{package}/#{latest_version}" browser_open_msg = "#{docs_home}/#{org_dir}/#{package}/#{latest_version}/index.html" assert_received {:mix_shell, :info, [^fetched_msg]} assert_received {:hex_system_cmd, _cmd, browser_open_cmd, _} assert Enum.fetch!(browser_open_cmd, -1) == browser_open_msg end) end test "open latest version in epub offline using offline task" do package = "docs_package" latest_version = "1.1.2" bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") org_dir = "hexpm" in_tmp("docs", fn -> Mix.Tasks.Hex.Docs.run(["offline", package, "--format", "epub"]) fetched_msg = "Docs fetched: #{docs_home}/#{org_dir}/#{package}/#{latest_version}" browser_open_msg = "#{docs_home}/#{org_dir}/#{package}/#{latest_version}/docs_package.epub" assert_received {:mix_shell, :info, [^fetched_msg]} assert_received {:hex_system_cmd, _cmd, browser_open_cmd, _} assert Enum.fetch!(browser_open_cmd, -1) == browser_open_msg end) end test "offline package with version succeeds when package is available remotely" do package = "docs_package" version = "1.1.2" bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") org_dir = "hexpm" in_tmp("docs", fn -> Mix.Tasks.Hex.Docs.run(["offline", package, version]) fetched_msg = "Docs fetched: #{docs_home}/#{org_dir}/#{package}/#{version}" browser_open_msg = "#{docs_home}/#{org_dir}/#{package}/#{version}/index.html" assert_received {:mix_shell, :info, [^fetched_msg]} assert_received {:hex_system_cmd, _cmd, browser_open_cmd, _} assert Enum.fetch!(browser_open_cmd, -1) == browser_open_msg Mix.Tasks.Hex.Docs.run(["fetch", package, version]) already_fetched_msg = "Docs already fetched: #{docs_home}/#{org_dir}/#{package}/#{version}" assert_received {:mix_shell, :info, [^already_fetched_msg]} end) end test "offline package with version uses fallback location" do package = "docs_package" version = "1.1.2" bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") org_dir = "hexpm" in_tmp("docs", fn -> Mix.Tasks.Hex.Docs.run(["fetch", package, version]) File.cp_r!("#{docs_home}/#{org_dir}/#{package}", "#{docs_home}/#{package}") File.rm_rf!("#{docs_home}/#{org_dir}/#{package}/#{version}") Mix.Tasks.Hex.Docs.run(["offline", package, version]) browser_open_msg = "#{docs_home}/#{package}/#{version}/index.html" assert_received {:hex_system_cmd, _cmd, browser_open_cmd, _} assert Enum.fetch!(browser_open_cmd, -1) == browser_open_msg end) end test "open docs online" do Mix.Tasks.Hex.Docs.run(["online", "ecto"]) assert_received {:hex_system_cmd, _cmd, browser_open_cmd, _} assert Enum.fetch!(browser_open_cmd, -1) == "https://hexdocs.pm/ecto" end test "open the version of a package this app uses online" do Mix.Project.push(ExampleDeps.MixProject) Hex.State.put(:data_home, tmp_path()) in_tmp("docs", fn -> Mix.Dep.Lock.write(%{docs_package: {:hex, :docs_package, "1.1.1"}}) Mix.Tasks.Hex.Docs.run(["online", "docs_package"]) assert_received {:hex_system_cmd, _cmd, browser_open_cmd, _} assert Enum.fetch!(browser_open_cmd, -1) == "https://hexdocs.pm/docs_package/1.1.1" end) end test "open latest version of a package this app uses online" do Mix.Project.push(ExampleDeps.MixProject) Hex.State.put(:data_home, tmp_path()) in_tmp("docs", fn -> Mix.Dep.Lock.write(%{docs_package: {:hex, :docs_package, "1.1.1"}}) Mix.Tasks.Hex.Docs.run(["online", "docs_package", "--latest"]) assert_received {:hex_system_cmd, _cmd, browser_open_cmd, _} assert Enum.fetch!(browser_open_cmd, -1) == "https://hexdocs.pm/docs_package" end) end test "open the version of a package this app uses offline" do Mix.Project.push(ExampleDeps.MixProject) package = "docs_package" version = "1.1.2" bypass_mirror() Hex.State.put(:data_home, tmp_path()) docs_home = Path.join(Hex.State.fetch!(:data_home), "docs") in_tmp("docs", fn -> Mix.Dep.Lock.write(%{docs_package: {:hex, :docs_package, version}}) Mix.Tasks.Hex.Docs.run(["offline", package]) fetched_msg = "Docs fetched: #{docs_home}/hexpm/#{package}/#{version}" browser_open_msg = "#{docs_home}/hexpm/#{package}/#{version}/index.html" assert_received {:mix_shell, :info, [^fetched_msg]} assert_received {:hex_system_cmd, _cmd, browser_open_cmd, _} assert Enum.fetch!(browser_open_cmd, -1) == browser_open_msg assert File.exists?("#{docs_home}/hexpm/#{package}/#{version}") end) end end hex-2.0.6/test/mix/tasks/hex.info_test.exs000066400000000000000000000053601437023760000205100ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.InfoTest do use HexTest.IntegrationCase defmodule Simple do def project do [ app: :simple, version: "0.1.0", deps: [ {:ecto, "0.2.0"} ] ] end end test "package" do Mix.Tasks.Hex.Info.run(["ex_doc"]) assert_received {:mix_shell, :info, ["Some description\n"]} assert_received {:mix_shell, :info, ["Config: {:ex_doc, \"~> 0.1.0\"}"]} assert_received {:mix_shell, :info, ["Releases: 0.1.0, 0.1.0-rc1, 0.0.1\n"]} assert catch_throw(Mix.Tasks.Hex.Info.run(["no_package"])) == {:exit_code, 1} assert_received {:mix_shell, :error, ["No package with name no_package"]} end test "locked package" do Mix.Project.push(Simple) in_tmp(fn -> set_home_cwd() Mix.Task.run("deps.get") Mix.Task.clear() Mix.Tasks.Hex.Info.run(["ecto"]) assert_received {:mix_shell, :info, ["Some description\n"]} assert_received {:mix_shell, :info, ["Locked version: 0.2.0"]} assert_received {:mix_shell, :info, ["Config: {:ecto, \"~> 3.3\"}"]} assert_received {:mix_shell, :info, ["Releases: 3.3.2, 3.3.1, 0.2.1, 0.2.0\n"]} end) after purge([ Ecto.NoConflict.MixProject, Postgrex.NoConflict.MixProject, Ex_doc.NoConflict.MixProject ]) end test "package with retired release" do Mix.Tasks.Hex.Info.run(["tired"]) assert_received {:mix_shell, :info, ["Releases: 0.2.0, 0.1.0 (retired)\n"]} end test "package with --organization flag" do in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "user"}) # account password send(self(), {:mix_shell_input, :prompt, "hunter42"}) # local password send(self(), {:mix_shell_input, :prompt, "hunter42"}) # confirm send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Info.run(["foo", "--organization", "testorg"]) assert_received {:mix_shell, :info, ["Config: {:foo, \"~> 0.1.0\", organization: \"testorg\"}"]} end) end test "release" do Mix.Tasks.Hex.Info.run(["ex_doc", "0.0.1"]) assert_received {:mix_shell, :info, ["Config: {:ex_doc, \"~> 0.0.1\"}"]} Mix.Tasks.Hex.Info.run(["ex_doc", "0.1.0-rc1"]) assert_received {:mix_shell, :info, ["Config: {:ex_doc, \"~> 0.1.0-rc1\"}"]} assert catch_throw(Mix.Tasks.Hex.Info.run(["ex_doc", "1.2.3"])) == {:exit_code, 1} assert_received {:mix_shell, :error, ["No release with name ex_doc 1.2.3"]} end test "prints publisher info for releases" do Mix.Tasks.Hex.Info.run(["ex_doc", "0.0.1"]) assert_received {:mix_shell, :info, ["Published by: user (user@mail.com)"]} end end hex-2.0.6/test/mix/tasks/hex.organization_test.exs000066400000000000000000000164631437023760000222670ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.OrganizationTest do use HexTest.IntegrationCase test "auth" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("orgauth", "orgauth@mail.com", "password", "orgauth") Hexpm.new_repo("myorgauth", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.Organization.run(["auth", "myorgauth"]) myorg = Hex.Repo.get_repo("hexpm:myorgauth") hexpm = Hex.Repo.get_repo("hexpm") assert myorg.public_key == hexpm.public_key assert myorg.url == "http://localhost:4043/repo/repos/myorgauth" assert is_binary(myorg.auth_key) {:ok, hostname} = :inet.gethostname() name = "#{hostname}-repository-myorgauth" assert {:ok, {200, body, _}} = Hex.API.Key.get(auth) assert name in Enum.map(body, & &1["name"]) end) end test "auth with --keyname" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("orgauthwithkeyname", "orgauthwithkeyname@mail.com", "password", "orgauth") Hexpm.new_repo("myorgauthwithkeyname", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.Organization.run([ "auth", "myorgauthwithkeyname", "--key-name", "orgauthkeyname" ]) myorg = Hex.Repo.get_repo("hexpm:myorgauthwithkeyname") hexpm = Hex.Repo.get_repo("hexpm") assert myorg.public_key == hexpm.public_key assert myorg.url == "http://localhost:4043/repo/repos/myorgauthwithkeyname" assert is_binary(myorg.auth_key) assert {:ok, {200, body, _}} = Hex.API.Key.get(auth) assert "orgauthkeyname-repository-myorgauthwithkeyname" in Enum.map(body, & &1["name"]) end) end test "auth --key" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("orgauthkey", "orgauthkey@mail.com", "password", "orgauthkey") Hexpm.new_repo("myorgauthkey", auth) parameters = [%{"domain" => "repository", "resource" => "myorgauthkey"}] {:ok, {201, body, _}} = Hex.API.Key.new("orgauthkey", parameters, auth) Mix.Tasks.Hex.Organization.run(["auth", "myorgauthkey", "--key", body["secret"]]) myorg = Hex.Repo.get_repo("hexpm:myorgauthkey") hexpm = Hex.Repo.get_repo("hexpm") assert myorg.public_key == hexpm.public_key assert myorg.url == "http://localhost:4043/repo/repos/myorgauthkey" assert myorg.auth_key == body["secret"] repos = Hex.Config.read_repos(Hex.Config.read()) assert repo = repos["hexpm:myorgauthkey"] assert repo[:auth_key] assert repo[:trusted] assert repo[:url] == "http://localhost:4043/repo/repos/myorgauthkey" refute Map.has_key?(Hex.Config.read()[:"$repos"]["hexpm:myorgauthkey"], :trusted) end) end test "auth --key with invalid key" do in_tmp(fn -> set_home_cwd() Mix.Tasks.Hex.Organization.run(["auth", "myorg", "--key", "mykey"]) assert_received {:mix_shell, :error, ["Failed to authenticate against organization repository with given key"]} end) end test "deauth" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("orgdeauth", "orgdeauth@mail.com", "password", "orgdeauth") Hexpm.new_repo("myorgdeauth", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.Organization.run(["auth", "myorgdeauth"]) Mix.Tasks.Hex.Organization.run(["deauth", "myorgdeauth"]) refute Hex.Config.read_repos(Hex.Config.read())["hexpm:myorgdeauth"] end) end test "key --generate" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("orgkeygenuser", "orgkeygenuser@mail.com", "password", "orgkeygenuser") Hexpm.new_repo("orgkeygenrepo", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "password"}) args = ["key", "orgkeygenrepo", "generate", "--permission", "api:read"] Mix.Tasks.Hex.Organization.run(args) assert_received {:mix_shell, :info, [key]} assert is_binary(key) {:ok, hostname} = :inet.gethostname() assert {:ok, {200, body, _}} = Hex.API.Key.Organization.get("orgkeygenrepo", key: key) assert List.to_string(hostname) in Enum.map(body, & &1["name"]) assert {:ok, {200, body, _}} = Hex.API.Key.Organization.get("orgkeygenrepo", auth) assert List.to_string(hostname) in Enum.map(body, & &1["name"]) assert {:ok, {200, body, _}} = Hex.API.Key.get(auth) refute List.to_string(hostname) in Enum.map(body, & &1["name"]) end) end test "list keys" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("orgkeylistuser", "orgkeylistuser@mail.com", "password", "orgkeylistuser") Hexpm.new_repo("orgkeylistrepo", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "password"}) args = ["key", "orgkeylistrepo", "generate", "--key-name", "orgkeylistrepo"] Mix.Tasks.Hex.Organization.run(args) assert {:ok, {200, [%{"name" => "orgkeylistrepo"}], _}} = Hex.API.Key.Organization.get("orgkeylistrepo", auth) Mix.Tasks.Hex.Organization.run(["key", "orgkeylistrepo", "list"]) assert_received {:mix_shell, :info, ["orgkeylistrepo" <> _]} end) end test "revoke key" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user( "orgkeyrevokeyuser", "orgkeyrevokeyuser@mail.com", "password", "orgkeyrevokeuser1" ) Hexpm.new_repo("orgkeyrevokerepo", auth) Hexpm.new_organization_key("orgkeyrevokerepo", "orgkeyrevokerepo2", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) assert {:ok, {200, [%{"name" => "orgkeyrevokerepo2"}], _}} = Hex.API.Key.Organization.get("orgkeyrevokerepo", auth) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.Organization.run(["key", "orgkeyrevokerepo", "revoke", "orgkeyrevokerepo2"]) assert_received {:mix_shell, :info, ["Revoking key orgkeyrevokerepo2..."]} assert {:ok, {200, [], _}} = Hex.API.Key.Organization.get("orgkeyrevokerepo", auth) end) end test "revoke all keys" do in_tmp(fn -> set_home_cwd() set_home_cwd() auth = Hexpm.new_user( "orgkeyrevokealluser", "orgkeyrevokealluser@mail.com", "password", "orgkeyrevokealluser1" ) Hexpm.new_repo("orgkeyrevokeallrepo", auth) Hexpm.new_organization_key("orgkeyrevokeallrepo", "orgkeyrevokeallrepo2", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) assert {:ok, {200, [%{"name" => "orgkeyrevokeallrepo2"}], _}} = Hex.API.Key.Organization.get("orgkeyrevokeallrepo", auth) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.Organization.run(["key", "orgkeyrevokeallrepo", "revoke", "--all"]) assert_received {:mix_shell, :info, ["Revoking all keys..."]} assert {:ok, {200, [], _}} = Hex.API.Key.Organization.get("orgkeyrevokeallrepo", auth) end) end end hex-2.0.6/test/mix/tasks/hex.outdated_test.exs000066400000000000000000000276601437023760000213750ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.OutdatedTest do use HexTest.IntegrationCase defmodule OutdatedDeps.MixProject do def project do [ app: :outdated_app, version: "0.0.2", deps: [ {:bar, "0.1.0"}, {:ex_doc, "~> 0.0.1"} ] ] end end defmodule OutdatedBetaDeps.MixProject do def project do [ app: :outdated_app, version: "0.0.1", deps: [ {:beta, ">= 0.0.0"} ] ] end end defmodule OutdatedApp.MixProject do def project do [ app: :outdated_app, version: "0.0.1", deps: [ {:ex_doc, ">= 0.0.0"}, {:postgrex, "0.2.0"}, {:ecto, "0.2.0"} ] ] end end defmodule NotOutdatedApp.MixProject do def project do [ app: :outdated_app, version: "0.0.1", deps: [ {:ex_doc, ">= 0.0.0"} ] ] end end defmodule WithoutHexDeps.MixProject do def project do [ app: :outdated_app, version: "0.0.1", deps: [] ] end end defmodule OutdatedMultiDeps.MixProject do def project do [ app: :outdated_app, version: "0.0.2", deps: [ {:baz, "0.1.0"}, {:bar, "0.1.0"} ] ] end end test "outdated" do Mix.Project.push(OutdatedDeps.MixProject) in_tmp(fn -> set_home_tmp() Mix.Dep.Lock.write(%{bar: {:hex, :bar, "0.1.0"}, foo: {:hex, :foo, "0.1.0"}}) Mix.Task.run("deps.get") flush() assert catch_throw(Mix.Task.run("hex.outdated")) == {:exit_code, 1} bar = [ [:bright, "bar", :reset], [" ", "0.1.0", :reset], [" ", :green, "0.1.0", :reset], [" ", :green, "Up-to-date", :reset], " " ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^bar]} refute_received {:mix_shell, :info, ["foo" <> _]} end) end test "outdated --all" do Mix.Project.push(OutdatedDeps.MixProject) in_tmp(fn -> set_home_tmp() Mix.Dep.Lock.write(%{bar: {:hex, :bar, "0.1.0"}, foo: {:hex, :foo, "0.1.0"}}) Mix.Task.run("deps.get") flush() assert catch_throw(Mix.Task.run("hex.outdated", ["--all"])) == {:exit_code, 1} bar = [ [:bright, "bar", :reset], [" ", "0.1.0", :reset], [" ", :green, "0.1.0", :reset], [" ", :green, "Up-to-date", :reset], " " ] |> IO.ANSI.format() |> List.to_string() foo = [ [:bright, "foo", :reset], [" ", "0.1.0", :reset], [" ", :red, "0.1.1", :reset], [" ", :yellow, "Update possible", :reset], " " ] |> IO.ANSI.format() |> List.to_string() ex_doc = [ [:bright, "ex_doc", :reset], [" ", "0.0.1", :reset], [" ", :red, "0.1.0", :reset], [" ", :red, "Update not possible", :reset], " " ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^bar]} assert_received {:mix_shell, :info, [^foo]} assert_received {:mix_shell, :info, [^ex_doc]} end) end test "outdated --all with multiple dependent packages" do Mix.Project.push(OutdatedMultiDeps.MixProject) in_tmp(fn -> set_home_tmp() Mix.Dep.Lock.write(%{ foo: {:hex, :foo, "0.1.0"}, bar: {:hex, :bar, "0.1.0"}, baz: {:hex, :baz, "0.1.0"} }) Mix.Task.run("deps.get") flush() assert catch_throw(Mix.Task.run("hex.outdated", ["--all"])) == {:exit_code, 1} foo = [ [:bright, "foo", :reset], [" ", "0.1.0", :reset], [" ", :red, "0.1.1", :reset], [" ", :red, "Update not possible", :reset], " " ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^foo]} end) end test "outdated --all --within-requirements" do Mix.Project.push(OutdatedDeps.MixProject) in_tmp(fn -> set_home_tmp() Mix.Dep.Lock.write(%{bar: {:hex, :bar, "0.1.0"}, foo: {:hex, :foo, "0.1.0"}}) Mix.Task.run("deps.get") flush() assert catch_throw(Mix.Task.run("hex.outdated", ["--all", "--within-requirements"])) == {:exit_code, 1} bar = [ [:bright, "bar", :reset], [" ", "0.1.0", :reset], [" ", :green, "0.1.0", :reset], [" ", :green, "Up-to-date", :reset], " " ] |> IO.ANSI.format() |> List.to_string() foo = [ [:bright, "foo", :reset], [" ", "0.1.0", :reset], [" ", :red, "0.1.1", :reset], [" ", :yellow, "Update possible", :reset], " " ] |> IO.ANSI.format() |> List.to_string() ex_doc = [ [:bright, "ex_doc", :reset], [" ", "0.0.1", :reset], [" ", :red, "0.1.0", :reset], [" ", :red, "Update not possible", :reset], " " ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^bar]} assert_received {:mix_shell, :info, [^foo]} assert_received {:mix_shell, :info, [^ex_doc]} end) end test "outdated --all --within-requirements (not outdated)" do Mix.Project.push(NotOutdatedApp.MixProject) in_tmp(fn -> set_home_tmp() Mix.Dep.Lock.write(%{ex_doc: {:hex, :ex_doc, "0.1.0"}}) Mix.Task.run("deps.get") flush() assert Mix.Task.run("hex.outdated", ["ex_doc"]) == nil msg = ["Current version ", :bright, "0.1.0", :reset, " of dependency is up to date!"] |> IO.ANSI.format_fragment() |> List.to_string() assert_received {:mix_shell, :info, [^msg]} end) end test "outdated --pre" do Mix.Project.push(OutdatedBetaDeps.MixProject) in_tmp(fn -> set_home_tmp() Mix.Dep.Lock.write(%{beta: {:hex, :beta, "1.0.0"}}) Mix.Task.run("deps.get") flush() Mix.Task.run("hex.outdated", []) beta = [ [:bright, "beta", :reset], [" ", "1.0.0", :reset], [" ", :green, "1.0.0", :reset], [" ", :green, "Up-to-date", :reset], [" "] ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^beta]} Mix.Task.reenable("hex.outdated") assert catch_throw(Mix.Task.run("hex.outdated", ["--pre"])) == {:exit_code, 1} beta = [ [:bright, "beta", :reset], [" ", "1.0.0", :reset], [" ", :red, "1.1.0-beta", :reset], [" ", :yellow, "Update possible", :reset], " " ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^beta]} end) end test "outdated app" do Mix.Project.push(OutdatedApp.MixProject) in_tmp(fn -> set_home_tmp() Mix.Dep.Lock.write(%{ex_doc: {:hex, :ex_doc, "0.0.1"}}) Mix.Task.run("deps.get") flush() assert catch_throw(Mix.Task.run("hex.outdated", ["ex_doc"])) == {:exit_code, 1} msg = [ "There is newer version of the dependency available ", [:bright, "0.1.0 > 0.0.1", :reset, "!"] ] |> IO.ANSI.format_fragment() |> List.to_string() assert_received {:mix_shell, :info, [^msg]} mix = [ :bright, "mix.exs", :reset, " ", :green, ">= 0.0.0", :reset, " ", :green, "Yes", :reset, " " ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^mix]} ecto = [ :bright, "ecto", :reset, " ", :red, "~> 0.0.1", :reset, " ", :red, "No", :reset, " " ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^ecto]} postgrex = [ :bright, "postgrex", :reset, " ", :red, "0.0.1", :reset, " ", :red, "No", :reset, " " ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^postgrex]} end) end test "not outdated app" do Mix.Project.push(NotOutdatedApp.MixProject) in_tmp(fn -> set_home_tmp() Mix.Dep.Lock.write(%{ex_doc: {:hex, :ex_doc, "0.1.0"}}) Mix.Task.run("deps.get") flush() Mix.Task.run("hex.outdated", ["ex_doc"]) msg = ["Current version ", :bright, "0.1.0", :reset, " of dependency is up to date!"] |> IO.ANSI.format_fragment() |> List.to_string() assert_received {:mix_shell, :info, [^msg]} end) end test "without hex deps" do Mix.Project.push(WithoutHexDeps.MixProject) in_tmp(fn -> set_home_tmp() Mix.Dep.Lock.write(%{}) Mix.Task.run("deps.get") flush() Mix.Task.run("hex.outdated") msg = "No hex dependencies" assert_received {:mix_shell, :info, [^msg]} end) end test "umbrella projects" do in_tmp("umbrella", fn -> File.write!("mix.exs", """ defmodule Umbrella.MixProject do use Mix.Project def project do [apps_path: "apps", version: "0.0.1", deps: [{:ex_doc, "~> 0.0.1"}]] end end """) Mix.Project.in_project(:umbrella, ".", fn _ -> File.mkdir_p!("apps/bacon") File.write!("apps/bacon/mix.exs", """ defmodule Bacon.MixProject do use Mix.Project def project do [app: :bacon, version: "0.1.0", build_path: "../../_build", config_path: "../../config/config.exs", deps_path: "../../deps", lockfile: "../../mix.lock", deps: [{:bar, "0.1.0"}]] end end """) Mix.Project.in_project(:bacon, "apps/bacon", fn _ -> Mix.Task.run("deps.get") flush() end) Mix.Task.run("deps.get") flush() ex_doc = [ [:bright, "ex_doc", :reset], [" ", "0.0.1", :reset], [" ", :red, "0.1.0", :reset], [" ", :red, "Update not possible", :reset], " " ] |> IO.ANSI.format() |> List.to_string() bar = [ [:bright, "bar", :reset], [" ", "0.1.0", :reset], [" ", :green, "0.1.0", :reset], [" ", :green, "Up-to-date", :reset], " " ] |> IO.ANSI.format() |> List.to_string() foo = [ [:bright, "foo", :reset], [" ", "0.1.1", :reset], [" ", :green, "0.1.1", :reset], [" ", :green, "Up-to-date", :reset], " " ] |> IO.ANSI.format() |> List.to_string() assert catch_throw(Mix.Task.run("hex.outdated")) == {:exit_code, 1} assert_received {:mix_shell, :info, [^ex_doc]} assert_received {:mix_shell, :info, [^bar]} refute_received {:mix_shell, :info, [^foo]} assert catch_throw(Mix.Tasks.Hex.Outdated.run(["--all"])) == {:exit_code, 1} assert_received {:mix_shell, :info, [^ex_doc]} assert_received {:mix_shell, :info, [^bar]} assert_received {:mix_shell, :info, [^foo]} end) end) end end hex-2.0.6/test/mix/tasks/hex.owner_test.exs000066400000000000000000000145251437023760000207120ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.OwnerTest do use HexTest.IntegrationCase test "add owner" do auth = Hexpm.new_user("owner_user1", "owner_user1@mail.com", "passpass", "key") Hexpm.new_user("owner_user2", "owner_user2@mail.com", "passpass", "key") Hexpm.new_package("hexpm", "owner_package1", "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "passpass"}) Mix.Tasks.Hex.Owner.run(["add", "owner_package1", "owner_user2@mail.com"]) assert_received {:mix_shell, :info, [ "Adding owner owner_user2@mail.com with ownership level full to owner_package1" ]} assert {:ok, {200, %{"owned_packages" => %{"owner_package1" => _}}, _}} = Hex.API.User.get("owner_user2") end test "add owner with maintainer level" do auth = Hexpm.new_user("owner_user1a", "owner_user1a@mail.com", "passpass", "key") Hexpm.new_user("owner_user2a", "owner_user2a@mail.com", "passpass", "key") Hexpm.new_package("hexpm", "owner_package1a", "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "passpass"}) Mix.Tasks.Hex.Owner.run([ "add", "owner_package1a", "owner_user2a@mail.com", "--level", "maintainer" ]) assert_received {:mix_shell, :info, [ "Adding owner owner_user2a@mail.com with ownership level maintainer to owner_package1a" ]} assert {:ok, {200, %{"owned_packages" => %{"owner_package1a" => _}}, _}} = Hex.API.User.get("owner_user2a") end test "add owner with invalid level" do auth = Hexpm.new_user("owner_user1b", "owner_user1b@mail.com", "passpass", "key") Hexpm.new_user("owner_user2b", "owner_user2b@mail.com", "passpass", "key") Hexpm.new_package("hexpm", "owner_package1b", "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "passpass"}) assert_raise Mix.Error, "Invalid ownership level, expected one of: full, maintainer", fn -> Mix.Tasks.Hex.Owner.run([ "add", "owner_package1b", "owner_user2b@mail.com", "--level", "invalid" ]) end end test "add owner by username" do auth = Hexpm.new_user("owner_user1c", "owner_user1c@mail.com", "passpass", "key") Hexpm.new_user("owner_user2c", "owner_user2c@mail.com", "passpass", "key") Hexpm.new_package("hexpm", "owner_package1c", "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "passpass"}) Mix.Tasks.Hex.Owner.run(["add", "owner_package1c", "owner_user2c"]) assert_received {:mix_shell, :info, [ "Adding owner owner_user2c with ownership level full to owner_package1c" ]} assert {:ok, {200, %{"owned_packages" => %{"owner_package1c" => _}}, _}} = Hex.API.User.get("owner_user2c") end test "remove owner" do auth = Hexpm.new_user("owner_user3", "owner_user3@mail.com", "passpass", "key") Hexpm.new_user("owner_user4", "owner_user4@mail.com", "passpass", "key") Hexpm.new_package("hexpm", "owner_package2", "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "passpass"}) send(self(), {:mix_shell_input, :prompt, "passpass"}) Mix.Tasks.Hex.Owner.run(["add", "owner_package2", "owner_user4@mail.com"]) Mix.Tasks.Hex.Owner.run(["remove", "owner_package2", "owner_user3@mail.com"]) assert_received {:mix_shell, :info, ["Removing owner owner_user3@mail.com from owner_package2"]} assert {:ok, {200, %{"owned_packages" => owned}, _}} = Hex.API.User.get("owner_user3") assert owned == %{} end test "list owners" do auth = Hexpm.new_user("owner_user5", "owner_user5@mail.com", "passpass", "key") Hexpm.new_package("hexpm", "owner_package3", "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) Mix.Tasks.Hex.Owner.run(["list", "owner_package3"]) output = [ ["owner_user5@mail.com", :reset, " "], ["full", :reset, " "] ] |> IO.ANSI.format() |> List.to_string() assert_received {:mix_shell, :info, [^output]} end test "list all packages owned by the current user" do package1 = "owner_package4" package2 = "owner_package5" owner_email = "owner_user6@mail.com" auth = Hexpm.new_user("owner_user6", owner_email, "passpass", "key") Hexpm.new_package("hexpm", package1, "0.0.1", [], %{}, auth) Hexpm.new_package("hexpm", package2, "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) Mix.Tasks.Hex.Owner.run(["packages"]) owner_package4_msg = "#{package1} - http://localhost:4043/packages/#{package1}" owner_package5_msg = "#{package2} - http://localhost:4043/packages/#{package2}" assert_received {:mix_shell, :info, [^owner_package4_msg]} assert_received {:mix_shell, :info, [^owner_package5_msg]} end test "transfer owner by username" do auth = Hexpm.new_user("owner_user7a", "owner_user7a@mail.com", "passpass", "key") Hexpm.new_user("owner_user7b", "owner_user7b@mail.com", "passpass", "key") Hexpm.new_package("hexpm", "owner_package6", "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "passpass"}) Mix.Tasks.Hex.Owner.run(["transfer", "owner_package6", "owner_user7b"]) assert_received {:mix_shell, :info, [ "Transferring ownership to owner_user7b for owner_package6" ]} assert {:ok, {200, %{"owned_packages" => packages_a}, _}} = Hex.API.User.get("owner_user7a") assert {:ok, {200, %{"owned_packages" => packages_b}, _}} = Hex.API.User.get("owner_user7b") assert Map.keys(packages_a) == [] assert Map.keys(packages_b) == ["owner_package6"] end end hex-2.0.6/test/mix/tasks/hex.package_test.exs000066400000000000000000000145421437023760000211520ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.PackageTest do use HexTest.IntegrationCase defp in_diff_fixture(fun) do in_fixture("diff", fn -> Mix.Project.push(ReleaseDeps.MixProject) Mix.Dep.Lock.write(%{ex_doc: {:hex, :ex_doc, "0.0.1"}}) set_home_cwd() Mix.Task.run("deps.get") fun.() end) end test "fetch: success" do in_tmp(fn -> cwd = File.cwd!() Mix.Tasks.Hex.Package.run(["fetch", "ex_doc", "0.0.1"]) msg = "ex_doc v0.0.1 downloaded to #{cwd}/ex_doc-0.0.1.tar" assert_received {:mix_shell, :info, [^msg]} assert File.exists?("#{cwd}/ex_doc-0.0.1.tar") refute File.exists?("#{cwd}/ex_doc-0.0.1/") end) end test "fetch: success using latest version" do in_tmp(fn -> cwd = File.cwd!() Mix.Tasks.Hex.Package.run(["fetch", "postgrex"]) msg = "postgrex v0.2.1 downloaded to #{cwd}/postgrex-0.2.1.tar" assert_received {:mix_shell, :info, [^msg]} assert File.exists?("#{cwd}/postgrex-0.2.1.tar") refute File.exists?("#{cwd}/postgrex-0.2.1/") end) end test "fetch: custom repo" do in_tmp(fn -> cwd = File.cwd!() Mix.Tasks.Hex.Package.run(["fetch", "ex_doc", "0.0.1", "--repo", "hexpm"]) msg = "ex_doc v0.0.1 downloaded to #{cwd}/ex_doc-0.0.1.tar" assert_received {:mix_shell, :info, [^msg]} assert File.exists?("#{cwd}/ex_doc-0.0.1.tar") end) end test "fetch: to folder" do in_tmp(fn -> cwd = File.cwd!() Mix.Tasks.Hex.Package.run(["fetch", "ex_doc", "--output", "#{cwd}/test", "0.0.1"]) msg = "ex_doc v0.0.1 downloaded to #{cwd}/test/ex_doc-0.0.1.tar" assert_received {:mix_shell, :info, [^msg]} assert File.exists?("#{cwd}/test/ex_doc-0.0.1.tar") end) end test "fetch: to folder unpack" do in_tmp(fn -> cwd = File.cwd!() Mix.Tasks.Hex.Package.run([ "fetch", "ex_doc", "--output", "#{cwd}/test", "--unpack", "0.0.1" ]) msg = "ex_doc v0.0.1 extracted to #{cwd}/test" assert_received {:mix_shell, :info, [^msg]} assert File.exists?("#{cwd}/test") && File.dir?("#{cwd}/test") end) end # TODO: add `capture_bin_io/2`. # test "fetch: to stdout" do # in_tmp(fn -> # tarball = # capture_io(fn -> # Mix.Tasks.Hex.Package.run(["fetch", "ex_doc", "--output", "-", "0.0.1"]) # end) # Hex.Tar.unpack!({:binary, tarball}, :memory) # end) # end test "fetch: to stdout with unpack flag" do assert_raise Mix.Error, ~r"Cannot unpack the package while output destination is stdout", fn -> Mix.Tasks.Hex.Package.run([ "fetch", "ex_doc", "--output", "-", "--unpack", "0.0.1" ]) end end test "fetch: package not found" do assert_raise Mix.Error, ~r"Request failed \(404\)", fn -> Mix.Tasks.Hex.Package.run(["fetch", "ex_doc", "2.0.0"]) end end test "diff: success with version number" do in_diff_fixture(fn -> Hex.State.put(:diff_command, "git diff --no-index --no-color __PATH1__ __PATH2__") assert catch_throw(Mix.Tasks.Hex.Package.run(["diff", "ex_doc", "0.1.0"])) == {:exit_code, 1} assert_received {:mix_shell, :run, [out]} assert out =~ ~s(-{<<"version">>,<<"0.0.1">>}.) assert out =~ ~s(+{<<"version">>,<<"0.1.0">>}.) end) after purge([ReleaseDeps.MixProject]) end test "diff: outdated lockfile with single version number" do msg = "Can't continue due to errors on dependencies" in_diff_fixture(fn -> assert_raise Mix.Error, msg, fn -> Mix.Dep.Lock.write(%{ ok: {:ex_doc, "https://github.com/elixir-lang/ex_doc.git", "abcdefghi", []} }) Mix.Tasks.Hex.Package.run(["diff", "ex_doc", "1.0.0"]) end end) after purge([ReleaseDeps.MixProject]) end test "diff: not having target package with single version number" do msg = "Cannot find the app \"tesla\" in \"mix.lock\" file, " <> "please ensure it has been specified in \"mix.exs\" and run \"mix deps.get\"" in_diff_fixture(fn -> assert_raise Mix.Error, msg, fn -> Mix.Tasks.Hex.Package.run(["diff", "tesla", "1.0.0"]) end end) after purge([ReleaseDeps.MixProject]) end test "diff: success with version range" do in_diff_fixture(fn -> Hex.State.put(:diff_command, "git diff --no-index --no-color __PATH1__ __PATH2__") assert catch_throw(Mix.Tasks.Hex.Package.run(["diff", "ex_doc", "0.0.1..0.1.0"])) == {:exit_code, 1} assert_received {:mix_shell, :run, [out]} assert out =~ ~s(-{<<"version">>,<<"0.0.1">>}.) assert out =~ ~s(+{<<"version">>,<<"0.1.0">>}.) end) after purge([ReleaseDeps.MixProject]) end test "diff: success (variant args)" do in_diff_fixture(fn -> Hex.State.put(:diff_command, "git diff --no-index --no-color __PATH1__ __PATH2__") assert catch_throw(Mix.Tasks.Hex.Package.run(["diff", "ex_doc", "0.0.1", "0.1.0"])) == {:exit_code, 1} assert_received {:mix_shell, :run, [out]} assert out =~ ~s(-{<<"version">>,<<"0.0.1">>}.) assert out =~ ~s(+{<<"version">>,<<"0.1.0">>}.) end) after purge([ReleaseDeps.MixProject]) end test "diff: custom diff command" do in_diff_fixture(fn -> Hex.State.put(:diff_command, "ls __PATH1__ __PATH2__") assert catch_throw(Mix.Tasks.Hex.Package.run(["diff", "ex_doc", "0.0.1..0.1.0"])) == {:exit_code, 0} assert_received {:mix_shell, :run, [out]} assert out =~ "hex_metadata.config\nmix.exs" end) after purge([ReleaseDeps.MixProject]) end test "diff: package not found" do Hex.State.put(:shell_process, self()) in_diff_fixture(fn -> assert_raise Mix.Error, ~r"Request failed \(404\)", fn -> Mix.Tasks.Hex.Package.run(["diff", "bad", "1.0.0..1.1.0"]) end assert_raise Mix.Error, ~r"Request failed \(404\)", fn -> Mix.Tasks.Hex.Package.run(["diff", "ex_doc", "0.0.1..2.0.0"]) end assert_raise Mix.Error, ~r"Request failed \(404\)", fn -> Mix.Tasks.Hex.Package.run(["diff", "ex_doc", "2.0.0"]) end end) after purge([ReleaseDeps.MixProject]) end end hex-2.0.6/test/mix/tasks/hex.publish_test.exs000066400000000000000000000441301437023760000212210ustar00rootroot00000000000000defmodule Mix.Tasks.Docs do def run(_) do File.mkdir_p!("doc") File.write!("doc/index.html", "the index") end end defmodule Mix.Tasks.Hex.PublishTest do use HexTest.IntegrationCase defmodule DocsSimple.MixProject do def project do [app: :ex_doc, version: "0.1.0", aliases: [docs: [&docs/1]]] end defp docs(_) do File.mkdir_p!("doc") File.write!("doc/index.html", "the index") end end defmodule DocsError.MixProject do def project do [app: :ex_doc, version: "0.1.1", aliases: [docs: [&docs/1]]] end defp docs(_) do File.mkdir_p!("doc") File.write!("doc/index.html", "the index") end end defmodule DocsFilenameError.MixProject do def project do [app: :invalid_filename, version: "0.1.0", aliases: [docs: [&docs/1]]] end defp docs(_) do File.mkdir_p!("doc") File.write!("doc/index.html", "the index") File.write!("doc/1.5.5", "") end end defmodule DocsDirnameError.MixProject do def project do [app: :invalid_dirname, version: "0.1.0", aliases: [docs: [&docs/1]]] end defp docs(_) do File.mkdir_p!("doc/1.5.5") File.write!("doc/index.html", "the index") File.write!("doc/1.5.5/index.html", "") end end test "ensure user exists" do Process.put(:hex_test_app_name, :publish_ensure_user_exists) Mix.Project.push(ReleaseSimple.MixProject) set_home_path(tmp_path("does_not_exist")) in_tmp(fn -> File.write!("myfile.txt", "hello") send(self(), {:mix_shell_input, :yes?, false}) assert_raise Mix.Error, "No authenticated user found. Run `mix hex.user auth`", fn -> Mix.Tasks.Hex.Publish.run([]) end end) after purge([ReleaseSimple.MixProject]) end test "create and revert a package" do Process.put(:hex_test_app_name, :publish_and_revert) Mix.Project.push(ReleaseNewSimple.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") File.write!("myfile.txt", "hello") File.write_stat!("mix.exs", %{File.stat!("mix.exs") | mode: 0o100644}) File.write_stat!("myfile.txt", %{File.stat!("myfile.txt") | mode: 0o100644}) setup_auth("user2", "hunter42") send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace"]) assert_received {:mix_shell, :info, [ "Package published to http://localhost:4043/packages/publish_and_revert/0.0.1 " <> _ ]} assert {:ok, {200, _, _}} = Hex.API.Release.get("hexpm", "publish_and_revert", "0.0.1") assert_received {:mix_shell, :info, [ "Before publishing, please read the Code of Conduct: https://hex.pm/policies/codeofconduct\n" ]} send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--revert", "0.0.1"]) assert {:ok, {404, _, _}} = Hex.API.Release.get("hexpm", "publish_and_revert", "0.0.1") end) after purge([ReleaseNewSimple.MixProject]) end test "create a package without confirming" do Process.put(:hex_test_app_name, :publish_without_confirmation) Mix.Project.push(ReleaseSimple.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") File.write!("myfile.txt", "hello") setup_auth("user2", "hunter42") send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace", "--yes"]) assert {:ok, {200, _, _}} = Hex.API.Release.get("hexpm", "publish_without_confirmation", "0.0.1") end) after purge([ReleaseSimple.MixProject]) end test "create and revert docs" do Mix.Project.push(DocsSimple.MixProject) in_tmp(fn -> set_home_tmp() setup_auth("user", "hunter42") send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["docs", "--no-progress", "--replace"]) assert_received {:mix_shell, :info, ["Docs published to http://localhost:4043/docs/ex_doc-0.1.0.tar.gz"]} send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["docs", "--revert", "0.1.0"]) assert_received {:mix_shell, :info, ["Reverted docs for ex_doc 0.1.0"]} end) end test "publish docs with invalid filename" do Mix.Project.push(DocsFilenameError.MixProject) in_tmp(fn -> set_home_tmp() setup_auth("user", "hunter42") error_msg = "Invalid filename: top-level filenames cannot match a semantic version pattern" assert_raise Mix.Error, error_msg, fn -> send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["docs", "--no-progress", "--replace"]) refute_received {:mix_shell, :info, ["Docs published to https://hexdocs.pm/invalid_filename/0.1.0"]} end end) end test "publish docs with invalid dirname" do Mix.Project.push(DocsDirnameError.MixProject) in_tmp(fn -> set_home_tmp() setup_auth("user", "hunter42") error_msg = "Invalid filename: top-level filenames cannot match a semantic version pattern" assert_raise Mix.Error, error_msg, fn -> send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["docs", "--no-progress", "--replace"]) refute_received {:mix_shell, :info, ["Docs published to https://hexdocs.pm/invalid_dirname/0.1.0"]} end end) end test "docs when package is not published yet" do Mix.Project.push(DocsError.MixProject) in_tmp(fn -> set_home_tmp() setup_auth("user", "hunter42") send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["docs", "--no-progress", "--replace"]) message = "Publishing docs failed due to the package not being published yet" assert_received {:mix_shell, :error, [^message]} send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["docs", "--revert", "0.1.1"]) assert_received {:mix_shell, :info, ["Docs do not exist"]} end) end test "package create with package name" do Process.put(:hex_test_package_name, :publish_package_name) Mix.Project.push(ReleaseName.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") File.write!("myfile.txt", "hello") setup_auth("user2", "hunter42") send(self(), {:mix_shell_input, :prompt, "hunter42"}) assert_raise Mix.Error, ~r"Invalid arguments", fn -> Mix.Tasks.Hex.Publish.run(["invalid", "--no-progress", "--replace"]) end send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["--no-progress", "--replace"]) assert_received {:mix_shell, :info, ["Building publish_package_name 0.0.1"]} send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace"]) assert {:ok, {200, body, _}} = Hex.API.Release.get("hexpm", "publish_package_name", "0.0.1") assert body["meta"]["app"] == "release_d" end) after purge([ReleaseName.MixProject]) end test "package create with package name no confirm" do Process.put(:hex_test_package_name, :publish_package_name_no_confirm) Mix.Project.push(ReleaseName.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") File.write!("myfile.txt", "hello") setup_auth("user", "hunter42") send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["--no-progress", "--replace", "--yes"]) assert_received {:mix_shell, :info, ["Building publish_package_name_no_confirm 0.0.1"]} assert {:ok, {200, body, _}} = Hex.API.Release.get("hexpm", "publish_package_name_no_confirm", "0.0.1") assert body["meta"]["app"] == "release_d" end) after purge([ReleaseName.MixProject]) end test "publish package and docs with dry run" do Process.put(:hex_test_package_name, :publish_package_name_docs_dry_run) Mix.Project.push(ReleaseName.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") File.write!("myfile.txt", "hello") setup_auth("user", "hunter42") send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["--dry-run", "--yes", "--replace"]) assert_received {:mix_shell, :info, ["Building publish_package_name_docs_dry_run 0.0.1"]} refute_received {:mix_shell, :info, ["Package published to" <> _]} refute_received {:mix_shell, :info, ["Docs published to" <> _]} end) after purge([ReleaseName.MixProject]) end test "create with key" do Process.put(:hex_test_app_name, :publish_with_key) Mix.Project.push(ReleaseSimple.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") File.write!("myfile.txt", "hello") setup_auth("user2", "hunter42") send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace"]) assert {:ok, {200, _, _}} = Hex.API.Release.get("hexpm", "publish_with_key", "0.0.1") end) after purge([ReleaseSimple.MixProject]) end test "create with HEX_API_KEY" do Process.put(:hex_test_app_name, :publish_with_hex_api_key) Mix.Project.push(ReleaseSimple.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") File.write!("myfile.txt", "hello") send(self(), {:mix_shell_input, :prompt, "user2"}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.User.run(["key", "generate"]) assert_received {:mix_shell, :info, ["Generating key..."]} assert_received {:mix_shell, :info, [key]} Hex.State.put(:api_key_write_unencrypted, key) Mix.Tasks.Hex.Publish.run(["package", "--yes", "--no-progress", "--replace"]) assert_received {:mix_shell, :info, ["Building publish_with_hex_api_key 0.0.1"]} assert {:ok, {200, _, _}} = Hex.API.Release.get("hexpm", "publish_with_hex_api_key", "0.0.1") end) after purge([ReleaseSimple.MixProject]) end test "create with an invalid HEX_API_KEY" do Process.put(:hex_test_app_name, :publish_with_invalid_hex_api_key) Mix.Project.push(ReleaseSimple.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") File.write!("myfile.txt", "hello") Hex.State.put(:api_key_write_unencrypted, "invalid hex api key") assert {:exit_code, 1} = ["package", "--yes", "--no-progress", "--replace"] |> Mix.Tasks.Hex.Publish.run() |> catch_throw() assert_received {:mix_shell, :info, ["invalid API key"]} end) after purge([ReleaseSimple.MixProject]) end test "create with deps" do Process.put(:hex_test_app_name, :publish_with_deps) Mix.Project.push(ReleaseDeps.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") setup_auth("user", "hunter42") Mix.Tasks.Deps.Get.run([]) error_msg = "Stopping package build due to errors.\nMissing metadata fields: links" assert_raise Mix.Error, error_msg, fn -> send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace"]) end assert {:ok, {404, _, _}} = Hex.API.Release.get("hexpm", "publish_with_deps", "0.0.2") end) after purge([ReleaseDeps.MixProject]) end test "raise for missing metadata" do Process.put(:hex_test_app_name, :publish_with_missing_metadata) Mix.Project.push(ReleaseMeta.MixProject) in_tmp(fn -> set_home_tmp() setup_auth("user", "hunter42") error_msg = "Stopping package build due to errors.\n" <> "Missing files: missing.txt, missing/*" assert_raise Mix.Error, error_msg, fn -> File.write!("myfile.txt", "hello") send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace"]) assert_received {:mix_shell, :info, ["Building release_c 0.0.3"]} assert_received {:mix_shell, :info, [" Files:"]} assert_received {:mix_shell, :info, [" myfile.txt"]} assert_received {:mix_shell, :info, [" Extra: \n c: d"]} refute_received {:mix_shell, :error, ["Missing metadata fields" <> _]} end end) after purge([ReleaseMeta.MixProject]) end test "create with metadata" do Process.put(:hex_test_app_name, :publish_with_metadata) Mix.Project.push(ReleaseMeta.MixProject) in_tmp(fn -> set_home_tmp() setup_auth("user2", "hunter42") File.mkdir!("missing") File.write!("myfile.txt", "hello") File.write!("missing.txt", "hello") File.write!("missing/file.txt", "hello") send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace"]) assert_received {:mix_shell, :info, ["Building publish_with_metadata 0.0.3"]} assert_received {:mix_shell, :info, [" Files:"]} assert_received {:mix_shell, :info, [" myfile.txt"]} assert_received {:mix_shell, :info, [" Extra: \n c: d"]} assert_received {:mix_shell, :info, ["Publishing package using http://" <> _]} refute_received {:mix_shell, :error, ["Missing metadata fields" <> _]} end) after purge([ReleaseMeta.MixProject]) end test "create with organization prompt" do Process.put(:hex_test_app_name, :publish_with_organization_prompt) Mix.Project.push(ReleaseSimple.MixProject) in_tmp(fn -> set_home_tmp() setup_auth("user", "hunter42") File.write!("myfile.txt", "hello") send(self(), {:mix_shell_input, :prompt, "2"}) send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace"]) assert_received {:mix_shell, :info, ["You are a member of one or multiple organizations. " <> _]} assert_received {:mix_shell, :info, ["Publishing package using http://" <> _]} assert_received {:mix_shell, :info, ["Transferring ownership to testorg..."]} assert {:ok, {200, body, _headers}} = Hex.API.Package.get("hexpm", "publish_with_organization_prompt") assert "testorg" in Enum.map(body["owners"], & &1["username"]) end) after purge([ReleaseSimple.MixProject]) end test "create package with :organization config" do Process.put(:hex_test_app_name, :publish_with_org_config) Mix.Project.push(ReleaseRepo.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") bypass_repo("myorg") setup_auth("user", "hunter42") send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace"]) assert_received {:mix_shell, :info, ["Publishing package to private repository myorg using http://" <> _]} assert_received {:mix_shell, :info, ["Package published to myrepo html_url" <> _]} end) after purge([ReleaseRepo.MixProject]) end test "create package with :organization config with no organization in user config" do Process.put(:hex_test_app_name, :publish_without_org_in_user_config) Mix.Project.push(ReleaseRepo.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") setup_auth("user", "hunter42") send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) assert {:exit_code, 1} = ["package", "--no-progress", "--replace"] |> Mix.Tasks.Hex.Publish.run() |> catch_throw() refute_received {:mix_shell, :info, ["Package published to myrepo html_url" <> _]} end) after purge([ReleaseRepo.MixProject]) end test "create package with --organization flag overrides :organization config" do Process.put(:hex_test_app_name, :publish_organization_flag_override) Mix.Project.push(ReleaseRepo.MixProject) in_tmp(fn -> set_home_tmp() File.write!("mix.exs", "mix.exs") bypass_repo("myorg2") setup_auth("user", "hunter42") send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) Mix.Tasks.Hex.Publish.run([ "package", "--no-progress", "--replace", "--organization", "myorg2" ]) assert_received {:mix_shell, :info, ["Publishing package to private repository myorg2 using http://" <> _]} assert_received {:mix_shell, :info, ["Package published to myrepo html_url" <> _]} end) after purge([ReleaseRepo.MixProject]) end test "create with empty file list" do Process.put(:hex_test_app_name, :publish_with_empty_file_list) Mix.Project.push(ReleaseMetaNoFiles.MixProject) in_tmp(fn -> set_home_tmp() setup_auth("user2", "hunter42") error_msg = "Stopping package build due to errors.\n" <> "Creating tarball failed: File list was empty." send(self(), {:mix_shell_input, :yes?, true}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) assert_raise Mix.Error, error_msg, fn -> Mix.Tasks.Hex.Publish.run(["package", "--no-progress", "--replace"]) end end) after purge([ReleaseMetaNoFiles.MixProject]) end end hex-2.0.6/test/mix/tasks/hex.registry_test.exs000066400000000000000000000163541437023760000214320ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.RegistryTest do use HexTest.Case test "build" do in_tmp(fn -> bypass = setup_bypass() 0 = Mix.shell().cmd("openssl genrsa -out private_key.pem") flush() Mix.Task.run( "hex.registry", ~w(build public --name acme --private-key private_key.pem) ) assert_received {:mix_shell, :info, ["* creating public/public_key"]} assert_received {:mix_shell, :info, ["* creating public/tarballs"]} assert_received {:mix_shell, :info, ["* creating public/names"]} assert_received {:mix_shell, :info, ["* creating public/versions"]} refute_received _ config = %{ :mix_hex_core.default_config() | repo_url: "http://localhost:#{bypass.port}", repo_verify: false, repo_verify_origin: false } assert {:ok, {200, _, []}} = :mix_hex_repo.get_names(config) assert {:ok, {200, _, []}} = :mix_hex_repo.get_versions(config) {:ok, %{tarball: tarball}} = :mix_hex_tarball.create(%{name: "foo", version: "0.10.0"}, []) File.write!("public/tarballs/foo-0.10.0.tar", tarball) Mix.Task.reenable("hex.registry") Mix.Task.run( "hex.registry", ~w(build public --name acme --private-key private_key.pem) ) assert_received {:mix_shell, :info, ["* creating public/packages/foo"]} assert_received {:mix_shell, :info, ["* updating public/names"]} assert_received {:mix_shell, :info, ["* updating public/versions"]} refute_received _ assert {:ok, {200, _, names}} = :mix_hex_repo.get_names(config) assert [%{name: "foo", updated_at: %{seconds: updated_at}}] = names assert updated_at == "public/tarballs/foo-0.10.0.tar" |> File.stat!() |> Map.fetch!(:mtime) |> Mix.Tasks.Hex.Registry.to_unix() assert {:ok, {200, _, versions}} = :mix_hex_repo.get_versions(config) assert versions == [%{name: "foo", retired: [], versions: ["0.10.0"]}] {:ok, %{tarball: tarball}} = :mix_hex_tarball.create(%{name: "foo", version: "0.9.0"}, []) File.write!("public/tarballs/foo-0.9.0.tar", tarball) Mix.Task.reenable("hex.registry") Mix.Task.run( "hex.registry", ~w(build public --name acme --private-key private_key.pem) ) assert_received {:mix_shell, :info, ["* updating public/packages/foo"]} assert_received {:mix_shell, :info, ["* updating public/names"]} assert_received {:mix_shell, :info, ["* updating public/versions"]} refute_received _ assert {:ok, {200, _, names}} = :mix_hex_repo.get_names(config) assert [%{name: "foo", updated_at: %{seconds: updated_at}}] = names assert updated_at == "public/tarballs/foo-0.9.0.tar" |> File.stat!() |> Map.fetch!(:mtime) |> Mix.Tasks.Hex.Registry.to_unix() assert {:ok, {200, _, versions}} = :mix_hex_repo.get_versions(config) assert versions == [%{name: "foo", retired: [], versions: ["0.9.0", "0.10.0"]}] # Versions with hyphen {:ok, %{tarball: tarball}} = :mix_hex_tarball.create(%{name: "foo", version: "1.0.0-rc"}, []) File.write!("public/tarballs/foo-1.0.0-rc.tar", tarball) Mix.Task.reenable("hex.registry") Mix.Task.run( "hex.registry", ~w(build public --name acme --private-key private_key.pem) ) assert_received {:mix_shell, :info, ["* updating public/packages/foo"]} assert_received {:mix_shell, :info, ["* updating public/names"]} assert_received {:mix_shell, :info, ["* updating public/versions"]} refute_received _ assert {:ok, {200, _, names}} = :mix_hex_repo.get_names(config) assert [%{name: "foo", updated_at: _}] = names assert {:ok, {200, _, versions}} = :mix_hex_repo.get_versions(config) assert versions == [%{name: "foo", retired: [], versions: ["0.9.0", "0.10.0", "1.0.0-rc"]}] # Re-generating private key 0 = Mix.shell().cmd("openssl genrsa -out private_key.pem") flush() Mix.Task.reenable("hex.registry") Mix.Task.run( "hex.registry", ~w(build public --name acme --private-key private_key.pem) ) assert_received {:mix_shell, :info, ["* public key at public/public_key does not" <> _]} assert_received {:mix_shell, :info, ["* updating public/public_key"]} assert_received {:mix_shell, :info, ["* updating public/packages/foo"]} assert_received {:mix_shell, :info, ["* updating public/names"]} assert_received {:mix_shell, :info, ["* updating public/versions"]} refute_received _ # Package with deps metadata = %{ name: "bar", version: "0.1.0", requirements: %{ "foo" => %{ "app" => "foo", "optional" => false, "repository" => "acme", "requirement" => "~> 0.1.0" }, "baz" => %{ "app" => "baz", "optional" => false, "repository" => "external", "requirement" => "~> 0.1.0" } } } {:ok, %{tarball: tarball}} = :mix_hex_tarball.create(metadata, []) File.write!("public/tarballs/bar-0.1.0.tar", tarball) Mix.Task.reenable("hex.registry") Mix.Task.run( "hex.registry", ~w(build public --name acme --private-key private_key.pem) ) assert_received {:mix_shell, :info, ["* creating public/packages/bar"]} assert_received {:mix_shell, :info, ["* updating public/packages/foo"]} assert_received {:mix_shell, :info, ["* updating public/names"]} assert_received {:mix_shell, :info, ["* updating public/versions"]} refute_received _ assert {:ok, {200, _, names}} = :mix_hex_repo.get_names(config) assert [%{name: "bar", updated_at: _}, %{name: "foo", updated_at: _}] = names assert {:ok, {200, _, [package]}} = :mix_hex_repo.get_package(config, "bar") assert package.dependencies == [ %{ app: "baz", optional: false, package: "baz", requirement: "~> 0.1.0", repository: "external" }, %{ app: "foo", optional: false, package: "foo", requirement: "~> 0.1.0" } ] # Removing all package releases File.rm!("public/tarballs/foo-0.9.0.tar") File.rm!("public/tarballs/foo-0.10.0.tar") File.rm!("public/tarballs/foo-1.0.0-rc.tar") Mix.Task.reenable("hex.registry") Mix.Task.run( "hex.registry", ~w(build public --name acme --private-key private_key.pem) ) assert_received {:mix_shell, :info, ["* updating public/packages/bar"]} assert_received {:mix_shell, :info, ["* removing public/packages/foo"]} assert_received {:mix_shell, :info, ["* updating public/names"]} assert_received {:mix_shell, :info, ["* updating public/versions"]} refute_received _ end) end defp setup_bypass() do bypass = Bypass.open() Bypass.expect(bypass, fn conn -> opts = Plug.Static.init(at: "/", from: File.cwd!() <> "/public") Plug.Static.call(conn, opts) end) bypass end end hex-2.0.6/test/mix/tasks/hex.repo_test.exs000066400000000000000000000121751437023760000205240ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.RepoTest do use HexTest.Case @public_key """ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApqREcFDt5vV21JVe2QNB Edvzk6w36aNFhVGWN5toNJRjRJ6m4hIuG4KaXtDWVLjnvct6MYMfqhC79HAGwyF+ IqR6Q6a5bbFSsImgBJwz1oadoVKD6ZNetAuCIK84cjMrEFRkELtEIPNHblCzUkkM 3rS9+DPlnfG8hBvGi6tvQIuZmXGCxF/73hU0/MyGhbmEjIKRtG6b0sJYKelRLTPW XgK7s5pESgiwf2YC/2MGDXjAJfpfCd0RpLdvd4eRiXtVlE9qO9bND94E7PgQ/xqZ J1i2xWFndWa6nfFnRxZmCStCOZWYYPlaxr+FZceFbpMwzTNs4g3d4tLNUcbKAIH4 0wIDAQAB -----END PUBLIC KEY----- """ @public_key_fingerprint "SHA256:O1LOYhHFW4kcrblKAxROaDEzLD8bn1seWbe5tq8TRsk" defp bypass_public_key() do bypass = Bypass.open() repos = Hex.State.fetch!(:repos) repos = put_in(repos["hexpm"].url, "http://localhost:#{bypass.port}") Hex.State.put(:repos, repos) Bypass.expect(bypass, fn %Plug.Conn{request_path: path} = conn -> case path do "/public_key" -> Plug.Conn.resp(conn, 200, @public_key) "/not_found/public_key" -> Plug.Conn.resp(conn, 404, "not found") end end) bypass end defp bypass_endpoint_url(bypass) do "http://localhost:#{bypass.port}" end test "add" do in_tmp(fn -> Hex.State.put(:config_home, File.cwd!()) File.write!("public_key.pem", @public_key) Mix.Tasks.Hex.Repo.run(["add", "reponame", "url", "--public-key", "public_key.pem"]) assert [ "$repos": %{ "reponame" => %{ auth_key: nil, public_key: "-----BEGIN PUBLIC KEY" <> _, url: "url" } } ] = Hex.Config.read() File.write!("foo.pem", "INVALID PUBLIC KEY") assert_raise Mix.Error, fn -> Mix.Tasks.Hex.Repo.run(["add", "reponame", "url", "--public-key", "foo.pem"]) end bypass = bypass_public_key() bypass_endpoint = bypass_endpoint_url(bypass) Mix.Tasks.Hex.Repo.run([ "add", "another-reponame", bypass_endpoint, "--fetch-public-key", @public_key_fingerprint, "--auth-key", "AAAA" ]) assert [ "$repos": %{ "another-reponame" => %{ auth_key: "AAAA", public_key: "-----BEGIN PUBLIC KEY" <> _, url: ^bypass_endpoint } } ] = Hex.Config.read() assert_raise Mix.Error, ~r/Public key fingerprint mismatch/, fn -> Mix.Tasks.Hex.Repo.run([ "add", "reponame-wrong-fingerprint", bypass_endpoint, "--fetch-public-key", "WRONG-FINGERPRINT" ]) end refute Keyword.get(Hex.Config.read(), :"$repos")["reponame-wrong-fingerprint"] assert catch_throw( Mix.Tasks.Hex.Repo.run([ "add", "not-found-reponame", "#{bypass_endpoint}/not_found", "--fetch-public-key", @public_key_fingerprint ]) ) == {:exit_code, 1} assert_received {:mix_shell, :error, ["Downloading public key failed with code \"404\""]} Bypass.down(bypass) assert catch_throw( Mix.Tasks.Hex.Repo.run([ "add", "reponame-connection-error", bypass_endpoint, "--fetch-public-key", @public_key_fingerprint ]) ) == {:exit_code, 1} assert_received {:mix_shell, :error, ["Downloading public key failed"]} end) end test "remove" do in_tmp(fn -> Hex.State.put(:config_home, File.cwd!()) Mix.Tasks.Hex.Repo.run(["add", "reponame", "url"]) Mix.Tasks.Hex.Repo.run(["remove", "reponame"]) assert ["$repos": %{}] = Hex.Config.read() end) end test "set url" do in_tmp(fn -> Hex.State.put(:config_home, File.cwd!()) Mix.Tasks.Hex.Repo.run(["add", "reponame", "url"]) Mix.Tasks.Hex.Repo.run(["set", "reponame", "--url", "other_url"]) assert ["$repos": %{"reponame" => %{url: "other_url"}}] = Hex.Config.read() end) end test "show url" do in_tmp(fn -> Hex.State.put(:config_home, File.cwd!()) Mix.Tasks.Hex.Repo.run(["add", "reponame", "url"]) Mix.Tasks.Hex.Repo.run(["show", "reponame", "--url"]) assert_received {:mix_shell, :info, ["url"]} end) end test "show prints repo config" do in_tmp(fn -> Hex.State.put(:config_home, File.cwd!()) Mix.Tasks.Hex.Repo.run(["add", "reponame", "url"]) Mix.Tasks.Hex.Repo.run(["show", "reponame"]) assert_received {:mix_shell, :info, [headers]} assert_received {:mix_shell, :info, [config]} assert headers =~ ~r{URL.*Public key.*Auth key} assert config =~ "url" end) end test "show raises an error when called with non-existant repo name" do in_tmp(fn -> Hex.State.put(:config_home, File.cwd!()) assert_raise Mix.Error, "Config does not contain repo non-existant-reponame", fn -> Mix.Tasks.Hex.Repo.run(["show", "non-existant-reponame"]) end end) end end hex-2.0.6/test/mix/tasks/hex.retire_test.exs000066400000000000000000000027101437023760000210430ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.RetireTest do use HexTest.IntegrationCase test "retire and unretire package" do auth = Hexpm.new_user("retire_user", "retire_user@mail.com", "passpass", "key") Hexpm.new_package("hexpm", "retire_package", "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "passpass"}) Mix.Tasks.Hex.Retire.run(["retire_package", "0.0.1", "renamed", "--message", "message"]) assert {:ok, {200, %{"retirement" => %{"message" => "message", "reason" => "renamed"}}, _}} = Hex.API.Release.get("hexpm", "retire_package", "0.0.1") send(self(), {:mix_shell_input, :prompt, "passpass"}) Mix.Tasks.Hex.Retire.run(["retire_package", "0.0.1", "--unretire"]) assert {:ok, {200, %{"retirement" => nil}, _}} = Hex.API.Release.get("hexpm", "retire_package", "0.0.1") end test "retire --message flag is required" do auth = Hexpm.new_user("retire_user_message", "retire_user_message@mail.com", "passpass", "key") Hexpm.new_package("hexpm", "retire_package_message", "0.0.1", [], %{}, auth) set_home_tmp() Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) send(self(), {:mix_shell_input, :prompt, "passpass"}) assert_raise Mix.Error, "Missing required flag --message", fn -> Mix.Tasks.Hex.Retire.run(["retire_package", "0.0.1", "renamed"]) end end end hex-2.0.6/test/mix/tasks/hex.search_test.exs000066400000000000000000000032321437023760000210160ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.SearchTest do use HexTest.IntegrationCase test "search" do Mix.Tasks.Hex.Search.run(["doc"]) assert_received {:mix_shell, :info, ["ex_doc" <> ex_doc]} assert_received {:mix_shell, :info, ["only_doc" <> only_doc]} assert ex_doc =~ ~r"\w*0\.1\.0.*http://localhost:4043/packages/ex_doc" assert only_doc =~ ~r"\w*0\.1\.0.*http://localhost:4043/packages/only_doc" end test "empty search" do Mix.Tasks.Hex.Search.run(["bloopdoopbloop"]) assert_received {:mix_shell, :info, ["No packages found"]} end test "search all private packages" do in_tmp(fn -> set_home_tmp() auth = Hexpm.new_user("searchuser1", "searchuser1@mail.com", "password", "searchuser1") Hexpm.new_repo("searchrepo1", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) Mix.Tasks.Hex.Search.run(["doc"]) assert_received {:mix_shell, :info, ["ex_doc" <> ex_doc]} assert_received {:mix_shell, :info, ["only_doc" <> only_doc]} assert ex_doc =~ ~r"\w*0\.1\.0.*http://localhost:4043/packages/ex_doc" assert only_doc =~ ~r"\w*0\.1\.0.*http://localhost:4043/packages/only_doc" end) end test "search private package" do in_tmp(fn -> set_home_tmp() auth = Hexpm.new_user("searchuser2", "searchuser2@mail.com", "password", "searchuser2") Hexpm.new_repo("searchrepo2", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) Mix.Tasks.Hex.Search.run(["doc", "--organization", "searchrepo2"]) refute_received {:mix_shell, :info, ["ex_doc" <> _]} refute_received {:mix_shell, :info, ["only_doc" <> _]} end) end end hex-2.0.6/test/mix/tasks/hex.sponsor_test.exs000066400000000000000000000043361437023760000212620ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.SponsorTest do use HexTest.IntegrationCase @package :test_sponsored_package @package_name Atom.to_string(@package) defmodule SponsoredDeps.MixProject do def project do [app: :test_app, version: "0.0.1", deps: [{:test_sponsored_package, ">= 0.1.0"}]] end end setup_all do auth = Hexpm.new_user("sponsor_user", "sponsor@mail.com", "passpass", "key") {:ok, [auth: auth]} end test "sponsor with sponsor link", context do url = "https://sponsor.foo.bar" with_test_package("0.1.0", %{links: %{sponsor: url}}, context, fn -> Mix.Task.run("hex.sponsor") end) assert_received {:mix_shell, :info, [header_output]} assert_received {:mix_shell, :info, [package_line]} assert header_output =~ "Dependency" assert header_output =~ "Sponsorship" assert package_line =~ @package_name assert package_line =~ url end test "without sponsor link", context do with_test_package("1.2.0", %{links: %{github: "https://github.com/foo/bar"}}, context, fn -> Mix.Task.run("hex.sponsor") end) assert_received {:mix_shell, :info, [header_output]} refute_received {:mix_shell, :info, [_package_line]} assert header_output =~ "No dependencies with sponsorship link found" end test "outside a mix project", %{auth: auth} do in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) flush() error_msg = "The sponsor task only works inside a Mix project. " <> "Please ensure you are in a directory with a mix.exs file." assert_raise Mix.Error, error_msg, fn -> Mix.Tasks.Hex.Sponsor.run([]) end end) end defp with_test_package(version, metadata, %{auth: auth}, fun) do Mix.Project.push(SponsoredDeps.MixProject) Hexpm.new_package( "hexpm", @package_name, version, [], metadata, auth ) in_tmp(fn -> Hex.State.put(:cache_home, tmp_path()) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) Mix.Dep.Lock.write(%{@package => {:hex, @package, version}}) Mix.Task.run("deps.get") flush() fun.() end) end end hex-2.0.6/test/mix/tasks/hex.user_test.exs000066400000000000000000000210051437023760000205250ustar00rootroot00000000000000defmodule Mix.Tasks.Hex.UserTest do use HexTest.IntegrationCase test "register" do send(self(), {:mix_shell_input, :prompt, "eric"}) send(self(), {:mix_shell_input, :prompt, "mail@mail.com"}) send(self(), {:mix_shell_input, :yes?, false}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) assert_raise Mix.Error, "Entered passwords do not match", fn -> Mix.Tasks.Hex.User.run(["register"]) end send(self(), {:mix_shell_input, :prompt, "eric"}) send(self(), {:mix_shell_input, :prompt, "mail@mail.com"}) send(self(), {:mix_shell_input, :yes?, false}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) Mix.Tasks.Hex.User.run(["register"]) assert {:ok, {200, body, _}} = Hex.API.User.get("eric") assert body["username"] == "eric" end test "auth" do in_tmp(fn -> set_home_cwd() send(self(), {:mix_shell_input, :prompt, "user"}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) Mix.Tasks.Hex.User.run(["auth"]) {:ok, name} = :inet.gethostname() name = List.to_string(name) auth = Mix.Tasks.Hex.auth_info(:read) assert {:ok, {200, body, _}} = Hex.API.Key.get(auth) assert "#{name}-api" in Enum.map(body, & &1["name"]) assert "#{name}-repositories" in Enum.map(body, & &1["name"]) end) end test "auth with --key-name" do in_tmp(fn -> set_home_cwd() send(self(), {:mix_shell_input, :prompt, "user"}) send(self(), {:mix_shell_input, :prompt, "hunter42"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) Mix.Tasks.Hex.User.run(["auth", "--key-name", "userauthkeyname"]) auth = Mix.Tasks.Hex.auth_info(:read) assert {:ok, {200, body, _}} = Hex.API.Key.get(auth) assert "userauthkeyname-api" in Enum.map(body, & &1["name"]) assert "userauthkeyname-repositories" in Enum.map(body, & &1["name"]) end) end test "auth organizations" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("userauthorg", "userauthorg@mail.com", "password", "userauthorg") Hexpm.new_repo("myuserauthorg", auth) send(self(), {:mix_shell_input, :prompt, "userauthorg"}) send(self(), {:mix_shell_input, :prompt, "password"}) send(self(), {:mix_shell_input, :prompt, "password"}) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.User.run(["auth"]) assert {:ok, hexpm_repo} = Hex.Repo.fetch_repo("hexpm") assert {:ok, neworg_repo} = Hex.Repo.fetch_repo("hexpm:myuserauthorg") assert is_binary(hexpm_repo.auth_key) assert hexpm_repo.auth_key == neworg_repo.auth_key end) end test "deauth user and organizations" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("userdeauth1", "userdeauth1@mail.com", "password", "userdeauth1") Hexpm.new_repo("myorguserdeauth1", auth) Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) assert Hex.Config.read()[:"$write_key"] == auth[:"$write_key"] send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.Organization.run(["auth", "myorguserdeauth1"]) Mix.Tasks.Hex.User.run(["deauth"]) refute Hex.Config.read()[:"$write_key"] refute Hex.Config.read()[:"$repos"]["hexpm:myorguserdeauth1"] end) end test "whoami" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("whoami", "whoami@mail.com", "password", "whoami") Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) Mix.Tasks.Hex.User.run(["whoami"]) assert_received {:mix_shell, :info, ["whoami"]} end) end test "list keys" do in_tmp(fn -> set_home_cwd() auth = Hexpm.new_user("list_keys", "list_keys@mail.com", "password", "list_keys") Mix.Tasks.Hex.update_keys(auth[:"$write_key"], auth[:"$read_key"]) assert {:ok, {200, [%{"name" => "list_keys"}], _}} = Hex.API.Key.get(auth) Mix.Tasks.Hex.User.run(["key", "list"]) assert_received {:mix_shell, :info, ["list_keys" <> _]} end) end test "revoke key" do in_tmp(fn -> set_home_cwd() auth_a = Hexpm.new_user("revoke_key", "revoke_key@mail.com", "password", "revoke_key_a") auth_b = Hexpm.new_key("revoke_key", "password", "revoke_key_b") Mix.Tasks.Hex.update_keys(auth_a[:"$write_key"], auth_a[:"$read_key"]) assert {:ok, {200, _, _}} = Hex.API.Key.get(auth_a) assert {:ok, {200, _, _}} = Hex.API.Key.get(auth_b) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.User.run(["key", "revoke", "revoke_key_b"]) assert_received {:mix_shell, :info, ["Revoking key revoke_key_b..."]} assert {:ok, {200, _, _}} = Hex.API.Key.get(auth_a) assert {:ok, {401, _, _}} = Hex.API.Key.get(auth_b) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.User.run(["key", "revoke", "revoke_key_a"]) assert_received {:mix_shell, :info, ["Revoking key revoke_key_a..."]} message = "Authentication credentials removed from the local machine. " <> "To authenticate again, run `mix hex.user auth` or create a new user with " <> "`mix hex.user register`" assert_received {:mix_shell, :info, [^message]} assert {:ok, {401, _, _}} = Hex.API.Key.get(auth_a) end) end test "revoke all keys" do in_tmp(fn -> set_home_cwd() auth_a = Hexpm.new_user( "revoke_all_keys", "revoke_all_keys@mail.com", "password", "revoke_all_keys_a" ) auth_b = Hexpm.new_key("revoke_all_keys", "password", "revoke_all_keys_b") Mix.Tasks.Hex.update_keys(auth_a[:"$write_key"], auth_a[:"$read_key"]) assert {:ok, {200, _, _}} = Hex.API.Key.get(auth_a) assert {:ok, {200, _, _}} = Hex.API.Key.get(auth_b) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.User.run(["key", "revoke", "--all"]) assert_received {:mix_shell, :info, ["Revoking all keys..."]} message = "Authentication credentials removed from the local machine. " <> "To authenticate again, run `mix hex.user auth` or create a new user with " <> "`mix hex.user register`" assert_received {:mix_shell, :info, [^message]} assert {:ok, {401, _, _}} = Hex.API.Key.get(auth_a) assert {:ok, {401, _, _}} = Hex.API.Key.get(auth_b) end) end test "key generate" do in_tmp(fn -> set_home_cwd() Hexpm.new_user("userkeygenerate", "userkeygenerate@mail.com", "password", "password") send(self(), {:mix_shell_input, :prompt, "userkeygenerate"}) send(self(), {:mix_shell_input, :prompt, "password"}) Mix.Tasks.Hex.User.run(["key", "generate"]) assert_received {:mix_shell, :info, ["Generating key..."]} assert_received {:mix_shell, :info, [key]} assert is_binary(key) end) end test "reset account password" do Hexpm.new_user("reset_password", "reset_password@mail.com", "password", "reset_password") send(self(), {:mix_shell_input, :prompt, "reset_password"}) Mix.Tasks.Hex.User.run(["reset_password", "account"]) assert_received {:mix_shell, :info, ["We’ve sent you an email" <> _]} end test "reset local password" do in_tmp(fn -> set_home_cwd() Mix.Tasks.Hex.update_keys(Mix.Tasks.Hex.encrypt_key("hunter42", "qwerty")) first_key = Hex.Config.read()[:"$write_key"] read_key = Hex.Config.read()[:"$read_key"] send(self(), {:mix_shell_input, :prompt, "hunter42"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) Mix.Tasks.Hex.User.run(["reset_password", "local"]) assert Hex.Config.read()[:"$write_key"] != first_key assert Hex.Config.read()[:"$read_key"] == read_key send(self(), {:mix_shell_input, :prompt, "wrong"}) send(self(), {:mix_shell_input, :prompt, "hunter43"}) send(self(), {:mix_shell_input, :prompt, "hunter44"}) send(self(), {:mix_shell_input, :prompt, "hunter44"}) Mix.Tasks.Hex.User.run(["reset_password", "local"]) assert_received {:mix_shell, :error, ["Wrong password. Try again"]} end) end end hex-2.0.6/test/mix/tasks/hex_test.exs000066400000000000000000000004401437023760000175500ustar00rootroot00000000000000defmodule Mix.Tasks.HexTest do use HexTest.Case test "run without args shows help" do Mix.Tasks.Hex.run([]) assert_received {:mix_shell, :info, ["Hex is a package manager for the Erlang ecosystem."]} assert_received {:mix_shell, :info, ["mix hex.config" <> _]} end end hex-2.0.6/test/setup_hexpm.exs000066400000000000000000000062551437023760000163560ustar00rootroot00000000000000alias HexTest.Case alias HexTest.Hexpm Hexpm.init() Hexpm.start() pkg_meta = %{ "licenses" => ["GPL2", "MIT", "Apache"], "links" => %{"docs" => "http://docs", "repo" => "http://repo"}, "description" => "Some description" } auth = Hexpm.new_user("user", "user@mail.com", "hunter42", "my_key") Hexpm.new_user("user2", "user2@mail.com", "hunter42", "my_key") package_name_meta = Map.put(pkg_meta, "app", "app_name") Hexpm.new_package("hexpm", "ex_doc", "0.0.1", [], pkg_meta, auth) Hexpm.new_package("hexpm", "ex_doc", "0.1.0", [], pkg_meta, auth) Hexpm.new_package("hexpm", "ex_doc", "0.1.0-rc1", [], pkg_meta, auth) Hexpm.new_package("hexpm", "postgrex", "0.2.1", [ex_doc: "~> 0.1.0"], pkg_meta, auth) Hexpm.new_package("hexpm", "postgrex", "0.2.0", [ex_doc: "0.0.1"], pkg_meta, auth) Hexpm.new_package( "hexpm", "ecto", "0.2.0", [postgrex: "~> 0.2.0", ex_doc: "~> 0.0.1"], pkg_meta, auth ) Hexpm.new_package("hexpm", "phoenix", "0.0.1", [postgrex: "~> 0.2"], pkg_meta, auth) Hexpm.new_package( "hexpm", "only_doc", "0.1.0", [{:ex_doc, ">= 0.0.0", optional: true}], pkg_meta, auth ) Hexpm.new_package("hexpm", "package_name", "0.1.0", [], package_name_meta, auth) Hexpm.new_package("hexpm", "foo", "0.1.0", [], pkg_meta, auth) Hexpm.new_package("hexpm", "foo", "0.1.1", [], pkg_meta, auth) Hexpm.new_package("hexpm", "bar", "0.1.0", [foo: "~> 0.1.0"], pkg_meta, auth) Hexpm.new_package("hexpm", "baz", "0.1.0", [foo: "0.1.0"], pkg_meta, auth) Hexpm.new_package("hexpm", "beta", "1.0.0", [], pkg_meta, auth) Hexpm.new_package("hexpm", "beta", "1.1.0-beta", [], pkg_meta, auth) Hexpm.new_package("hexpm", "tired", "0.1.0", [], pkg_meta, auth) Hexpm.new_package("hexpm", "tired", "0.2.0", [], pkg_meta, auth) Hexpm.new_package( "hexpm", "ecto", "0.2.1", [ {:sample, "0.0.1", path: Case.fixture_path("sample")}, postgrex: "~> 0.2.1", ex_doc: "0.1.0" ], pkg_meta, auth ) Hexpm.new_package( "hexpm", "depend_name", "0.2.0", [{:app_name, ">= 0.0.0", hex: :package_name}], pkg_meta, auth ) {:ok, _} = Hex.API.Release.retire("hexpm", "tired", "0.1.0", %{reason: "invalid"}, auth) Hexpm.new_repo("testorg", auth) Hexpm.new_package("testorg", "foo", "0.1.0", [], pkg_meta, auth) Hexpm.new_package("testorg", "bar", "0.1.0", [foo: "~> 0.1.0"], pkg_meta, auth) Hexpm.new_package("hexpm", "ecto_sql", "3.3.2", [ecto: "~> 3.3.1"], pkg_meta, auth, [ {"mix.exs", File.read!(Case.fixture_path("ecto_sql_3_3_2/mix.exs"))} ]) Hexpm.new_package("hexpm", "ecto_sql", "3.3.3", [ecto: "~> 3.3.2"], pkg_meta, auth, [ {"mix.exs", File.read!(Case.fixture_path("ecto_sql_3_3_3/mix.exs"))} ]) Hexpm.new_package("hexpm", "ecto_enum", "1.4.0", [ecto: ">= 3.0.0"], pkg_meta, auth, [ {"mix.exs", File.read!(Case.fixture_path("ecto_enum_1_4_0/mix.exs"))} ]) Hexpm.new_package("hexpm", "ecto", "3.3.1", [], pkg_meta, auth, [ {"mix.exs", File.read!(Case.fixture_path("ecto_3_3_1/mix.exs"))} ]) Hexpm.new_package("hexpm", "ecto", "3.3.2", [], pkg_meta, auth, [ {"mix.exs", File.read!(Case.fixture_path("ecto_3_3_2/mix.exs"))} ]) sponsored_meta = put_in(pkg_meta, ["links", "Sponsor"], "https://my.sponsor.link") Hexpm.new_package("hexpm", "sponsored", "0.1.0", [], sponsored_meta, auth) hex-2.0.6/test/support/000077500000000000000000000000001437023760000150005ustar00rootroot00000000000000hex-2.0.6/test/support/case.ex000066400000000000000000000320761437023760000162610ustar00rootroot00000000000000defmodule HexTest.Case do use ExUnit.CaseTemplate using do quote do import unquote(__MODULE__) alias HexTest.Case alias HexTest.Hexpm end end def flush do flush([]) end if Version.compare(System.version(), "1.10.0-rc.0") == :lt do def clear_cache(), do: Mix.ProjectStack.clear_cache() else def clear_cache(), do: Mix.State.clear_cache() end defp flush(acc) do receive do any -> flush([any | acc]) after 0 -> Enum.reverse(acc) end end def tmp_path() do Path.expand("../../tmp", __DIR__) end def tmp_path(extension) do Path.join(tmp_path(), extension) end def fixture_path() do Path.expand("../fixtures", __DIR__) end def fixture_path(extension) do Path.join(fixture_path(), extension) end defp escape_path(path) do case :os.type() do {:win32, _} -> String.replace(path, ~R'[~#%&*{}\\:<>?/+|"]', "_") _ -> path end end defmacro test_tmp() do module = escape_path("#{__CALLER__.module}") function = escape_path("#{elem(__CALLER__.function, 0)}") Path.join([HexTest.Case.tmp_path(), module, function]) end defmacro test_name() do module = escape_path("#{__CALLER__.module}") function = escape_path("#{elem(__CALLER__.function, 0)}") Path.join([module, function]) end defmacro in_tmp(fun) do module = escape_path("#{__CALLER__.module}") function = escape_path("#{elem(__CALLER__.function, 0)}") path = Path.join([module, function]) quote do in_tmp(unquote(path), unquote(fun)) end end def in_tmp(tmp, function) do path = tmp_path(tmp) File.rm_rf!(path) File.mkdir_p!(path) File.cd!(path, function) end defmacro in_fixture(which, block) do module = inspect(__CALLER__.module) function = Atom.to_string(elem(__CALLER__.function, 0)) tmp = Path.join(module, function) quote do unquote(__MODULE__).in_fixture(unquote(which), unquote(tmp), unquote(block)) end end def in_fixture(which, tmp, function) do src = fixture_path(which) dest = tmp_path(String.replace(tmp, ":", "_")) flag = String.to_charlist(tmp_path()) File.rm_rf!(dest) File.mkdir_p!(dest) File.cp_r!(src, dest) get_path = :code.get_path() previous = :code.all_loaded() try do File.cd!(dest, function) after :code.set_path(get_path) for {mod, file} <- :code.all_loaded() -- previous, file == [] or (is_list(file) and :lists.prefix(flag, file)) do purge([mod]) end end end def purge(modules) do Enum.each(modules, fn m -> :code.delete(m) :code.purge(m) end) end @ets_table :hex_index def create_test_registry(path, registry) do registry = Enum.sort(registry) versions = Enum.reduce(registry, %{}, fn {repo, name, vsn, _deps}, map -> key = {Atom.to_string(repo), Atom.to_string(name)} Map.update(map, key, [vsn], &(&1 ++ [vsn])) end) |> Enum.to_list() deps = Enum.map(registry, fn {outer_repo, name, vsn, deps} -> deps = Enum.map(deps, fn config -> destructure [name, req, optional, app, repo], Tuple.to_list(config) optional = optional || false app = app || name repo = repo || outer_repo {Atom.to_string(repo), Atom.to_string(name), Atom.to_string(app), req, optional} end) {{Atom.to_string(outer_repo), Atom.to_string(name), vsn}, deps} end) create_registry(path, versions, deps) end defp create_registry(path, versions, deps) do tid = :ets.new(@ets_table, []) versions = Enum.map(versions, fn {{repo, pkg}, versions} -> {{:versions, repo, pkg}, versions} end) deps = Enum.map(deps, fn {{repo, pkg, vsn}, deps} -> {{:deps, repo, pkg, vsn}, deps} end) :ets.insert(tid, versions ++ deps ++ [{:version, 3}]) File.mkdir_p!(Path.dirname(path)) :ok = :ets.tab2file(tid, String.to_charlist(path)) :ets.delete(tid) end defp test_registry() do [ {:hexpm, :bar, "0.0.1", []}, {:hexpm, :bar, "0.1.0", [foo: "~> 0.1.0"]}, {:hexpm, :bar, "0.2.0", [foo: "~> 0.2.0"]}, {:hexpm, :beta, "1.0.0", []}, {:hexpm, :beta, "1.1.0-beta", []}, {:hexpm, :decimal, "0.0.1", []}, {:hexpm, :decimal, "0.1.0", []}, {:hexpm, :decimal, "0.2.0", []}, {:hexpm, :decimal, "0.2.1", []}, {:hexpm, :depend_name, "0.2.0", [{:package_name, ">= 0.0.0", false, :app_name}]}, {:hexpm, :ecto, "0.2.0", [postgrex: "~> 0.2.0", ex_doc: "~> 0.0.1"]}, {:hexpm, :ecto, "0.2.1", [postgrex: "~> 0.2.1", ex_doc: "0.1.0"]}, {:hexpm, :ecto, "1.1.0", [poison: "~> 1.0"]}, {:hexpm, :eric, "0.0.1", []}, {:hexpm, :eric, "0.0.2", []}, {:hexpm, :eric, "0.1.0", [jose: "~> 0.1.0"]}, {:hexpm, :eric, "0.1.2", [jose: "~> 0.1.0"]}, {:hexpm, :eric, "0.2.0", [jose: "~> 0.3.0"]}, {:hexpm, :ex_doc, "0.0.1", []}, {:hexpm, :ex_doc, "0.0.2", []}, {:hexpm, :ex_doc, "0.1.0", []}, {:hexpm, :ex_plex, "0.0.1", []}, {:hexpm, :ex_plex, "0.0.2", [decimal: "0.1.1"]}, {:hexpm, :ex_plex, "0.1.0", [decimal: "~> 0.1.0"]}, {:hexpm, :ex_plex, "0.1.2", [decimal: "~> 0.1.0"]}, {:hexpm, :ex_plex, "0.2.0", [decimal: "~> 0.2.0"]}, {:hexpm, :foo, "0.0.1", []}, {:hexpm, :foo, "0.1.0", []}, {:hexpm, :foo, "0.2.0", []}, {:hexpm, :foo, "0.2.1", []}, {:hexpm, :has_optional, "0.1.0", [{:ex_doc, "~> 0.0.1", true}]}, {:hexpm, :invalid_dirname, "0.1.0", []}, {:hexpm, :invalid_filename, "0.1.0", []}, {:hexpm, :jose, "0.2.0", []}, {:hexpm, :jose, "0.2.1", []}, {:hexpm, :only_doc, "0.1.0", [{:ex_doc, ">= 0.0.0", true}]}, {:hexpm, :package_name, "0.1.0", []}, {:hexpm, :phoenix, "0.0.1", [postgrex: "~> 0.2"]}, {:hexpm, :phoenix, "1.1.2", [poison: "~> 1.5 or ~> 2.0"]}, {:hexpm, :phoenix, "1.1.3", [poison: "~> 1.5 or ~> 2.0"]}, {:hexpm, :poison, "1.5.2", []}, {:hexpm, :poison, "2.0.0", []}, {:hexpm, :phoenix_ecto, "2.0.0", [ecto: "~> 1.1", poison: "~> 1.3"]}, {:hexpm, :phoenix_ecto, "2.0.1", [ecto: "~> 1.1", poison: "~> 1.3"]}, {:hexpm, :phoenix_live_reload, "1.0.0", [phoenix: "~> 0.16 or ~> 1.0"]}, {:hexpm, :phoenix_live_reload, "1.0.3", [phoenix: "~> 0.16 or ~> 1.0"]}, {:hexpm, :postgrex, "0.2.0", [ex_doc: "0.0.1"]}, {:hexpm, :postgrex, "0.2.1", [ex_doc: "~> 0.1.0"]}, {:repo2, :hexpm_deps, "0.1.0", [{:poison, ">= 0.0.0", false, :poison, :hexpm}]}, {:repo2, :poison, "2.0.0", []}, {:repo2, :repo2_deps, "0.1.0", [poison: ">= 0.0.0"]} ] end def setup_auth(username, password) do write_permissions = [%{"domain" => "api"}] read_permissions = [%{"domain" => "api", "resource" => "read"}] {:ok, {201, write_body, _}} = Hex.API.Key.new("setup_auth_write", write_permissions, user: username, pass: password) {:ok, {201, read_body, _}} = Hex.API.Key.new("setup_auth_read", read_permissions, user: username, pass: password) write_key = Mix.Tasks.Hex.encrypt_key(password, write_body["secret"]) read_key = read_body["secret"] Mix.Tasks.Hex.update_keys(write_key, read_key) [key: write_key] end def get_auth(username, password) do permissions = [%{"domain" => "api"}] {:ok, {201, body, _}} = Hex.API.Key.new("setup_auth", permissions, user: username, pass: password) [key: body["secret"]] end def init_reset_state() do public_key = File.read!(Path.join(__DIR__, "../fixtures/test_pub.pem")) Hex.State.put(:config_home, Path.expand("../../tmp/hex_config_home", __DIR__)) Hex.State.put(:cache_home, Path.expand("../../tmp/hex_cache_home", __DIR__)) Hex.State.put(:data_home, Path.expand("../../tmp/hex_data_home", __DIR__)) Hex.State.put(:api_url, "http://localhost:4043/api") Hex.State.put(:api_key_write, nil) Hex.State.put(:api_key_read, nil) Hex.State.put(:api_key_write_unencrypted, nil) Hex.State.update!(:repos, &put_in(&1["hexpm"].url, "http://localhost:4043/repo")) Hex.State.update!(:repos, &put_in(&1["hexpm"].public_key, public_key)) Hex.State.update!(:repos, &put_in(&1["hexpm"].auth_key, nil)) Hex.State.put(:repos_key, nil) Hex.State.put(:pbkdf2_iters, 10) Hex.State.put(:clean_pass, false) Application.put_env(:hex, :reset_state, Hex.State.get_all()) end def reset_state do Hex.State.put_all(Application.get_env(:hex, :reset_state)) end def set_home_cwd() do set_home_path(File.cwd!()) end def set_home_tmp() do set_home_path(tmp_path()) end def set_home_path(path) do Hex.State.put(:config_home, path) Hex.State.put(:cache_home, path) Hex.State.put(:data_home, path) end def wait_on_exit({:ok, pid}) do on_exit(fn -> ref = Process.monitor(pid) receive do {:DOWN, ^ref, :process, ^pid, _info} -> :ok end end) end setup_all context do unless context[:async] do ets_path = tmp_path("cache.ets") File.rm(ets_path) create_test_registry(ets_path, test_registry()) reset_state() end :ok end setup context do unless context[:async] do wait_on_exit(Hex.Registry.Server.start_link()) wait_on_exit(Hex.UpdateChecker.start_link()) reset_state() Hex.Parallel.clear(:hex_fetcher) Mix.shell(Hex.Shell.Process) Mix.Task.clear() Hex.Shell.Process.flush() clear_cache() Mix.ProjectStack.clear_stack() end :ok end def bypass_mirror() do bypass = Bypass.open() repos = Hex.State.fetch!(:repos) repos = put_in(repos["hexpm"].url, "http://localhost:#{bypass.port}") Hex.State.put(:repos, repos) Bypass.expect(bypass, fn conn -> case conn do %Plug.Conn{request_path: "/docs/docs_package-1.1.2.tar.gz"} -> tar_file = tmp_path("docs_package-1.1.2.tar.gz") index_file = String.to_charlist("index.html") epub_file = String.to_charlist("docs_package.epub") :mix_hex_erl_tar.create(tar_file, [{index_file, ""}, {epub_file, ""}], [:compressed]) package = File.read!(tar_file) Plug.Conn.resp(conn, 200, package) %Plug.Conn{request_path: "/docs/docs_package"} -> Plug.Conn.resp(conn, 404, "") %Plug.Conn{request_path: "/docs/pre_only_package-0.0.1-rc1.tar.gz"} -> tar_file = tmp_path("pre_only_package-0.0.1-rc1.tar.gz") index_file = String.to_charlist("index.html") :mix_hex_erl_tar.create(tar_file, [{index_file, ""}], [:compressed]) package = File.read!(tar_file) Plug.Conn.resp(conn, 200, package) end end) bypass end def bypass_repo(repo) do bypass = Bypass.open() map = %{ url: "http://localhost:#{bypass.port}/repo", public_key: nil, auth_key: nil, organization: "hexpm" } repos = Hex.State.fetch!(:repos) repos = Map.put(repos, repo, map) Hex.State.put(:repos, repos) Hex.State.put(:api_url, "http://localhost:#{bypass.port}/api") package_path = "/api/repos/#{repo}/packages/ecto" release_path = "/api/repos/#{repo}/publish" Bypass.expect(bypass, fn conn -> case conn do %Plug.Conn{method: "GET", request_path: ^package_path} -> body = %{"meta" => %{"description" => "ecto description"}} conn |> Plug.Conn.put_resp_header("content-type", "application/vnd.hex+erlang") |> Plug.Conn.resp(200, Hex.Utils.safe_serialize_erlang(body)) %Plug.Conn{method: "POST", request_path: ^release_path} -> body = %{"html_url" => "myrepo html_url"} conn |> Plug.Conn.put_resp_header("content-type", "application/vnd.hex+erlang") |> Plug.Conn.resp(201, Hex.Utils.safe_serialize_erlang(body)) %Plug.Conn{method: "GET", request_path: "/api/users/me"} -> body = %{"organizations" => [%{"name" => repo}]} conn |> Plug.Conn.put_resp_header("content-type", "application/vnd.hex+erlang") |> Plug.Conn.resp(200, Hex.Utils.safe_serialize_erlang(body)) %Plug.Conn{method: "POST", request_path: "/api/keys"} -> body = %{"secret" => "myrepo secret"} conn |> Plug.Conn.put_resp_header("content-type", "application/vnd.hex+erlang") |> Plug.Conn.resp(201, Hex.Utils.safe_serialize_erlang(body)) end end) bypass end def bypass_package() do bypass = Bypass.open() repos = Hex.State.fetch!(:repos) repos = put_in(repos["hexpm"].url, "http://localhost:#{bypass.port}") Hex.State.put(:repos, repos) Bypass.expect(bypass, fn conn -> case conn do %Plug.Conn{request_path: "/tarballs/package-1.0.0.tar"} -> tar_file = tmp_path("package-1.0.0.tar") index_file = String.to_charlist("index.html") :mix_hex_erl_tar.create(tar_file, [{index_file, ""}], [:compressed]) package = File.read!(tar_file) Plug.Conn.resp(conn, 200, package) %Plug.Conn{request_path: "/tarballs/package-1.0.1.tar"} -> Plug.Conn.resp(conn, 404, "") end end) bypass end end hex-2.0.6/test/support/hexpm.ex000066400000000000000000000155141437023760000164650ustar00rootroot00000000000000defmodule HexTest.Hexpm do import ExUnit.Assertions defmodule WrappedCollectable do defstruct [:collectable, :fun] defimpl Collectable do def into(%{collectable: collectable, fun: fun}) do {term, collectable_fun} = Collectable.into(collectable) {term, wrap(collectable_fun, fun)} end defp wrap(collectable_fun, fun) do fn term, {:cont, x} -> collectable_fun.(term, {:cont, fun.(x)}) term, command -> collectable_fun.(term, command) end end end end defp stream_hexpm do %WrappedCollectable{ collectable: IO.stream(:stdio, :line), fun: &IO.ANSI.format([:blue, &1]) } end @mix_exs_template """ defmodule ~s.NoConflict.MixProject do use Mix.Project def project do [app: :~s, version: "~s", deps: deps()] end defp deps do ~s end end """ def init() do check_hexpm() mix = hexpm_mix() |> List.to_string() cmd(mix, ["ecto.drop", "-r", "Hexpm.RepoBase", "--quiet"]) cmd(mix, ["ecto.create", "-r", "Hexpm.RepoBase", "--quiet"]) cmd(mix, ["ecto.load", "-r", "Hexpm.RepoBase", "--quiet"]) cmd(mix, ["ecto.migrate", "-r", "Hexpm.RepoBase", "--quiet"]) end def start() do path = String.to_charlist(path()) hexpm_mix_home = String.to_charlist(hexpm_mix_home()) hexpm_mix_archives = String.to_charlist(hexpm_mix_archives()) key = Path.join(__DIR__, "../fixtures/test_priv.pem") |> File.read!() |> String.to_charlist() env = [ {~c"MIX_ENV", ~c"hex"}, {~c"MIX_HOME", hexpm_mix_home}, {~c"MIX_ARCHIVES", hexpm_mix_archives}, {~c"PATH", path}, {~c"HEX_SIGNING_KEY", key}, {~c"HEXPM_SETUP", ~c"1"} ] spawn(fn -> port = Port.open({:spawn_executable, hexpm_mix()}, [ :exit_status, :use_stdio, :stderr_to_stdout, :binary, :hide, env: env, cd: hexpm_dir(), args: ["phx.server"] ]) fun = fn fun -> receive do {^port, {:data, data}} -> IO.ANSI.format([:blue, data]) |> IO.write() fun.(fun) {^port, {:exit_status, status}} -> IO.puts("Hexpm quit with status #{status}") System.halt(status) end end fun.(fun) end) wait_on_start() end defp check_hexpm do dir = hexpm_dir() unless File.exists?(dir) do IO.puts( "Unable to find #{dir}, make sure to clone the hexpm repository " <> "into it to run integration tests or set HEXPM_PATH to its location" ) System.halt(1) end end defp hexpm_dir do System.get_env("HEXPM_PATH") || "../hexpm" end defp hexpm_mix do if path = hexpm_elixir() do path = String.to_charlist(path) :os.find_executable(~c"mix", path) else :os.find_executable(~c"mix") end end defp hexpm_elixir do if path = System.get_env("HEXPM_ELIXIR_PATH") do path |> Path.expand() |> Path.join("bin") end end defp hexpm_otp do if path = System.get_env("HEXPM_OTP_PATH") do path |> Path.expand() |> Path.join("bin") end end defp hexpm_mix_home do (System.get_env("HEXPM_MIX_HOME") || Mix.Utils.mix_home()) |> Path.expand() end defp hexpm_mix_archives do (System.get_env("HEXPM_MIX_ARCHIVES") || archives_path()) |> Path.expand() end cond do function_exported?(Mix, :path_for, 1) -> defp archives_path(), do: Mix.path_for(:archives) function_exported?(Mix.Local, :path_for, 1) -> defp archives_path(), do: Mix.Local.path_for(:archive) true -> defp archives_path(), do: Mix.Local.archives_path() end defp cmd(command, args) do env = [ {"MIX_ENV", "hex"}, {"PATH", path()}, {"MIX_HOME", hexpm_mix_home()}, {"MIX_ARCHIVES", hexpm_mix_archives()} ] opts = [stderr_to_stdout: true, into: stream_hexpm(), env: env, cd: hexpm_dir()] 0 = System.cmd(command, args, opts) |> elem(1) end defp path do [hexpm_elixir(), hexpm_otp(), System.get_env("PATH")] |> Enum.join(":") end defp wait_on_start do case :httpc.request(:get, {~c"http://localhost:4043", []}, [], []) do {:ok, _} -> :ok {:error, _} -> :timer.sleep(10) wait_on_start() end end def new_repo(repository, auth) do Hex.API.erlang_post_request(nil, "repo", %{"name" => repository}, auth) end def new_user(username, email, password, key) do permissions = [%{"domain" => "api"}] {:ok, {201, _, _}} = Hex.API.User.new(username, email, password) {:ok, {201, %{"secret" => secret}, _}} = Hex.API.Key.new(key, permissions, user: username, pass: password) [key: secret, "$write_key": Mix.Tasks.Hex.encrypt_key(password, secret), "$read_key": secret] end def new_key(auth) do permissions = [%{"domain" => "api"}] {:ok, {201, %{"secret" => secret}, _}} = Hex.API.Key.new("key", permissions, auth) [key: secret] end def new_key(username, password, key) do permissions = [%{"domain" => "api"}] {:ok, {201, %{"secret" => secret}, _}} = Hex.API.Key.new(key, permissions, user: username, pass: password) [key: secret, "$write_key": Mix.Tasks.Hex.encrypt_key(password, secret), "$read_key": secret] end def new_organization_key(organization, key, auth) do permissions = [%{"domain" => "api"}] {:ok, {201, %{"secret" => secret}, _}} = Hex.API.Key.Organization.new(organization, key, permissions, auth) [key: secret] end def new_package(organization, name, version, deps, meta, auth, files \\ nil) do reqs = Enum.filter(deps, fn {_app, _req, opts} -> !(opts[:path] || opts[:git] || opts[:github]) _ -> true end) reqs = Map.new(reqs, fn {app, req} -> {app, %{app: app, requirement: req, optional: false}} {app, req, opts} -> opts = Map.new(opts) default_opts = %{app: app, requirement: req, optional: false} {opts[:hex] || app, Map.merge(default_opts, opts)} end) meta = meta |> Map.merge(%{name: name, version: version, requirements: reqs}) |> Map.put_new(:description, "empty") |> Map.put_new(:licenses, ["MIT"]) |> Map.put_new(:app, name) |> Map.put_new(:build_tools, ["mix"]) |> Map.put_new(:files, ["mix.exs"]) deps = inspect(deps, pretty: true) module = String.capitalize(name) mix_exs = :io_lib.format(@mix_exs_template, [module, name, version, deps]) files = files || [{"mix.exs", List.to_string(mix_exs)}] %{tarball: tarball} = Hex.Tar.create!(meta, files, :memory) {:ok, {result, %{"version" => ^version}, _}} = Hex.API.Release.publish(organization, tarball, auth) assert result in [200, 201] end end hex-2.0.6/test/support/integration_case.ex000066400000000000000000000004141437023760000206530ustar00rootroot00000000000000defmodule HexTest.IntegrationCase do use ExUnit.CaseTemplate using do quote do use HexTest.Case @moduletag :integration setup_all do Code.require_file("../setup_hexpm.exs", unquote(__DIR__)) :ok end end end end hex-2.0.6/test/support/release_samples.ex000066400000000000000000000173121437023760000205060ustar00rootroot00000000000000defmodule Sample.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "sample", version: "0.0.1", deps: [], package: [ licenses: ["MIT"], files: ["myfile.txt", "mix.exs"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseSimple.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "baz", version: "0.0.1", package: [ licenses: ["MIT"], files: ["myfile.txt"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseNewSimple.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "baz", version: "0.0.1", package: [ licenses: ["MIT"], files: ["myfile.txt"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseDeps.MixProject do def project do [ app: Process.get(:hex_test_app_name, :release_deps), description: "bar", version: "0.0.2", deps: [ {:ex_doc, "0.0.1"} ], package: [ licenses: ["MIT"] ] ] end end defmodule ReleaseCustomRepoDeps.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "bar", version: "0.0.2", deps: [ {:ex_doc, "0.0.1"}, {:ecto, "0.0.1", repo: :my_repo} ], package: [ licenses: ["MIT"] ] ] end end defmodule ReleaseMeta.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), version: "0.0.3", description: "foo", package: [ files: ["myfile.txt", "missing.txt", "missing/*"], licenses: ["Apache"], links: %{"a" => "http://a"}, extra: %{"c" => "d"} ] ] end end defmodule ReleaseMetaNoFiles.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), version: "0.0.3", description: "foo", package: [ files: [], licenses: ["Apache"], links: %{"a" => "http://a"}, extra: %{"c" => "d"} ] ] end end defmodule ReleaseName.MixProject do def project do [ app: :release_d, description: "Whatever", version: "0.0.1", package: [ name: Process.get(:hex_test_package_name) || raise("missing package name"), licenses: ["MIT"], files: ["myfile.txt"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseNoDescription.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), version: "0.0.1" ] end end defmodule ReleaseTooLongDescription.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: String.duplicate("w", 301), version: "0.0.1" ] end end defmodule ReleasePreDeps.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "bar", version: "0.0.1", deps: [ {:ex_doc, "~> 0.0.1-pre"} ], package: [ files: ["myfile.txt"], licenses: ["MIT"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseFiles.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), version: "0.0.1", description: "foo", package: [ files: ["myfile.txt", "executable.sh", "dir", "empty_dir", "link_dir"], licenses: ["MIT"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseExcludePatterns.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), version: "0.0.1", description: "foo", package: [ files: ["myfile.txt"], exclude_patterns: ["exclude.*"], licenses: ["MIT"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseRepo.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "baz", version: "0.0.1", package: [ organization: "myorg", licenses: ["MIT"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseRepoInvalidLicenses.MixProject do def project do [ app: :release_repo_invalid_licenses, description: "Invalid license", version: "0.0.1", package: [ organization: "myorg", licenses: ["CustomLicense"], files: ["myfile.txt"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseMisspelledOrganization.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "baz", version: "0.0.1", package: [ organisation: "myorg", licenses: ["MIT"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseOrganizationWrongLocation.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "baz", version: "0.0.1", organization: "myorg", package: [ licenses: ["MIT"], files: ["myfile.txt"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseIncludeReservedFile.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "baz", version: "0.0.1", package: [ licenses: ["MIT"], links: %{"a" => "http://a"}, files: ["hex_meta*"] ] ] end end defmodule ReleaseGitDeps.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "Package with git dependencies", version: "0.0.2", deps: [ {:ex_doc, "0.0.1"}, {:ecto, github: "elixir-ecto/ecto", tag: "v0.2.5"}, {:gettext, git: "https://github.com/elixir-lang/gettext.git", branch: "master"} ], package: [ licenses: ["MIT"], links: %{"example" => "http://example.com"} ] ] end end defmodule ReleaseCustomApiUrl.MixProject do def project do [ app: Process.get(:hex_test_app_name) || raise("missing app name"), description: "Package with custom api_url", version: "0.0.1", deps: [], package: [ licenses: ["MIT"], links: %{"a" => "http://a"} ], hex: [ api_url: "https://custom" ] ] end end defmodule ReleaseMissingLicenses.MixProject do def project do [ app: :release_missing_licenses, description: "Package with missing licenses", version: "0.0.1", package: [ licenses: [], files: ["myfile.txt"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseInvalidLicenses.MixProject do def project do [ app: :release_invalid_licenses, description: "Package with invalid licenses", version: "0.0.1", package: [ licenses: ["CustomLicense"], files: ["myfile.txt"], links: %{"a" => "http://a"} ] ] end end defmodule ReleaseAppFalseDep.MixProject do def project do [ app: :release_app_false_dep, description: "Package with invalid licenses", version: "0.0.1", deps: [ {:ex_doc, "0.0.1", app: false} ], package: [ licenses: [], files: ["myfile.txt"], links: %{"a" => "http://a"} ] ] end end hex-2.0.6/test/support/solver_helper.ex000066400000000000000000000052211437023760000202070ustar00rootroot00000000000000defmodule HexTest.SolverHelper do alias Hex.Registry.Server, as: Registry def solve(deps, locked \\ []) do dependencies = dependencies(deps) locked = locked(locked) overridden = overridden(deps) (dependencies ++ locked) |> Enum.map(fn %{repo: repo, name: name} -> {repo, name} end) |> Registry.prefetch() case Hex.Solver.run(Registry, dependencies, locked, overridden) do {:ok, result} -> Map.new(result, fn {package, {version, nil}} -> {String.to_atom(package), to_string(version)} {package, {version, repo}} -> {{repo, String.to_atom(package)}, to_string(version)} end) {:error, message} -> message end end defp dependencies(dependencies) do Enum.map(dependencies, fn {package, requirement} -> %{ repo: nil, name: to_string(package), constraint: Hex.Solver.parse_constraint!(requirement || ">= 0.0.0"), optional: false, label: package } {package, requirement, opts} -> repo = Keyword.get(opts, :repo) optional = Keyword.get(opts, :optional, false) app = Keyword.get(opts, :app, false) %{ repo: repo, name: to_string(package), constraint: Hex.Solver.parse_constraint!(requirement || ">= 0.0.0"), optional: optional, label: app } end) end defp locked(dependencies) do Enum.map(dependencies, fn {package, requirement} -> %{ repo: nil, name: to_string(package), version: Hex.Solver.parse_constraint!(requirement || ">= 0.0.0"), label: package } {package, requirement, opts} -> repo = Keyword.get(opts, :repo) app = Keyword.get(opts, :app, false) %{ repo: repo, name: to_string(package), version: Hex.Solver.parse_constraint!(requirement || ">= 0.0.0"), label: app } end) end defp overridden(dependencies) do Enum.flat_map(dependencies, fn {_package, _requirement} -> [] {package, _requirement, opts} -> if opts[:override] do [package] else [] end end) end def setup_registry(path, registry) do registry = expand_versions(registry) HexTest.Case.create_test_registry(path, registry) Registry.close() Registry.open(registry_path: path) end def expand_versions(registry) do Enum.flat_map(registry, fn {repo, package, versions, deps} -> Enum.map(versions, fn version -> {repo, package, version, deps} end) end) end end hex-2.0.6/test/test_helper.exs000066400000000000000000000003521437023760000163230ustar00rootroot00000000000000ExUnit.configure(exclude: [:skip | ExUnit.configuration()[:exclude]]) ExUnit.start() Application.ensure_all_started(:bypass) File.rm_rf!(HexTest.Case.tmp_path()) File.mkdir_p!(HexTest.Case.tmp_path()) HexTest.Case.init_reset_state()